[opensuse-kernel] [RFC] arm64 backports for 3.16
Hi kernel gurus, There were quite a good number of bug fixes and necessary features in post-3.16 as well as some patches that are missing upstream to make arm64 a shiny out of the box experience. I would like to shove the patches below into our openSUSE-13.2 branch. I have a properly trimmed down (and adjusted) version of the changes below based on 3.18 and an untested variant on top of 3.17. What is the strategy with 13.2 going to be? Are we going to uprev the kernel for it? Is it going to jump to 3.17, so should I push the changes here into the 13.2 branch the stable branch and the master branch? Or would master and 13.2 suffice? Also, if you think the changes below are too intrusive, please let me know. I've tried to double-check that they basically only touch arm64 specific code paths with a few shared ppc blocks. But the likelyhood for x86 breakage is low: .../devicetree/bindings/pci/xgene-pci.txt | 57 + MAINTAINERS | 8 + arch/arm/include/asm/io.h | 1 + arch/arm/include/asm/kvm_mmu.h | 25 + arch/arm/include/uapi/asm/kvm.h | 1 + arch/arm/kvm/arm.c | 23 +- arch/arm/kvm/mmu.c | 157 +- arch/arm/mach-integrator/pci_v3.c | 23 +- arch/arm64/Kconfig | 24 +- arch/arm64/boot/dts/apm-mustang.dts | 22 + arch/arm64/boot/dts/apm-storm.dtsi | 257 +- arch/arm64/crypto/Makefile | 2 +- arch/arm64/include/asm/Kbuild | 1 + arch/arm64/include/asm/io.h | 3 +- arch/arm64/include/asm/kvm_arm.h | 17 +- arch/arm64/include/asm/kvm_mmu.h | 90 + arch/arm64/include/asm/pci.h | 37 + arch/arm64/include/asm/pgtable.h | 2 + arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/efi-stub.c | 16 +- arch/arm64/kernel/entry-fpsimd.S | 2 +- arch/arm64/kernel/entry.S | 19 +- arch/arm64/kernel/fpsimd.c | 1 + arch/arm64/kernel/head.S | 6 +- arch/arm64/kernel/pci.c | 78 + arch/arm64/kvm/hyp-init.S | 20 +- arch/ia64/kernel/time.c | 15 - drivers/ata/ahci_xgene.c | 24 +- drivers/ata/libahci_platform.c | 12 + drivers/cpufreq/arm_big_little.c | 1 + drivers/irqchip/irq-gic.c | 24 +- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/amd/Makefile | 2 +- drivers/net/ethernet/amd/xgbe-a0/Makefile | 8 + drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h | 1104 ++++++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c | 270 ++ drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c | 374 +++ drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c | 566 +++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c | 2643 ++++++++++++++++++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c | 1864 ++++++++++++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c | 544 ++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c | 566 +++++ drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c | 330 +++ drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c | 285 +++ drivers/net/ethernet/amd/xgbe-a0/xgbe.h | 769 ++++++ drivers/net/ethernet/apm/Kconfig | 1 + drivers/net/ethernet/apm/Makefile | 5 + drivers/net/ethernet/apm/xgene/Kconfig | 10 + drivers/net/ethernet/apm/xgene/Makefile | 7 + .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 150 ++ drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 743 ++++++ drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 325 +++ drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 1006 ++++++++ drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 163 ++ drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 389 +++ drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 41 + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 332 +++ drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 53 + drivers/net/fddi/skfp/h/skfbi.h | 5 - drivers/net/phy/Makefile | 1 + drivers/net/phy/amd-xgbe-a0-phy.c | 1445 +++++++++++ drivers/of/address.c | 154 ++ drivers/of/of_pci.c | 142 ++ drivers/pci/host/Kconfig | 10 + drivers/pci/host/Makefile | 1 + drivers/pci/host/pci-tegra.c | 10 +- drivers/pci/host/pci-xgene.c | 659 +++++ drivers/pci/host/pcie-rcar.c | 21 +- drivers/pci/pci.c | 40 + drivers/pci/probe.c | 11 +- drivers/power/reset/Kconfig | 12 +- drivers/power/reset/Makefile | 2 +- drivers/power/reset/syscon-reboot.c | 88 + drivers/power/reset/xgene-reboot.c | 103 - drivers/rtc/Kconfig | 2 +- drivers/rtc/Makefile | 4 + drivers/rtc/rtc-efi-platform.c | 31 + drivers/usb/host/Kconfig | 7 + drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-h20ahb.c | 341 +++ include/asm-generic/io.h | 2 +- include/asm-generic/pgtable.h | 4 + include/linux/irqchip/arm-gic.h | 3 + include/linux/of_address.h | 27 +- include/linux/of_pci.h | 13 + include/linux/pci.h | 27 + virt/kvm/arm/vgic.c | 18 + 89 files changed, 16404 insertions(+), 302 deletions(-) Best case would be if we could shove this into the 13.2 release kernel still, as with the state that we have not a single arm64 board would work to an extent where it's actually usable. If that's impossible, I guess we'd have to improvise with overloaded kernel packages on arm64. Alex diff --git a/config/arm64/default b/config/arm64/default index b3c4756..a570111 100644 --- a/config/arm64/default +++ b/config/arm64/default @@ -6,7 +6,6 @@ CONFIG_ARM64=y CONFIG_64BIT=y CONFIG_ARCH_PHYS_ADDR_T_64BIT=y CONFIG_MMU=y -CONFIG_NO_IOPORT_MAP=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_LOCKDEP_SUPPORT=y CONFIG_TRACE_IRQFLAGS_SUPPORT=y @@ -146,10 +145,8 @@ CONFIG_RD_LZ4=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y -CONFIG_HAVE_UID16=y CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_EXPERT=y -CONFIG_UID16=y CONFIG_SGETMASK_SYSCALL=y CONFIG_SYSFS_SYSCALL=y # CONFIG_SYSCTL_SYSCALL is not set @@ -166,6 +163,7 @@ CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y # CONFIG_EMBEDDED is not set CONFIG_HAVE_PERF_EVENTS=y CONFIG_PERF_USE_VMALLOC=y @@ -203,8 +201,6 @@ CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y CONFIG_MODULES_USE_ELF_RELA=y CONFIG_CLONE_BACKWARDS=y -CONFIG_OLD_SIGSUSPEND3=y -CONFIG_COMPAT_OLD_SIGACTION=y # # GCOV-based kernel profiling @@ -253,7 +249,6 @@ CONFIG_KARMA_PARTITION=y CONFIG_EFI_PARTITION=y CONFIG_SYSV68_PARTITION=y # CONFIG_CMDLINE_PARTITION is not set -CONFIG_BLOCK_COMPAT=y # # IO Schedulers @@ -289,11 +284,41 @@ CONFIG_ARCH_XGENE=y # Bus support # CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_SYSCALL=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +CONFIG_PCI_STUB=y +CONFIG_PCI_ATS=y +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y + +# +# PCI host controller drivers +# +CONFIG_PCI_XGENE=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEAER_INJECT is not set +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set # # Kernel Features # -# CONFIG_ARM64_64K_PAGES is not set +CONFIG_ARM64_64K_PAGES=y # CONFIG_CPU_BIG_ENDIAN is not set CONFIG_SMP=y CONFIG_SCHED_MC=y @@ -312,7 +337,6 @@ CONFIG_HAVE_ARCH_PFN_VALID=y CONFIG_HW_PERF_EVENTS=y CONFIG_SYS_SUPPORTS_HUGETLBFS=y CONFIG_ARCH_WANT_GENERAL_HUGETLB=y -CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y CONFIG_SELECT_MEMORY_MODEL=y CONFIG_SPARSEMEM_MANUAL=y @@ -349,7 +373,7 @@ CONFIG_ZSMALLOC=y # CONFIG_PGTABLE_MAPPING is not set CONFIG_GENERIC_EARLY_IOREMAP=y # CONFIG_PARAVIRT_XEN is not set -CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORCE_MAX_ZONEORDER=14 # # Boot options @@ -362,14 +386,11 @@ CONFIG_EFI=y # Userspace binary formats # CONFIG_BINFMT_ELF=y -CONFIG_COMPAT_BINFMT_ELF=y CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y CONFIG_BINFMT_SCRIPT=y # CONFIG_HAVE_AOUT is not set CONFIG_BINFMT_MISC=m CONFIG_COREDUMP=y -CONFIG_COMPAT=y -CONFIG_SYSVIPC_COMPAT=y # # Power management options @@ -424,7 +445,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m # # CONFIG_ARM_KIRKWOOD_CPUFREQ is not set CONFIG_NET=y -CONFIG_COMPAT_NETLINK_MESSAGES=y # # Networking options @@ -845,6 +865,7 @@ CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5=y CONFIG_SCTP_COOKIE_HMAC_MD5=y # CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set CONFIG_RDS=m +CONFIG_RDS_RDMA=m CONFIG_RDS_TCP=m # CONFIG_RDS_DEBUG is not set # CONFIG_TIPC is not set @@ -1026,8 +1047,14 @@ CONFIG_CAN_LEDS=y CONFIG_CAN_SJA1000=m CONFIG_CAN_SJA1000_ISA=m CONFIG_CAN_SJA1000_PLATFORM=m +CONFIG_CAN_EMS_PCI=m +CONFIG_CAN_PEAK_PCI=m +CONFIG_CAN_PEAK_PCIEC=y +CONFIG_CAN_KVASER_PCI=m +CONFIG_CAN_PLX_PCI=m CONFIG_CAN_C_CAN=m CONFIG_CAN_C_CAN_PLATFORM=m +CONFIG_CAN_C_CAN_PCI=m CONFIG_CAN_CC770=m CONFIG_CAN_CC770_ISA=m CONFIG_CAN_CC770_PLATFORM=m @@ -1097,6 +1124,7 @@ CONFIG_KS959_DONGLE=m # CONFIG_USB_IRDA=m CONFIG_SIGMATEL_FIR=m +CONFIG_VLSI_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m CONFIG_BT_6LOWPAN=y @@ -1172,6 +1200,7 @@ CONFIG_RFKILL_INPUT=y CONFIG_RFKILL_GPIO=m CONFIG_NET_9P=m CONFIG_NET_9P_VIRTIO=m +CONFIG_NET_9P_RDMA=m # CONFIG_NET_9P_DEBUG is not set CONFIG_CAIF=m # CONFIG_CAIF_DEBUG is not set @@ -1300,13 +1329,18 @@ CONFIG_MTD_PHYSMAP_START=0x8000000 CONFIG_MTD_PHYSMAP_LEN=0x0 CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_PHYSMAP_OF is not set +CONFIG_MTD_PCI=m CONFIG_MTD_GPIO_ADDR=m +# CONFIG_MTD_INTEL_VR_NOR is not set CONFIG_MTD_PLATRAM=m CONFIG_MTD_LATCH_ADDR=m # # Self-contained MTD device drivers # +CONFIG_MTD_PMC551=m +# CONFIG_MTD_PMC551_BUGFIX is not set +# CONFIG_MTD_PMC551_DEBUG is not set # CONFIG_MTD_DATAFLASH is not set # CONFIG_MTD_M25P80 is not set # CONFIG_MTD_SST25L is not set @@ -1326,16 +1360,18 @@ CONFIG_MTD_NAND_ECC_SMC=y CONFIG_MTD_NAND=m CONFIG_MTD_NAND_BCH=m CONFIG_MTD_NAND_ECC_BCH=y -# CONFIG_MTD_SM_COMMON is not set +CONFIG_MTD_SM_COMMON=m # CONFIG_MTD_NAND_DENALI is not set CONFIG_MTD_NAND_GPIO=m CONFIG_MTD_NAND_IDS=m +CONFIG_MTD_NAND_RICOH=m CONFIG_MTD_NAND_DISKONCHIP=m CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADVANCED=y CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS=0x0 CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH=y CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE=y CONFIG_MTD_NAND_DOCG4=m +# CONFIG_MTD_NAND_CAFE is not set # CONFIG_MTD_NAND_NANDSIM is not set CONFIG_MTD_NAND_PLATFORM=m CONFIG_MTD_ONENAND=m @@ -1365,9 +1401,12 @@ CONFIG_OF=y CONFIG_OF_FLATTREE=y CONFIG_OF_EARLY_FLATTREE=y CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y CONFIG_OF_IRQ=y CONFIG_OF_NET=y CONFIG_OF_MDIO=m +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y CONFIG_OF_MTD=y CONFIG_OF_RESERVED_MEM=y CONFIG_PARPORT=m @@ -1377,9 +1416,14 @@ CONFIG_PARPORT_1284=y CONFIG_PARPORT_NOT_PC=y CONFIG_BLK_DEV=y CONFIG_BLK_DEV_NULL_BLK=m +CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m CONFIG_ZRAM=m # CONFIG_ZRAM_LZ4_COMPRESS is not set # CONFIG_ZRAM_DEBUG is not set +CONFIG_BLK_CPQ_CISS_DA=m +CONFIG_CISS_SCSI_TAPE=y +CONFIG_BLK_DEV_DAC960=m +CONFIG_BLK_DEV_UMEM=m # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 @@ -1387,7 +1431,10 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_DRBD=m # CONFIG_DRBD_FAULT_INJECTION is not set CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_NVME=m +CONFIG_BLK_DEV_SKD=m CONFIG_BLK_DEV_OSD=m +CONFIG_BLK_DEV_SX8=m CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -1398,6 +1445,7 @@ CONFIG_CDROM_PKTCDVD_WCACHE=y CONFIG_ATA_OVER_ETH=m CONFIG_VIRTIO_BLK=m CONFIG_BLK_DEV_RBD=m +CONFIG_BLK_DEV_RSXX=m # # Misc devices @@ -1405,8 +1453,13 @@ CONFIG_BLK_DEV_RBD=m CONFIG_SENSORS_LIS3LV02D=m # CONFIG_AD525X_DPOT is not set CONFIG_DUMMY_IRQ=m +CONFIG_PHANTOM=m +CONFIG_SGI_IOC4=m +CONFIG_TIFM_CORE=m +CONFIG_TIFM_7XX1=m # CONFIG_ICS932S401 is not set CONFIG_ENCLOSURE_SERVICES=m +CONFIG_HP_ILO=m # CONFIG_APDS9802ALS is not set # CONFIG_ISL29003 is not set # CONFIG_ISL29020 is not set @@ -1434,6 +1487,9 @@ CONFIG_C2PORT=m # CONFIG_EEPROM_MAX6875 is not set CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_93XX46 is not set +CONFIG_CB710_CORE=m +# CONFIG_CB710_DEBUG is not set +CONFIG_CB710_DEBUG_ASSUMPTIONS=y # # Texas Instruments shared transport line discipline @@ -1445,7 +1501,7 @@ CONFIG_SENSORS_LIS3_SPI=m # # Altera FPGA firmware download module # -# CONFIG_ALTERA_STAPL is not set +CONFIG_ALTERA_STAPL=m # # Intel MIC Host Driver @@ -1454,6 +1510,7 @@ CONFIG_SENSORS_LIS3_SPI=m # # Intel MIC Card Driver # +CONFIG_GENWQE=m CONFIG_ECHO=m # @@ -1499,12 +1556,84 @@ CONFIG_SCSI_SRP_TGT_ATTRS=y CONFIG_SCSI_LOWLEVEL=y CONFIG_ISCSI_TCP=m CONFIG_ISCSI_BOOT_SYSFS=m +CONFIG_SCSI_CXGB3_ISCSI=m +CONFIG_SCSI_CXGB4_ISCSI=m +CONFIG_SCSI_BNX2_ISCSI=m +CONFIG_SCSI_BNX2X_FCOE=m +CONFIG_BE2ISCSI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_3W_9XXX=m +CONFIG_SCSI_3W_SAS=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_AIC7XXX=m +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=5000 +CONFIG_AIC7XXX_DEBUG_ENABLE=y +CONFIG_AIC7XXX_DEBUG_MASK=0 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=5000 +CONFIG_AIC79XX_DEBUG_ENABLE=y +CONFIG_AIC79XX_DEBUG_MASK=0 +CONFIG_AIC79XX_REG_PRETTY_PRINT=y +CONFIG_SCSI_AIC94XX=m +CONFIG_AIC94XX_DEBUG=y +CONFIG_SCSI_MVSAS=m +CONFIG_SCSI_MVSAS_DEBUG=y +# CONFIG_SCSI_MVSAS_TASKLET is not set +CONFIG_SCSI_MVUMI=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_ESAS2R=m +CONFIG_MEGARAID_NEWGEN=y +CONFIG_MEGARAID_MM=m +CONFIG_MEGARAID_MAILBOX=m +CONFIG_MEGARAID_LEGACY=m +CONFIG_MEGARAID_SAS=m +CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_MPT2SAS_MAX_SGE=128 +# CONFIG_SCSI_MPT2SAS_LOGGING is not set +CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_MPT3SAS_MAX_SGE=128 +# CONFIG_SCSI_MPT3SAS_LOGGING is not set CONFIG_SCSI_UFSHCD=m +CONFIG_SCSI_UFSHCD_PCI=m CONFIG_SCSI_UFSHCD_PLATFORM=m +CONFIG_SCSI_HPTIOP=m CONFIG_LIBFC=m CONFIG_LIBFCOE=m +CONFIG_FCOE=m +CONFIG_SCSI_DMX3191D=m +CONFIG_SCSI_FUTURE_DOMAIN=m +CONFIG_SCSI_IPS=m +CONFIG_SCSI_INITIO=m +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_STEX=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +CONFIG_SCSI_SYM53C8XX_MMIO=y +CONFIG_SCSI_IPR=m +CONFIG_SCSI_IPR_TRACE=y +CONFIG_SCSI_IPR_DUMP=y +CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA_FC=m +CONFIG_TCM_QLA2XXX=m +CONFIG_SCSI_QLA_ISCSI=m +CONFIG_SCSI_LPFC=m +CONFIG_SCSI_LPFC_DEBUG_FS=y +CONFIG_SCSI_DC395x=m +CONFIG_SCSI_DC390T=m CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_PMCRAID=m +CONFIG_SCSI_PM8001=m +CONFIG_SCSI_SRP=m +CONFIG_SCSI_BFA_FC=m CONFIG_SCSI_VIRTIO=m +CONFIG_SCSI_CHELSIO_FCOE=m # CONFIG_SCSI_LOWLEVEL_PCMCIA is not set CONFIG_SCSI_DH=m CONFIG_SCSI_DH_RDAC=m @@ -1524,32 +1653,90 @@ CONFIG_SATA_PMP=y # # Controllers with non-SFF native interface # +CONFIG_SATA_AHCI=m CONFIG_SATA_AHCI_PLATFORM=m CONFIG_AHCI_XGENE=m +CONFIG_SATA_INIC162X=m +CONFIG_SATA_ACARD_AHCI=m +CONFIG_SATA_SIL24=m CONFIG_ATA_SFF=y # # SFF controllers with custom DMA interface # +CONFIG_PDC_ADMA=m +CONFIG_SATA_QSTOR=m +CONFIG_SATA_SX4=m CONFIG_ATA_BMDMA=y # # SATA SFF controllers with BMDMA # +CONFIG_ATA_PIIX=m +CONFIG_SATA_MV=m +CONFIG_SATA_NV=m +CONFIG_SATA_PROMISE=m +CONFIG_SATA_SIL=m +CONFIG_SATA_SIS=m +CONFIG_SATA_SVW=m +CONFIG_SATA_ULI=m +CONFIG_SATA_VIA=m +CONFIG_SATA_VITESSE=m # # PATA SFF controllers with BMDMA # +CONFIG_PATA_ALI=m +CONFIG_PATA_AMD=m +CONFIG_PATA_ARTOP=m +CONFIG_PATA_ATIIXP=m +CONFIG_PATA_ATP867X=m +CONFIG_PATA_CMD64X=m +CONFIG_PATA_CYPRESS=m +CONFIG_PATA_EFAR=m +CONFIG_PATA_HPT366=m +CONFIG_PATA_HPT37X=m +CONFIG_PATA_HPT3X2N=m +CONFIG_PATA_HPT3X3=m +# CONFIG_PATA_HPT3X3_DMA is not set +CONFIG_PATA_IT8213=m +CONFIG_PATA_IT821X=m +CONFIG_PATA_JMICRON=m +CONFIG_PATA_MARVELL=m +CONFIG_PATA_NETCELL=m +CONFIG_PATA_NINJA32=m +CONFIG_PATA_NS87415=m +CONFIG_PATA_OLDPIIX=m +CONFIG_PATA_OPTIDMA=m +CONFIG_PATA_PDC2027X=m +CONFIG_PATA_PDC_OLD=m +CONFIG_PATA_RADISYS=m +CONFIG_PATA_RDC=m +CONFIG_PATA_SCH=m +CONFIG_PATA_SERVERWORKS=m +CONFIG_PATA_SIL680=m +CONFIG_PATA_SIS=m +CONFIG_PATA_TOSHIBA=m +CONFIG_PATA_TRIFLEX=m +CONFIG_PATA_VIA=m +CONFIG_PATA_WINBOND=m # # PIO-only SFF controllers # +CONFIG_PATA_CMD640_PCI=m +CONFIG_PATA_MPIIX=m +CONFIG_PATA_NS87410=m +CONFIG_PATA_OPTI=m CONFIG_PATA_PLATFORM=m # CONFIG_PATA_OF_PLATFORM is not set +CONFIG_PATA_RZ1000=m # # Generic fallback / legacy drivers # +CONFIG_ATA_GENERIC=m +CONFIG_PATA_LEGACY=m CONFIG_MD=y CONFIG_BLK_DEV_MD=m CONFIG_MD_LINEAR=m @@ -1595,12 +1782,39 @@ CONFIG_TCM_PSCSI=m CONFIG_LOOPBACK_TARGET=m CONFIG_TCM_FC=m CONFIG_ISCSI_TARGET=m +CONFIG_SBP_TARGET=m +CONFIG_FUSION=y +CONFIG_FUSION_SPI=m +CONFIG_FUSION_FC=m +CONFIG_FUSION_SAS=m +CONFIG_FUSION_MAX_SGE=128 +CONFIG_FUSION_CTL=m +CONFIG_FUSION_LAN=m +# CONFIG_FUSION_LOGGING is not set + +# +# IEEE 1394 (FireWire) support +# +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_FIREWIRE_NOSY=m +CONFIG_I2O=m +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y +CONFIG_I2O_EXT_ADAPTEC=y +CONFIG_I2O_EXT_ADAPTEC_DMA64=y +CONFIG_I2O_BUS=m +CONFIG_I2O_BLOCK=m +CONFIG_I2O_SCSI=m +CONFIG_I2O_PROC=m CONFIG_NETDEVICES=y CONFIG_MII=m CONFIG_NET_CORE=y CONFIG_BONDING=m CONFIG_DUMMY=m CONFIG_EQUALIZER=m +CONFIG_NET_FC=y CONFIG_IFB=m CONFIG_NET_TEAM=m CONFIG_NET_TEAM_MODE_BROADCAST=m @@ -1619,9 +1833,39 @@ CONFIG_TUN=m CONFIG_VETH=m CONFIG_VIRTIO_NET=m CONFIG_NLMON=m +CONFIG_SUNGEM_PHY=m +# CONFIG_ARCNET is not set CONFIG_ATM_DRIVERS=y CONFIG_ATM_DUMMY=m CONFIG_ATM_TCP=m +CONFIG_ATM_LANAI=m +CONFIG_ATM_ENI=m +# CONFIG_ATM_ENI_DEBUG is not set +CONFIG_ATM_ENI_TUNE_BURST=y +CONFIG_ATM_ENI_BURST_TX_16W=y +CONFIG_ATM_ENI_BURST_TX_8W=y +CONFIG_ATM_ENI_BURST_TX_4W=y +CONFIG_ATM_ENI_BURST_TX_2W=y +CONFIG_ATM_ENI_BURST_RX_16W=y +CONFIG_ATM_ENI_BURST_RX_8W=y +CONFIG_ATM_ENI_BURST_RX_4W=y +CONFIG_ATM_ENI_BURST_RX_2W=y +CONFIG_ATM_NICSTAR=m +CONFIG_ATM_NICSTAR_USE_SUNI=y +CONFIG_ATM_NICSTAR_USE_IDT77105=y +CONFIG_ATM_IDT77252=m +# CONFIG_ATM_IDT77252_DEBUG is not set +# CONFIG_ATM_IDT77252_RCV_ALL is not set +CONFIG_ATM_IDT77252_USE_SUNI=y +CONFIG_ATM_IA=m +# CONFIG_ATM_IA_DEBUG is not set +CONFIG_ATM_FORE200E=m +CONFIG_ATM_FORE200E_USE_TASKLET=y +CONFIG_ATM_FORE200E_TX_RETRY=16 +CONFIG_ATM_FORE200E_DEBUG=0 +CONFIG_ATM_HE=m +CONFIG_ATM_HE_USE_SUNI=y +CONFIG_ATM_SOLOS=m # # CAIF transport drivers @@ -1645,45 +1889,198 @@ CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y CONFIG_NET_DSA_MV88E6131=m CONFIG_NET_DSA_MV88E6123_61_65=m CONFIG_ETHERNET=y +CONFIG_MDIO=m +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +CONFIG_TYPHOON=m +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_ADAPTEC_STARFIRE=m +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_ACENIC=m +# CONFIG_ACENIC_OMIT_TIGON_I is not set # CONFIG_ALTERA_TSE is not set CONFIG_NET_VENDOR_AMD=y +CONFIG_AMD8111_ETH=m +CONFIG_PCNET32=m CONFIG_AMD_XGBE=m +CONFIG_NET_XGENE=m CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_ATL2=m +CONFIG_ATL1=m +CONFIG_ATL1E=m +CONFIG_ATL1C=m +CONFIG_ALX=m CONFIG_NET_VENDOR_BROADCOM=y CONFIG_B44=m +CONFIG_B44_PCI_AUTOSELECT=y +CONFIG_B44_PCICORE_AUTOSELECT=y +CONFIG_B44_PCI=y CONFIG_BCMGENET=m +CONFIG_BNX2=m +CONFIG_CNIC=m +CONFIG_TIGON3=m +CONFIG_BNX2X=m +CONFIG_BNX2X_SRIOV=y CONFIG_SYSTEMPORT=m +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_BNA=m # CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_CHELSIO_T1=m +CONFIG_CHELSIO_T1_1G=y +CONFIG_CHELSIO_T3=m +CONFIG_CHELSIO_T4=m +CONFIG_CHELSIO_T4VF=m +CONFIG_NET_VENDOR_CISCO=y +CONFIG_ENIC=m CONFIG_DNET=m +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_TULIP=y +CONFIG_DE2104X=m +CONFIG_DE2104X_DSL=0 +CONFIG_TULIP=m +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +CONFIG_TULIP_NAPI=y +CONFIG_TULIP_NAPI_HW_MITIGATION=y +CONFIG_WINBOND_840=m +CONFIG_DM9102=m +CONFIG_ULI526X=m +CONFIG_NET_VENDOR_DLINK=y +CONFIG_DL2K=m +CONFIG_SUNDANCE=m +# CONFIG_SUNDANCE_MMIO is not set +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_BE2NET=m +CONFIG_BE2NET_VXLAN=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_S2IO=m +CONFIG_VXGE=m +# CONFIG_VXGE_DEBUG_TRACE_ALL is not set +CONFIG_NET_VENDOR_HP=y +CONFIG_HP100=m CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGB_HWMON=y +CONFIG_IGBVF=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGBE_HWMON=y +CONFIG_IXGBE_DCB=y +CONFIG_IXGBEVF=m +CONFIG_I40E=m +CONFIG_I40E_VXLAN=y +CONFIG_I40E_DCB=y +CONFIG_I40EVF=m CONFIG_NET_VENDOR_I825XX=y +CONFIG_IP1000=m +CONFIG_JME=m CONFIG_NET_VENDOR_MARVELL=y # CONFIG_MVMDIO is not set +CONFIG_SKGE=m +# CONFIG_SKGE_DEBUG is not set +CONFIG_SKGE_GENESIS=y +CONFIG_SKY2=m +# CONFIG_SKY2_DEBUG is not set +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_MLX4_EN=m +CONFIG_MLX4_EN_DCB=y +CONFIG_MLX4_EN_VXLAN=y +CONFIG_MLX4_CORE=m +CONFIG_MLX4_DEBUG=y +CONFIG_MLX5_CORE=m CONFIG_NET_VENDOR_MICREL=y +CONFIG_KS8842=m # CONFIG_KS8851 is not set CONFIG_KS8851_MLL=m +CONFIG_KSZ884X_PCI=m # CONFIG_NET_VENDOR_MICROCHIP is not set +CONFIG_NET_VENDOR_MYRI=y +CONFIG_MYRI10GE=m +CONFIG_FEALNX=m CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NATSEMI=m +CONFIG_NS83820=m CONFIG_NET_VENDOR_8390=y +CONFIG_NE2K_PCI=m +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=m +CONFIG_NET_VENDOR_OKI=y CONFIG_ETHOC=m +CONFIG_NET_PACKET_ENGINE=y +CONFIG_HAMACHI=m +CONFIG_YELLOWFIN=m +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_QLA3XXX=m +CONFIG_QLCNIC=m +CONFIG_QLCNIC_SRIOV=y +CONFIG_QLCNIC_DCB=y +CONFIG_QLCNIC_VXLAN=y +CONFIG_QLCNIC_HWMON=y +CONFIG_QLGE=m +CONFIG_NETXEN_NIC=m +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_8139CP=m +CONFIG_8139TOO=m +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +CONFIG_8139TOO_8129=y +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=m CONFIG_SH_ETH=m +CONFIG_NET_VENDOR_RDC=y +CONFIG_R6040=m CONFIG_NET_VENDOR_SAMSUNG=y CONFIG_SXGBE_ETH=m CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_SC92031=m +CONFIG_NET_VENDOR_SIS=y +CONFIG_SIS900=m +CONFIG_SIS190=m +CONFIG_SFC=m +CONFIG_SFC_MTD=y +CONFIG_SFC_MCDI_MON=y +CONFIG_SFC_SRIOV=y CONFIG_NET_VENDOR_SMSC=y CONFIG_SMC91X=m +CONFIG_EPIC100=m CONFIG_SMSC911X=m # CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_SMSC9420=m CONFIG_NET_VENDOR_STMICRO=y # CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_SUN=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNGEM=m +CONFIG_CASSINI=m +CONFIG_NIU=m +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_TEHUTI=m +CONFIG_NET_VENDOR_TI=y +CONFIG_TLAN=m CONFIG_NET_VENDOR_VIA=y +CONFIG_VIA_RHINE=m +CONFIG_VIA_RHINE_MMIO=y +CONFIG_VIA_VELOCITY=m CONFIG_NET_VENDOR_WIZNET=y CONFIG_WIZNET_W5100=m CONFIG_WIZNET_W5300=m # CONFIG_WIZNET_BUS_DIRECT is not set # CONFIG_WIZNET_BUS_INDIRECT is not set CONFIG_WIZNET_BUS_ANY=y +CONFIG_FDDI=m +CONFIG_DEFXX=m +CONFIG_DEFXX_MMIO=y +CONFIG_SKFP=m +CONFIG_HIPPI=y +CONFIG_ROADRUNNER=m +# CONFIG_ROADRUNNER_LARGE_RINGS is not set CONFIG_PHYLIB=m # @@ -1780,19 +2177,30 @@ CONFIG_WLAN=y CONFIG_LIBERTAS_THINFIRM=m # CONFIG_LIBERTAS_THINFIRM_DEBUG is not set CONFIG_LIBERTAS_THINFIRM_USB=m +CONFIG_ATMEL=m +CONFIG_PCI_ATMEL=m CONFIG_AT76C50X_USB=m +CONFIG_PRISM54=m CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_RTL8180=m CONFIG_RTL8187=m CONFIG_RTL8187_LEDS=y +CONFIG_ADM8211=m CONFIG_MAC80211_HWSIM=m +CONFIG_MWL8K=m CONFIG_ATH_COMMON=m CONFIG_ATH_CARDS=m # CONFIG_ATH_DEBUG is not set +CONFIG_ATH5K=m +# CONFIG_ATH5K_DEBUG is not set +# CONFIG_ATH5K_TRACER is not set +CONFIG_ATH5K_PCI=y CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K_BTCOEX_SUPPORT=y CONFIG_ATH9K=m +CONFIG_ATH9K_PCI=y # CONFIG_ATH9K_AHB is not set # CONFIG_ATH9K_DEBUGFS is not set # CONFIG_ATH9K_WOW is not set @@ -1806,7 +2214,11 @@ CONFIG_CARL9170_WPC=y # CONFIG_CARL9170_HWRNG is not set # CONFIG_ATH6KL is not set CONFIG_AR5523=m +CONFIG_WIL6210=m +CONFIG_WIL6210_ISR_COR=y +CONFIG_WIL6210_TRACING=y CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m # CONFIG_ATH10K_DEBUG is not set # CONFIG_ATH10K_DEBUGFS is not set # CONFIG_ATH10K_TRACING is not set @@ -1822,17 +2234,69 @@ CONFIG_BRCMSMAC=m CONFIG_HOSTAP=m CONFIG_HOSTAP_FIRMWARE=y CONFIG_HOSTAP_FIRMWARE_NVRAM=y +CONFIG_HOSTAP_PLX=m +CONFIG_HOSTAP_PCI=m +CONFIG_IPW2100=m +CONFIG_IPW2100_MONITOR=y +CONFIG_IPW2100_DEBUG=y +CONFIG_IPW2200=m +CONFIG_IPW2200_MONITOR=y +CONFIG_IPW2200_RADIOTAP=y +CONFIG_IPW2200_PROMISCUOUS=y +CONFIG_IPW2200_QOS=y +CONFIG_IPW2200_DEBUG=y +CONFIG_LIBIPW=m +CONFIG_LIBIPW_DEBUG=y +CONFIG_IWLWIFI=m +CONFIG_IWLWIFI_LEDS=y +CONFIG_IWLDVM=m +CONFIG_IWLMVM=m +CONFIG_IWLWIFI_OPMODE_MODULAR=y +# CONFIG_IWLWIFI_BCAST_FILTERING is not set + +# +# Debugging Options +# +CONFIG_IWLWIFI_DEBUG=y +CONFIG_IWLWIFI_DEBUGFS=y +# CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set +# CONFIG_IWLWIFI_DEVICE_TRACING is not set +CONFIG_IWLEGACY=m +CONFIG_IWL4965=m +CONFIG_IWL3945=m + +# +# iwl3945 / iwl4965 Debugging Options +# +# CONFIG_IWLEGACY_DEBUG is not set +# CONFIG_IWLEGACY_DEBUGFS is not set CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m CONFIG_LIBERTAS_SDIO=m # CONFIG_LIBERTAS_SPI is not set # CONFIG_LIBERTAS_DEBUG is not set CONFIG_LIBERTAS_MESH=y +CONFIG_HERMES=m +# CONFIG_HERMES_PRISM is not set +CONFIG_HERMES_CACHE_FW_ON_INIT=y +CONFIG_PLX_HERMES=m +CONFIG_TMD_HERMES=m +CONFIG_NORTEL_HERMES=m +CONFIG_ORINOCO_USB=m CONFIG_P54_COMMON=m CONFIG_P54_USB=m +CONFIG_P54_PCI=m # CONFIG_P54_SPI is not set CONFIG_P54_LEDS=y CONFIG_RT2X00=m +CONFIG_RT2400PCI=m +CONFIG_RT2500PCI=m +CONFIG_RT61PCI=m +CONFIG_RT2800PCI=m +CONFIG_RT2800PCI_RT33XX=y +CONFIG_RT2800PCI_RT35XX=y +CONFIG_RT2800PCI_RT53XX=y +CONFIG_RT2800PCI_RT3290=y CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m @@ -1843,6 +2307,9 @@ CONFIG_RT2800USB_RT53XX=y CONFIG_RT2800USB_RT55XX=y CONFIG_RT2800USB_UNKNOWN=y CONFIG_RT2800_LIB=m +CONFIG_RT2800_LIB_MMIO=m +CONFIG_RT2X00_LIB_MMIO=m +CONFIG_RT2X00_LIB_PCI=m CONFIG_RT2X00_LIB_USB=m CONFIG_RT2X00_LIB=m CONFIG_RT2X00_LIB_FIRMWARE=y @@ -1851,16 +2318,26 @@ CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_LIB_DEBUGFS is not set # CONFIG_RT2X00_DEBUG is not set CONFIG_RTL_CARDS=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m CONFIG_RTL8192CU=m CONFIG_RTLWIFI=m +CONFIG_RTLWIFI_PCI=m CONFIG_RTLWIFI_USB=m CONFIG_RTLWIFI_DEBUG=y CONFIG_RTL8192C_COMMON=m +CONFIG_RTL8723_COMMON=m +CONFIG_RTLBTCOEXIST=m # CONFIG_WL_TI is not set CONFIG_ZD1211RW=m # CONFIG_ZD1211RW_DEBUG is not set CONFIG_MWIFIEX=m CONFIG_MWIFIEX_SDIO=m +CONFIG_MWIFIEX_PCIE=m # CONFIG_MWIFIEX_USB is not set # CONFIG_CW1200 is not set CONFIG_RSI_91X=m @@ -1882,6 +2359,13 @@ CONFIG_HDLC_CISCO=m CONFIG_HDLC_FR=m CONFIG_HDLC_PPP=m CONFIG_HDLC_X25=m +CONFIG_PCI200SYN=m +CONFIG_WANXL=m +CONFIG_PC300TOO=m +CONFIG_FARSYNC=m +CONFIG_DSCC4=m +CONFIG_DSCC4_PCISYNC=y +CONFIG_DSCC4_PCI_RST=y CONFIG_DLCI=m CONFIG_DLCI_MAX=8 CONFIG_LAPBETHER=m @@ -1891,6 +2375,7 @@ CONFIG_IEEE802154_FAKEHARD=m CONFIG_IEEE802154_FAKELB=m # CONFIG_IEEE802154_AT86RF230 is not set # CONFIG_IEEE802154_MRF24J40 is not set +# CONFIG_VMXNET3 is not set CONFIG_ISDN=y CONFIG_ISDN_I4L=m CONFIG_ISDN_PPP=y @@ -1932,6 +2417,7 @@ CONFIG_HISAX_MAX_CARDS=8 # HiSax supported cards # CONFIG_HISAX_16_3=y +CONFIG_HISAX_TELESPCI=y CONFIG_HISAX_S0BOX=y CONFIG_HISAX_FRITZPCI=y CONFIG_HISAX_AVM_A1_PCMCIA=y @@ -1939,7 +2425,11 @@ CONFIG_HISAX_ELSA=y CONFIG_HISAX_DIEHLDIVA=y CONFIG_HISAX_SEDLBAUER=y CONFIG_HISAX_NICCY=y +CONFIG_HISAX_BKM_A4T=y +CONFIG_HISAX_SCT_QUADRO=y CONFIG_HISAX_GAZEL=y +CONFIG_HISAX_HFC_PCI=y +CONFIG_HISAX_W6692=y CONFIG_HISAX_HFC_SX=y # CONFIG_HISAX_DEBUG is not set @@ -1953,6 +2443,7 @@ CONFIG_HISAX_HFC_SX=y CONFIG_HISAX_ST5481=m CONFIG_HISAX_HFCUSB=m CONFIG_HISAX_HFC4S8S=m +CONFIG_HISAX_FRITZ_PCIPNP=m # # Active cards @@ -1968,7 +2459,17 @@ CONFIG_ISDN_CAPI_CAPIDRV=m # CAPI hardware drivers # CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m CONFIG_CAPI_EICON=y +CONFIG_ISDN_DIVAS=m +CONFIG_ISDN_DIVAS_BRIPCI=y +CONFIG_ISDN_DIVAS_PRIPCI=y +CONFIG_ISDN_DIVAS_DIVACAPI=m +CONFIG_ISDN_DIVAS_USERIDI=m +CONFIG_ISDN_DIVAS_MAINT=m CONFIG_ISDN_DRV_GIGASET=m CONFIG_GIGASET_CAPI=y # CONFIG_GIGASET_I4L is not set @@ -1977,6 +2478,8 @@ CONFIG_GIGASET_BASE=m CONFIG_GIGASET_M105=m CONFIG_GIGASET_M101=m # CONFIG_GIGASET_DEBUG is not set +CONFIG_HYSDN=m +CONFIG_HYSDN_CAPI=y CONFIG_MISDN=m CONFIG_MISDN_DSP=m CONFIG_MISDN_L1OIP=m @@ -1984,7 +2487,16 @@ CONFIG_MISDN_L1OIP=m # # mISDN hardware drivers # +CONFIG_MISDN_HFCPCI=m +CONFIG_MISDN_HFCMULTI=m CONFIG_MISDN_HFCUSB=m +CONFIG_MISDN_AVMFRITZ=m +CONFIG_MISDN_SPEEDFAX=m +CONFIG_MISDN_INFINEON=m +CONFIG_MISDN_W6692=m +CONFIG_MISDN_NETJET=m +CONFIG_MISDN_IPAC=m +CONFIG_MISDN_ISAR=m CONFIG_ISDN_HDLC=m # @@ -2126,6 +2638,7 @@ CONFIG_TOUCHSCREEN_TOUCHRIGHT=m CONFIG_TOUCHSCREEN_TOUCHWIN=m # CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set # CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set CONFIG_TOUCHSCREEN_USB_COMPOSITE=m CONFIG_TOUCHSCREEN_USB_EGALAX=y CONFIG_TOUCHSCREEN_USB_PANJIT=y @@ -2188,6 +2701,7 @@ CONFIG_SERIO=y CONFIG_SERIO_SERPORT=m CONFIG_SERIO_PARKBD=m # CONFIG_SERIO_AMBAKMI is not set +CONFIG_SERIO_PCIPS2=m CONFIG_SERIO_LIBPS2=y CONFIG_SERIO_RAW=m CONFIG_SERIO_ALTERA_PS2=m @@ -2197,6 +2711,8 @@ CONFIG_SERIO_APBPS2=m CONFIG_GAMEPORT=m CONFIG_GAMEPORT_NS558=m CONFIG_GAMEPORT_L4=m +CONFIG_GAMEPORT_EMU10K1=m +CONFIG_GAMEPORT_FM801=m # # Character devices @@ -2213,6 +2729,15 @@ CONFIG_DEVPTS_MULTIPLE_INSTANCES=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +CONFIG_CYCLADES=m +# CONFIG_CYZ_INTR is not set +CONFIG_MOXA_INTELLIO=m +CONFIG_MOXA_SMARTIO=m +CONFIG_SYNCLINKMP=m +CONFIG_SYNCLINK_GT=m +CONFIG_NOZOMI=m +CONFIG_ISI=m CONFIG_N_HDLC=m CONFIG_N_GSM=m CONFIG_TRACE_ROUTER=m @@ -2227,6 +2752,7 @@ CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCI=y CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set @@ -2242,8 +2768,12 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y # CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set # CONFIG_SERIAL_MAX3100 is not set # CONFIG_SERIAL_MAX310X is not set +CONFIG_SERIAL_MRST_MAX3110=m +# CONFIG_SERIAL_MFD_HSU is not set +CONFIG_SERIAL_UARTLITE=m CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_JSM=m CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_SERIAL_SCCNXP is not set # CONFIG_SERIAL_SC16IS7XX is not set @@ -2254,6 +2784,8 @@ CONFIG_SERIAL_ALTERA_UART_BAUDRATE=115200 # CONFIG_SERIAL_IFX6X60 is not set # CONFIG_SERIAL_XILINX_PS_UART is not set # CONFIG_SERIAL_ARC is not set +CONFIG_SERIAL_RP2=m +CONFIG_SERIAL_RP2_NR_UARTS=32 # CONFIG_SERIAL_FSL_LPUART is not set # CONFIG_TTY_PRINTK is not set CONFIG_PRINTER=m @@ -2274,6 +2806,7 @@ CONFIG_HW_RANDOM_TIMERIOMEM=m CONFIG_HW_RANDOM_VIRTIO=m CONFIG_HW_RANDOM_TPM=m CONFIG_R3964=m +CONFIG_APPLICOM=m # # PCMCIA character devices @@ -2284,7 +2817,9 @@ CONFIG_TCG_TPM=m # CONFIG_TCG_TIS_I2C_ATMEL is not set # CONFIG_TCG_TIS_I2C_INFINEON is not set # CONFIG_TCG_TIS_I2C_NUVOTON is not set +CONFIG_TCG_ATMEL=m # CONFIG_TCG_ST33_I2C is not set +CONFIG_DEVPORT=y CONFIG_CRASHER=m CONFIG_I2C=m CONFIG_I2C_BOARDINFO=y @@ -2300,16 +2835,37 @@ CONFIG_I2C_MUX=m # CONFIG_I2C_MUX_PCA9541 is not set # CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=m # # I2C Hardware Bus support # # +# PC SMBus host controller drivers +# +CONFIG_I2C_ALI1535=m +CONFIG_I2C_ALI1563=m +CONFIG_I2C_ALI15X3=m +CONFIG_I2C_AMD756=m +CONFIG_I2C_AMD8111=m +CONFIG_I2C_I801=m +CONFIG_I2C_ISCH=m +CONFIG_I2C_PIIX4=m +CONFIG_I2C_NFORCE2=m +CONFIG_I2C_SIS5595=m +CONFIG_I2C_SIS630=m +CONFIG_I2C_SIS96X=m +# CONFIG_I2C_VIA is not set +CONFIG_I2C_VIAPRO=m + +# # I2C system bus drivers (mostly embedded / system-on-chip) # # CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=m # CONFIG_I2C_DESIGNWARE_PLATFORM is not set +CONFIG_I2C_DESIGNWARE_PCI=m # CONFIG_I2C_GPIO is not set # CONFIG_I2C_KEMPLD is not set # CONFIG_I2C_NOMADIK is not set @@ -2356,11 +2912,13 @@ CONFIG_SPI_FSL_LIB=y CONFIG_SPI_FSL_SPI=y CONFIG_SPI_OC_TINY=m CONFIG_SPI_PL022=m +# CONFIG_SPI_PXA2XX is not set # CONFIG_SPI_PXA2XX_PCI is not set CONFIG_SPI_SC18IS602=m CONFIG_SPI_XCOMM=m CONFIG_SPI_XILINX=m CONFIG_SPI_DESIGNWARE=m +CONFIG_SPI_DW_PCI=m CONFIG_SPI_DW_MMIO=m # @@ -2415,6 +2973,7 @@ CONFIG_GPIO_DWAPB=m CONFIG_GPIO_PL061=y # CONFIG_GPIO_SCH311X is not set CONFIG_GPIO_SYSCON=m +CONFIG_GPIO_VX855=m CONFIG_GPIO_GRGPIO=m # @@ -2430,6 +2989,10 @@ CONFIG_GPIO_GRGPIO=m # # PCI GPIO expanders: # +CONFIG_GPIO_AMD8111=m +CONFIG_GPIO_ML_IOH=m +CONFIG_GPIO_TIMBERDALE=y +# CONFIG_GPIO_RDC321X is not set # # SPI GPIO expanders: @@ -2463,6 +3026,7 @@ CONFIG_W1_CON=y # # 1-wire Bus Masters # +CONFIG_W1_MASTER_MATROX=m CONFIG_W1_MASTER_DS2490=m # CONFIG_W1_MASTER_DS2482 is not set CONFIG_W1_MASTER_DS1WM=m @@ -2512,7 +3076,7 @@ CONFIG_CHARGER_GPIO=m CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_VEXPRESS=y -CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -2540,6 +3104,7 @@ CONFIG_HWMON_VID=m # CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS620 is not set # CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set CONFIG_SENSORS_F71805F=m CONFIG_SENSORS_F71882FG=m # CONFIG_SENSORS_F75375S is not set @@ -2600,6 +3165,7 @@ CONFIG_SENSORS_NCT6775=m CONFIG_SENSORS_SHT15=m # CONFIG_SENSORS_SHT21 is not set CONFIG_SENSORS_SHTC1=m +CONFIG_SENSORS_SIS5595=m # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_EMC1403 is not set # CONFIG_SENSORS_EMC2103 is not set @@ -2623,7 +3189,9 @@ CONFIG_SENSORS_ADC128D818=m # CONFIG_SENSORS_TMP401 is not set # CONFIG_SENSORS_TMP421 is not set CONFIG_SENSORS_VEXPRESS=m +# CONFIG_SENSORS_VIA686A is not set CONFIG_SENSORS_VT1211=m +# CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set # CONFIG_SENSORS_W83792D is not set @@ -2661,10 +3229,18 @@ CONFIG_SOFT_WATCHDOG=m # CONFIG_XILINX_WATCHDOG is not set # CONFIG_ARM_SP805_WATCHDOG is not set # CONFIG_DW_WATCHDOG is not set +CONFIG_ALIM7101_WDT=m +CONFIG_I6300ESB_WDT=m CONFIG_KEMPLD_WDT=m # CONFIG_MEN_A21_WDT is not set # +# PCI-based Watchdog Cards +# +CONFIG_PCIPCWATCHDOG=m +CONFIG_WDTPCI=m + +# # USB-based Watchdog Cards # CONFIG_USBPCWATCHDOG=m @@ -2674,10 +3250,16 @@ CONFIG_SSB_POSSIBLE=y # Sonics Silicon Backplane # CONFIG_SSB=m +CONFIG_SSB_SPROM=y +CONFIG_SSB_PCIHOST_POSSIBLE=y +CONFIG_SSB_PCIHOST=y +# CONFIG_SSB_B43_PCI_BRIDGE is not set CONFIG_SSB_SDIOHOST_POSSIBLE=y CONFIG_SSB_SDIOHOST=y # CONFIG_SSB_SILENT is not set # CONFIG_SSB_DEBUG is not set +CONFIG_SSB_DRIVER_PCICORE_POSSIBLE=y +CONFIG_SSB_DRIVER_PCICORE=y CONFIG_SSB_DRIVER_GPIO=y CONFIG_BCMA_POSSIBLE=y @@ -2685,6 +3267,8 @@ CONFIG_BCMA_POSSIBLE=y # Broadcom specific AMBA # CONFIG_BCMA=m +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_PCI=y CONFIG_BCMA_HOST_SOC=y CONFIG_BCMA_DRIVER_GMAC_CMN=y CONFIG_BCMA_DRIVER_GPIO=y @@ -2702,11 +3286,17 @@ CONFIG_MFD_CROS_EC=m # CONFIG_MFD_MC13XXX_SPI is not set # CONFIG_MFD_MC13XXX_I2C is not set CONFIG_HTC_PASIC3=m +# CONFIG_LPC_ICH is not set +CONFIG_LPC_SCH=m +# CONFIG_MFD_JANZ_CMODIO is not set CONFIG_MFD_KEMPLD=m # CONFIG_EZX_PCAP is not set CONFIG_MFD_VIPERBOARD=m # CONFIG_MFD_RETU is not set # CONFIG_MFD_PCF50633 is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_MFD_RDC321X is not set +CONFIG_MFD_RTSX_PCI=m CONFIG_MFD_RTSX_USB=m # CONFIG_MFD_SI476X_CORE is not set # CONFIG_MFD_SM501 is not set @@ -2724,7 +3314,9 @@ CONFIG_MFD_TI_AM335X_TSCADC=m # CONFIG_MFD_TPS65912_SPI is not set # CONFIG_MFD_WL1273_CORE is not set # CONFIG_MFD_LM3533 is not set +CONFIG_MFD_TIMBERDALE=m # CONFIG_MFD_TMIO is not set +CONFIG_MFD_VX855=m # CONFIG_MFD_ARIZONA_I2C is not set # CONFIG_MFD_ARIZONA_SPI is not set # CONFIG_MFD_WM831X_SPI is not set @@ -2773,16 +3365,22 @@ CONFIG_VIDEO_DEV=m CONFIG_VIDEO_V4L2=m # CONFIG_VIDEO_ADV_DEBUG is not set # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m CONFIG_V4L2_MEM2MEM_DEV=m CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_DMA_SG=m CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_VIDEOBUF_DMA_CONTIG=m +CONFIG_VIDEOBUF_DVB=m CONFIG_VIDEOBUF2_CORE=m CONFIG_VIDEOBUF2_MEMOPS=m CONFIG_VIDEOBUF2_DMA_CONTIG=m CONFIG_VIDEOBUF2_VMALLOC=m +CONFIG_VIDEOBUF2_DMA_SG=m +CONFIG_VIDEOBUF2_DVB=m CONFIG_DVB_CORE=m CONFIG_DVB_NET=y -# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTPCI_EEPROM=m CONFIG_DVB_MAX_ADAPTERS=8 CONFIG_DVB_DYNAMIC_MINORS=y @@ -2907,6 +3505,8 @@ CONFIG_VIDEO_HDPVR=m # # CONFIG_DVB_USB is not set # CONFIG_DVB_USB_V2 is not set +CONFIG_DVB_TTUSB_BUDGET=m +CONFIG_DVB_TTUSB_DEC=m # CONFIG_SMS_USB_DRV is not set # CONFIG_DVB_B2C2_FLEXCOP_USB is not set @@ -2914,9 +3514,72 @@ CONFIG_VIDEO_HDPVR=m # Webcam, TV (analog/digital) USB devices # # CONFIG_VIDEO_EM28XX is not set +CONFIG_MEDIA_PCI_SUPPORT=y + +# +# Media capture support +# + +# +# Media capture/analog TV support +# +CONFIG_VIDEO_IVTV=m +CONFIG_VIDEO_IVTV_ALSA=m +CONFIG_VIDEO_FB_IVTV=m +CONFIG_VIDEO_HEXIUM_GEMINI=m +CONFIG_VIDEO_HEXIUM_ORION=m +CONFIG_VIDEO_MXB=m + +# +# Media capture/analog/hybrid TV support +# +CONFIG_VIDEO_CX18=m +CONFIG_VIDEO_CX18_ALSA=m +CONFIG_VIDEO_CX23885=m +CONFIG_MEDIA_ALTERA_CI=m +CONFIG_VIDEO_CX25821=m +CONFIG_VIDEO_CX25821_ALSA=m +CONFIG_VIDEO_CX88=m +CONFIG_VIDEO_CX88_ALSA=m +CONFIG_VIDEO_CX88_BLACKBIRD=m +CONFIG_VIDEO_CX88_DVB=m +CONFIG_VIDEO_CX88_ENABLE_VP3054=y +CONFIG_VIDEO_CX88_VP3054=m +CONFIG_VIDEO_CX88_MPEG=m +CONFIG_VIDEO_BT848=m +CONFIG_DVB_BT8XX=m +CONFIG_VIDEO_SAA7134=m +CONFIG_VIDEO_SAA7134_ALSA=m +CONFIG_VIDEO_SAA7134_RC=y +CONFIG_VIDEO_SAA7134_DVB=m +CONFIG_VIDEO_SAA7164=m + +# +# Media digital TV PCI Adapters +# +CONFIG_DVB_AV7110=m +CONFIG_DVB_AV7110_OSD=y +CONFIG_DVB_BUDGET_CORE=m +CONFIG_DVB_BUDGET=m +CONFIG_DVB_BUDGET_CI=m +CONFIG_DVB_BUDGET_AV=m +CONFIG_DVB_BUDGET_PATCH=m +CONFIG_DVB_B2C2_FLEXCOP_PCI=m +# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set +CONFIG_DVB_PLUTO2=m +CONFIG_DVB_DM1105=m +CONFIG_DVB_PT1=m +CONFIG_MANTIS_CORE=m +CONFIG_DVB_MANTIS=m +CONFIG_DVB_HOPPER=m +CONFIG_DVB_NGENE=m +CONFIG_DVB_DDBRIDGE=m CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_CAFE_CCIC=m +CONFIG_VIDEO_TIMBERDALE=m # CONFIG_SOC_CAMERA is not set CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m CONFIG_VIDEO_SH_VEU=m CONFIG_V4L_TEST_DRIVERS=y CONFIG_VIDEO_VIVI=m @@ -2938,26 +3601,40 @@ CONFIG_USB_SI470X=m # CONFIG_RADIO_SI4713 is not set CONFIG_USB_MR800=m CONFIG_USB_DSBR=m +CONFIG_RADIO_MAXIRADIO=m CONFIG_RADIO_SHARK=m CONFIG_RADIO_SHARK2=m CONFIG_USB_KEENE=m # CONFIG_USB_RAREMONO is not set CONFIG_USB_MA901=m # CONFIG_RADIO_TEA5764 is not set -# CONFIG_RADIO_SAA7706H is not set -# CONFIG_RADIO_TEF6862 is not set +CONFIG_RADIO_SAA7706H=m +CONFIG_RADIO_TEF6862=m +CONFIG_RADIO_TIMBERDALE=m # CONFIG_RADIO_WL1273 is not set # # Texas Instruments WL128x FM driver (ST based) # CONFIG_RADIO_WL128X=m + +# +# Supported FireWire (IEEE 1394) Adapters +# +CONFIG_DVB_FIREDTV=m +CONFIG_DVB_FIREDTV_INPUT=y CONFIG_MEDIA_COMMON_OPTIONS=y # # common driver options # +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_BTCX=m +CONFIG_VIDEO_TVEEPROM=m CONFIG_CYPRESS_FIRMWARE=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_VIDEO_SAA7146=m +CONFIG_VIDEO_SAA7146_VV=m CONFIG_SMS_SIANO_MDTV=m CONFIG_SMS_SIANO_RC=y @@ -2971,26 +3648,44 @@ CONFIG_VIDEO_IR_I2C=m # # Audio decoders, processors and mixers # +CONFIG_VIDEO_TVAUDIO=m +CONFIG_VIDEO_TDA7432=m +CONFIG_VIDEO_TDA9840=m +CONFIG_VIDEO_TEA6415C=m +CONFIG_VIDEO_TEA6420=m +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS5345=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_WM8775=m +CONFIG_VIDEO_WM8739=m +CONFIG_VIDEO_VP27SMPX=m # # RDS decoders # +CONFIG_VIDEO_SAA6588=m # # Video decoders # +CONFIG_VIDEO_ADV7180=m +CONFIG_VIDEO_SAA711X=m # # Video and audio decoders # +CONFIG_VIDEO_SAA717X=m +CONFIG_VIDEO_CX25840=m # # Video encoders # +CONFIG_VIDEO_SAA7127=m # # Camera sensor devices # +CONFIG_VIDEO_OV7670=m # # Flash devices @@ -2999,14 +3694,18 @@ CONFIG_VIDEO_IR_I2C=m # # Video improvement chips # +CONFIG_VIDEO_UPD64031A=m +CONFIG_VIDEO_UPD64083=m # # Audio/Video compression chips # +CONFIG_VIDEO_SAA6752HS=m # # Miscellaneous helper chips # +CONFIG_VIDEO_M52790=m # # Sensors used on soc_camera driver @@ -3020,46 +3719,113 @@ CONFIG_MEDIA_TUNER_TDA9887=m CONFIG_MEDIA_TUNER_TEA5761=m CONFIG_MEDIA_TUNER_TEA5767=m CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2131=m CONFIG_MEDIA_TUNER_XC2028=m CONFIG_MEDIA_TUNER_XC5000=m CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MXL5005S=m CONFIG_MEDIA_TUNER_MC44S803=m # # Multistandard (satellite) frontends # +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV6110x=m # # Multistandard (cable + terrestrial) frontends # +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m # # DVB-S (satellite) frontends # +CONFIG_DVB_CX24110=m +CONFIG_DVB_CX24123=m +CONFIG_DVB_MT312=m +CONFIG_DVB_ZL10036=m +CONFIG_DVB_ZL10039=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_STV0288=m +CONFIG_DVB_STB6000=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_STV6110=m +CONFIG_DVB_STV0900=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TDA8261=m +CONFIG_DVB_VES1X93=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_TUNER_CX24113=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_TUA6100=m +CONFIG_DVB_CX24116=m +CONFIG_DVB_CX24117=m +CONFIG_DVB_SI21XX=m +CONFIG_DVB_TS2020=m +CONFIG_DVB_DS3000=m +CONFIG_DVB_MB86A16=m +CONFIG_DVB_TDA10071=m # # DVB-T (terrestrial) frontends # +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_STV0367=m # # DVB-C (cable) frontends # +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m # # ATSC (North American/Korean Terrestrial/Cable DTV) frontends # +CONFIG_DVB_NXT200X=m +CONFIG_DVB_OR51211=m +CONFIG_DVB_OR51132=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LGDT3305=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_S5H1411=m # # ISDB-T (terrestrial) frontends # +CONFIG_DVB_MB86A20S=m # # Digital terrestrial only tuners/PLL # +CONFIG_DVB_PLL=m # # SEC control devices for DVB-S # +CONFIG_DVB_LNBP21=m +CONFIG_DVB_ISL6405=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_ISL6423=m +CONFIG_DVB_A8293=m +CONFIG_DVB_TDA665x=m # # Tools to develop new frontends @@ -3069,6 +3835,8 @@ CONFIG_MEDIA_TUNER_MC44S803=m # # Graphics support # +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 # # Direct Rendering Manager @@ -3101,14 +3869,39 @@ CONFIG_FB_TILEBLITTING=y # # Frame buffer hardware drivers # +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set # CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set CONFIG_FB_UVESA=m # CONFIG_FB_OPENCORES is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set # CONFIG_FB_SMSCUFX is not set # CONFIG_FB_UDL is not set CONFIG_FB_VIRTUAL=m CONFIG_FB_METRONOME=m +# CONFIG_FB_MB862XX is not set CONFIG_FB_BROADSHEET=m # CONFIG_FB_AUO_K190X is not set # CONFIG_FB_SIMPLE is not set @@ -3160,6 +3953,7 @@ CONFIG_SND_TIMER=m CONFIG_SND_PCM=m CONFIG_SND_HWDEP=m CONFIG_SND_RAWMIDI=m +CONFIG_SND_JACK=y CONFIG_SND_SEQUENCER=m CONFIG_SND_SEQ_DUMMY=m CONFIG_SND_OSSEMUL=y @@ -3178,12 +3972,16 @@ CONFIG_SND_DEBUG=y # CONFIG_SND_DEBUG_VERBOSE is not set CONFIG_SND_PCM_XRUN_DEBUG=y CONFIG_SND_VMASTER=y +CONFIG_SND_KCTL_JACK=y CONFIG_SND_RAWMIDI_SEQ=m -# CONFIG_SND_OPL3_LIB_SEQ is not set +CONFIG_SND_OPL3_LIB_SEQ=m # CONFIG_SND_OPL4_LIB_SEQ is not set # CONFIG_SND_SBAWE_SEQ is not set -# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_EMU10K1_SEQ=m CONFIG_SND_MPU401_UART=m +CONFIG_SND_OPL3_LIB=m +CONFIG_SND_VX_LIB=m +CONFIG_SND_AC97_CODEC=m CONFIG_SND_DRIVERS=y CONFIG_SND_DUMMY=m CONFIG_SND_ALOOP=m @@ -3193,10 +3991,106 @@ CONFIG_SND_MTS64=m CONFIG_SND_SERIAL_U16550=m CONFIG_SND_MPU401=m CONFIG_SND_PORTMAN2X4=m +CONFIG_SND_AC97_POWER_SAVE=y +CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 +CONFIG_SND_PCI=y +CONFIG_SND_AD1889=m +CONFIG_SND_ALS300=m +CONFIG_SND_ALI5451=m +CONFIG_SND_ATIIXP=m +CONFIG_SND_ATIIXP_MODEM=m +CONFIG_SND_AU8810=m +CONFIG_SND_AU8820=m +CONFIG_SND_AU8830=m +CONFIG_SND_AW2=m +CONFIG_SND_AZT3328=m +CONFIG_SND_BT87X=m +# CONFIG_SND_BT87X_OVERCLOCK is not set +CONFIG_SND_CA0106=m +CONFIG_SND_CMIPCI=m +CONFIG_SND_OXYGEN_LIB=m +CONFIG_SND_OXYGEN=m +CONFIG_SND_CS4281=m +CONFIG_SND_CS46XX=m +CONFIG_SND_CS46XX_NEW_DSP=y +CONFIG_SND_CTXFI=m +CONFIG_SND_DARLA20=m +CONFIG_SND_GINA20=m +CONFIG_SND_LAYLA20=m +CONFIG_SND_DARLA24=m +CONFIG_SND_GINA24=m +CONFIG_SND_LAYLA24=m +CONFIG_SND_MONA=m +CONFIG_SND_MIA=m +CONFIG_SND_ECHO3G=m +CONFIG_SND_INDIGO=m +CONFIG_SND_INDIGOIO=m +CONFIG_SND_INDIGODJ=m +CONFIG_SND_INDIGOIOX=m +CONFIG_SND_INDIGODJX=m +CONFIG_SND_EMU10K1=m +CONFIG_SND_EMU10K1X=m +CONFIG_SND_ENS1370=m +CONFIG_SND_ENS1371=m +CONFIG_SND_ES1938=m +CONFIG_SND_ES1968=m +CONFIG_SND_ES1968_INPUT=y +CONFIG_SND_ES1968_RADIO=y +CONFIG_SND_FM801=m +CONFIG_SND_FM801_TEA575X_BOOL=y +CONFIG_SND_HDSP=m +CONFIG_SND_HDSPM=m +CONFIG_SND_ICE1712=m +CONFIG_SND_ICE1724=m +CONFIG_SND_INTEL8X0=m +CONFIG_SND_INTEL8X0M=m +CONFIG_SND_KORG1212=m +CONFIG_SND_LOLA=m +CONFIG_SND_LX6464ES=m +CONFIG_SND_MAESTRO3=m +CONFIG_SND_MAESTRO3_INPUT=y +CONFIG_SND_MIXART=m +CONFIG_SND_NM256=m +CONFIG_SND_PCXHR=m +CONFIG_SND_RIPTIDE=m +CONFIG_SND_RME32=m +CONFIG_SND_RME96=m +CONFIG_SND_RME9652=m +CONFIG_SND_SONICVIBES=m +CONFIG_SND_TRIDENT=m +CONFIG_SND_VIA82XX=m +CONFIG_SND_VIA82XX_MODEM=m +CONFIG_SND_VIRTUOSO=m +CONFIG_SND_VX222=m +CONFIG_SND_YMFPCI=m # # HD-Audio # +CONFIG_SND_HDA=m +CONFIG_SND_HDA_INTEL=m +CONFIG_SND_HDA_DSP_LOADER=y +CONFIG_SND_HDA_PREALLOC_SIZE=1024 +CONFIG_SND_HDA_HWDEP=y +CONFIG_SND_HDA_RECONFIG=y +CONFIG_SND_HDA_INPUT_BEEP=y +CONFIG_SND_HDA_INPUT_BEEP_MODE=1 +CONFIG_SND_HDA_INPUT_JACK=y +CONFIG_SND_HDA_PATCH_LOADER=y +CONFIG_SND_HDA_CODEC_REALTEK=m +CONFIG_SND_HDA_CODEC_ANALOG=m +CONFIG_SND_HDA_CODEC_SIGMATEL=m +CONFIG_SND_HDA_CODEC_VIA=m +CONFIG_SND_HDA_CODEC_HDMI=m +CONFIG_SND_HDA_CODEC_CIRRUS=m +CONFIG_SND_HDA_CODEC_CONEXANT=m +CONFIG_SND_HDA_CODEC_CA0110=m +CONFIG_SND_HDA_CODEC_CA0132=m +CONFIG_SND_HDA_CODEC_CA0132_DSP=y +CONFIG_SND_HDA_CODEC_CMEDIA=m +CONFIG_SND_HDA_CODEC_SI3054=m +CONFIG_SND_HDA_GENERIC=m +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 # CONFIG_SND_SPI is not set CONFIG_SND_USB=y CONFIG_SND_USB_AUDIO=m @@ -3206,8 +4100,17 @@ CONFIG_SND_USB_CAIAQ_INPUT=y CONFIG_SND_USB_6FIRE=m CONFIG_SND_USB_HIFACE=m CONFIG_SND_BCD2000=m +CONFIG_SND_FIREWIRE=y +CONFIG_SND_FIREWIRE_LIB=m +CONFIG_SND_DICE=m +CONFIG_SND_FIREWIRE_SPEAKERS=m +CONFIG_SND_ISIGHT=m +CONFIG_SND_SCS1X=m +CONFIG_SND_FIREWORKS=m +CONFIG_SND_BEBOB=m # CONFIG_SND_SOC is not set CONFIG_SOUND_PRIME=m +CONFIG_AC97_BUS=m # # HID support @@ -3333,6 +4236,7 @@ CONFIG_USB_DEFAULT_PERSIST=y # CONFIG_USB_OTG_BLACKLIST_HUB is not set # CONFIG_USB_OTG_FSM is not set CONFIG_USB_MON=m +CONFIG_USB_WUSB=m CONFIG_USB_WUSB_CBAF=m # CONFIG_USB_WUSB_CBAF_DEBUG is not set @@ -3345,6 +4249,8 @@ CONFIG_USB_XHCI_PLATFORM=m CONFIG_USB_EHCI_HCD=m # CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=m +CONFIG_USB_EHCI_HCD_SYNOPSYS=m CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -3354,12 +4260,16 @@ CONFIG_USB_FUSBH200_HCD=m CONFIG_USB_FOTG210_HCD=m CONFIG_USB_MAX3421_HCD=m CONFIG_USB_OHCI_HCD=m +CONFIG_USB_OHCI_HCD_PCI=m # CONFIG_USB_OHCI_HCD_SSB is not set CONFIG_USB_OHCI_HCD_PLATFORM=m +CONFIG_USB_UHCI_HCD=m CONFIG_USB_U132_HCD=m CONFIG_USB_SL811_HCD=m # CONFIG_USB_SL811_HCD_ISO is not set CONFIG_USB_R8A66597_HCD=m +CONFIG_USB_WHCI_HCD=m +CONFIG_USB_HWA_HCD=m # CONFIG_USB_HCD_BCMA is not set CONFIG_USB_HCD_SSB=m # CONFIG_USB_HCD_TEST_MODE is not set @@ -3408,6 +4318,7 @@ CONFIG_USB_DWC3_HOST=y # # Platform Glue Driver Support # +CONFIG_USB_DWC3_PCI=m # # Debugging features @@ -3416,6 +4327,7 @@ CONFIG_USB_DWC3_HOST=y CONFIG_USB_DWC2=y CONFIG_USB_DWC2_HOST=m CONFIG_USB_DWC2_PLATFORM=y +CONFIG_USB_DWC2_PCI=y # # Gadget mode requires USB Gadget support to be enabled @@ -3528,6 +4440,10 @@ CONFIG_NOP_USB_XCEIV=m # CONFIG_USB_ISP1301 is not set CONFIG_USB_ULPI=y # CONFIG_USB_GADGET is not set +CONFIG_UWB=m +CONFIG_UWB_HWA=m +CONFIG_UWB_WHCI=m +CONFIG_UWB_I1480U=m CONFIG_MMC=m # CONFIG_MMC_DEBUG is not set # CONFIG_MMC_CLKGATE is not set @@ -3546,14 +4462,20 @@ CONFIG_SDIO_UART=m # CONFIG_MMC_ARMMMCI=m CONFIG_MMC_SDHCI=m +CONFIG_MMC_SDHCI_PCI=m +CONFIG_MMC_RICOH_MMC=y CONFIG_MMC_SDHCI_PLTFM=m # CONFIG_MMC_SDHCI_OF_ARASAN is not set # CONFIG_MMC_SDHCI_PXAV3 is not set # CONFIG_MMC_SDHCI_PXAV2 is not set +CONFIG_MMC_TIFM_SD=m CONFIG_MMC_SPI=m +CONFIG_MMC_CB710=m +CONFIG_MMC_VIA_SDMMC=m CONFIG_MMC_VUB300=m CONFIG_MMC_USHC=m # CONFIG_MMC_USDHI6ROL0 is not set +CONFIG_MMC_REALTEK_PCI=m CONFIG_MMC_REALTEK_USB=m CONFIG_MEMSTICK=m # CONFIG_MEMSTICK_DEBUG is not set @@ -3568,6 +4490,10 @@ CONFIG_MS_BLOCK=m # # MemoryStick Host Controller Drivers # +CONFIG_MEMSTICK_TIFM_MS=m +CONFIG_MEMSTICK_JMICRON_38X=m +CONFIG_MEMSTICK_R592=m +CONFIG_MEMSTICK_REALTEK_PCI=m CONFIG_MEMSTICK_REALTEK_USB=m CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -3617,6 +4543,32 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=m # CONFIG_LEDS_TRIGGER_TRANSIENT is not set CONFIG_LEDS_TRIGGER_CAMERA=m # CONFIG_ACCESSIBILITY is not set +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_USER_MEM=y +CONFIG_INFINIBAND_ADDR_TRANS=y +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_QIB=m +CONFIG_INFINIBAND_AMSO1100=m +# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set +CONFIG_INFINIBAND_CXGB3=m +# CONFIG_INFINIBAND_CXGB3_DEBUG is not set +CONFIG_INFINIBAND_CXGB4=m +CONFIG_MLX4_INFINIBAND=m +CONFIG_MLX5_INFINIBAND=m +CONFIG_INFINIBAND_NES=m +# CONFIG_INFINIBAND_NES_DEBUG is not set +CONFIG_INFINIBAND_OCRDMA=m +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_CM=y +CONFIG_INFINIBAND_IPOIB_DEBUG=y +# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set +CONFIG_INFINIBAND_SRP=m +CONFIG_INFINIBAND_SRPT=m +CONFIG_INFINIBAND_ISER=m +CONFIG_INFINIBAND_ISERT=m CONFIG_RTC_LIB=y CONFIG_RTC_CLASS=y CONFIG_RTC_HCTOSYS=y @@ -3684,6 +4636,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +CONFIG_RTC_DRV_EFI=y # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set @@ -3714,23 +4667,40 @@ CONFIG_DMADEVICES=y # DMA Devices # # CONFIG_AMBA_PL08X is not set -# CONFIG_DW_DMAC_CORE is not set +CONFIG_DW_DMAC_CORE=m # CONFIG_DW_DMAC is not set +CONFIG_DW_DMAC_PCI=m +CONFIG_TIMB_DMA=m # CONFIG_PL330_DMA is not set # CONFIG_FSL_EDMA is not set +CONFIG_DMA_ENGINE=y CONFIG_DMA_OF=y + +# +# DMA Clients +# +CONFIG_ASYNC_TX_DMA=y +# CONFIG_DMATEST is not set CONFIG_AUXDISPLAY=y CONFIG_UIO=m +CONFIG_UIO_CIF=m CONFIG_UIO_PDRV_GENIRQ=m CONFIG_UIO_DMEM_GENIRQ=m +CONFIG_UIO_AEC=m +CONFIG_UIO_SERCOS3=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_UIO_NETX=m +CONFIG_UIO_MF624=m # CONFIG_VFIO_IOMMU_TYPE1 is not set CONFIG_VFIO=m +CONFIG_VFIO_PCI=m CONFIG_VIRT_DRIVERS=y CONFIG_VIRTIO=m # # Virtio drivers # +CONFIG_VIRTIO_PCI=m CONFIG_VIRTIO_BALLOON=m CONFIG_VIRTIO_MMIO=m # CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set @@ -3739,6 +4709,7 @@ CONFIG_VIRTIO_MMIO=m # Microsoft Hyper-V guest support # CONFIG_STAGING=y +CONFIG_ET131X=m CONFIG_USBIP_CORE=m CONFIG_USBIP_VHCI_HCD=m CONFIG_USBIP_HOST=m @@ -3751,6 +4722,7 @@ CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048 CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480 # CONFIG_COMEDI_MISC_DRIVERS is not set # CONFIG_COMEDI_ISA_DRIVERS is not set +# CONFIG_COMEDI_PCI_DRIVERS is not set CONFIG_COMEDI_USB_DRIVERS=y CONFIG_COMEDI_DT9812=m CONFIG_COMEDI_USBDUX=m @@ -3763,21 +4735,30 @@ CONFIG_PANEL=m CONFIG_PANEL_PARPORT=0 CONFIG_PANEL_PROFILE=5 # CONFIG_PANEL_CHANGE_MESSAGE is not set +CONFIG_RTL8192U=m CONFIG_RTLLIB=m CONFIG_RTLLIB_CRYPTO_CCMP=m CONFIG_RTLLIB_CRYPTO_TKIP=m CONFIG_RTLLIB_CRYPTO_WEP=m +CONFIG_RTL8192E=m CONFIG_R8712U=m CONFIG_R8188EU=m CONFIG_88EU_AP_MODE=y CONFIG_88EU_P2P=y +CONFIG_R8192EE=m CONFIG_R8723AU=m CONFIG_8723AU_AP_MODE=y CONFIG_8723AU_BT_COEXIST=y +CONFIG_R8821AE=m +CONFIG_RTS5208=m +# CONFIG_RTS5208_DEBUG is not set CONFIG_TRANZPORT=m +CONFIG_IDE_PHISON=m # CONFIG_LINE6_USB is not set CONFIG_USB_SERIAL_QUATECH2=m +CONFIG_VT6655=m CONFIG_VT6656=m +CONFIG_DX_SEP=m # # IIO staging drivers @@ -3874,6 +4855,10 @@ CONFIG_IIO_PERIODIC_RTC_TRIGGER=m CONFIG_IIO_SIMPLE_DUMMY=m # CONFIG_IIO_SIMPLE_DUMMY_EVENTS is not set # CONFIG_IIO_SIMPLE_DUMMY_BUFFER is not set +CONFIG_CRYSTALHD=m +CONFIG_CXT1E1=m +CONFIG_SBE_PMCC4_NCOMM=y +CONFIG_FB_XGI=m # CONFIG_USB_ENESTORAGE is not set # CONFIG_BCM_WIMAX is not set CONFIG_FT1000=m @@ -3899,11 +4884,16 @@ CONFIG_SPEAKUP_SYNTH_DUMMY=m CONFIG_STAGING_MEDIA=y # CONFIG_DVB_AS102 is not set # CONFIG_I2C_BCM2048 is not set +CONFIG_DVB_CXD2099=m +CONFIG_VIDEO_DT3155=m +CONFIG_DT3155_CCIR=y +CONFIG_DT3155_STREAMING=y # CONFIG_VIDEO_GO7007 is not set CONFIG_USB_MSI3101=m CONFIG_MEDIA_TUNER_MSI001=m # CONFIG_VIDEO_TCM825X is not set CONFIG_USB_SN9C102=m +CONFIG_SOLO6X10=m # CONFIG_LIRC_STAGING is not set # @@ -3913,19 +4903,27 @@ CONFIG_USB_SN9C102=m CONFIG_USB_WPAN_HCD=m # CONFIG_WIMAX_GDM72XX is not set CONFIG_LTE_GDM724X=m +CONFIG_NET_VENDOR_SILICOM=y +CONFIG_SBYPASS=m +CONFIG_BPCTL=m CONFIG_CED1401=m CONFIG_DGRP=m +CONFIG_FIREWIRE_SERIAL=m +CONFIG_FWTTY_MAX_TOTAL_PORTS=64 +CONFIG_FWTTY_MAX_CARD_PORTS=32 # CONFIG_MTD_SPINAND_MT29F is not set CONFIG_LUSTRE_FS=m CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER=8192 # CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK is not set CONFIG_LUSTRE_TRANSLATE_ERRNOS=y -CONFIG_LUSTRE_LLITE_LLOOP=m CONFIG_LNET=m CONFIG_LNET_MAX_PAYLOAD=1048576 CONFIG_LNET_SELFTEST=m +CONFIG_LNET_XPRT_IB=m CONFIG_XILLYBUS=m +CONFIG_XILLYBUS_PCIE=m CONFIG_XILLYBUS_OF=m +CONFIG_DGNC=m CONFIG_DGAP=m # CONFIG_GS_FPGABOOT is not set @@ -4137,6 +5135,7 @@ CONFIG_HID_SENSOR_PRESS=m # # CONFIG_MLX90614 is not set # CONFIG_TMP006 is not set +# CONFIG_VME_BUS is not set CONFIG_PWM=y CONFIG_PWM_SYSFS=y # CONFIG_PWM_FSL_FTM is not set @@ -4398,6 +5397,8 @@ CONFIG_SUNRPC_BACKCHANNEL=y CONFIG_SUNRPC_SWAP=y CONFIG_RPCSEC_GSS_KRB5=m CONFIG_SUNRPC_DEBUG=y +CONFIG_SUNRPC_XPRT_RDMA_CLIENT=m +CONFIG_SUNRPC_XPRT_RDMA_SERVER=m CONFIG_CEPH_FS=m CONFIG_CEPH_FSCACHE=y # CONFIG_CEPH_FS_POSIX_ACL is not set @@ -4490,7 +5491,7 @@ CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y CONFIG_VIRTUALIZATION=y CONFIG_KVM=y CONFIG_KVM_ARM_HOST=y -CONFIG_KVM_ARM_MAX_VCPUS=4 +CONFIG_KVM_ARM_MAX_VCPUS=8 CONFIG_KVM_ARM_VGIC=y CONFIG_KVM_ARM_TIMER=y @@ -4894,7 +5895,9 @@ CONFIG_TEXTSEARCH_FSM=m CONFIG_BTREE=y CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_DMA=y +CONFIG_CHECK_SIGNATURE=y CONFIG_CPU_RMAP=y CONFIG_DQL=y CONFIG_NLATTR=y diff --git a/config/armv6hl/default b/config/armv6hl/default index e08a52e..10051e8 100644 --- a/config/armv6hl/default +++ b/config/armv6hl/default @@ -1928,6 +1928,7 @@ CONFIG_NET_DSA_MV88E6131=m CONFIG_NET_DSA_MV88E6123_61_65=m CONFIG_ETHERNET=y # CONFIG_ALTERA_TSE is not set +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_CADENCE=y @@ -2925,6 +2926,7 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO=y CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_VEXPRESS=y +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -4116,6 +4118,7 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_FSL_MPH_DR_OF=m CONFIG_USB_EHCI_MXC=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set # CONFIG_USB_CNS3XXX_EHCI is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m diff --git a/config/armv7hl/default b/config/armv7hl/default index 9576148..4bf041f 100644 --- a/config/armv7hl/default +++ b/config/armv7hl/default @@ -2367,6 +2367,7 @@ CONFIG_NET_VENDOR_AMD=y # CONFIG_AMD8111_ETH is not set # CONFIG_PCNET32 is not set # CONFIG_AMD_XGBE is not set +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3701,6 +3702,7 @@ CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_SUN6I=y CONFIG_POWER_RESET_VEXPRESS=y CONFIG_POWER_RESET_KEYSTONE=y +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -5353,6 +5355,7 @@ CONFIG_USB_EHCI_MXC=m CONFIG_USB_EHCI_HCD_OMAP=m CONFIG_USB_EHCI_HCD_ORION=m CONFIG_USB_EHCI_HCD_SPEAR=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_MSM=m CONFIG_USB_EHCI_TEGRA=m CONFIG_USB_EHCI_EXYNOS=m diff --git a/config/armv7hl/lpae b/config/armv7hl/lpae index 3b6d27f..2ec68ec 100644 --- a/config/armv7hl/lpae +++ b/config/armv7hl/lpae @@ -2237,6 +2237,7 @@ CONFIG_NET_VENDOR_AMD=y # CONFIG_AMD8111_ETH is not set # CONFIG_PCNET32 is not set # CONFIG_AMD_XGBE is not set +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3480,6 +3481,7 @@ CONFIG_POWER_RESET_RESTART=y CONFIG_POWER_RESET_SUN6I=y CONFIG_POWER_RESET_VEXPRESS=y CONFIG_POWER_RESET_KEYSTONE=y +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -5034,6 +5036,7 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m CONFIG_USB_EHCI_HCD_OMAP=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_MSM=m CONFIG_USB_EHCI_TEGRA=m CONFIG_USB_EHCI_EXYNOS=m diff --git a/config/i386/debug b/config/i386/debug index 1e43353..3446c3b 100644 --- a/config/i386/debug +++ b/config/i386/debug @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -2395,6 +2395,7 @@ CONFIG_LANCE=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m CONFIG_NI65=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5191,6 +5192,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5577,6 +5579,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/i386/default b/config/i386/default index 6c73d27..a7eac98 100644 --- a/config/i386/default +++ b/config/i386/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -2396,6 +2396,7 @@ CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m CONFIG_NI65=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3720,6 +3721,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=m CONFIG_HWMON_VID=m @@ -5229,6 +5231,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5619,6 +5622,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/i386/desktop b/config/i386/desktop index 05f3246..71c1123 100644 --- a/config/i386/desktop +++ b/config/i386/desktop @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -2346,6 +2346,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5071,6 +5072,7 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=y +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5458,6 +5460,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/i386/ec2 b/config/i386/ec2 index bfee359..1cf965d 100644 --- a/config/i386/ec2 +++ b/config/i386/ec2 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y diff --git a/config/i386/pae b/config/i386/pae index 7c69700..2d56cf6 100644 --- a/config/i386/pae +++ b/config/i386/pae @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -2347,6 +2347,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5079,6 +5080,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5467,6 +5469,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/i386/xen b/config/i386/xen index 9fe133e..9dc83ef 100644 --- a/config/i386/xen +++ b/config/i386/xen @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/i386 3.16.3 Kernel Configuration +# Linux/i386 3.16.6 Kernel Configuration # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -453,9 +453,6 @@ CONFIG_HZ=250 CONFIG_SCHED_HRTICK=y CONFIG_KEXEC=y CONFIG_PHYSICAL_START=0x2000 -CONFIG_RELOCATABLE=y -# CONFIG_RANDOMIZE_BASE is not set -CONFIG_X86_NEED_RELOCS=y CONFIG_PHYSICAL_ALIGN=0x2000 CONFIG_XEN_BZIMAGE=y CONFIG_HOTPLUG_CPU=y @@ -2175,6 +2172,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -4849,6 +4847,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5234,7 +5233,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set -CONFIG_RTC_DRV_EFI=y +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/ppc/default b/config/ppc/default index 253c9b3..1868e70 100644 --- a/config/ppc/default +++ b/config/ppc/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/powerpc 3.16.3 Kernel Configuration +# Linux/powerpc 3.16.6 Kernel Configuration # # CONFIG_PPC64 is not set @@ -1835,6 +1835,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_APPLE=y CONFIG_MACE=m # CONFIG_MACE_AAUI_PORT is not set @@ -3014,6 +3015,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y # CONFIG_HWMON_VID is not set @@ -4333,6 +4335,7 @@ CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m # CONFIG_XPS_USB_HCD_XILINX is not set +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PPC_OF=y CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m diff --git a/config/ppc64/debug b/config/ppc64/debug index f206021..68d1337 100644 --- a/config/ppc64/debug +++ b/config/ppc64/debug @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/powerpc 3.16.3 Kernel Configuration +# Linux/powerpc 3.16.6 Kernel Configuration # CONFIG_PPC64=y @@ -1999,6 +1999,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3166,6 +3167,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -4469,6 +4471,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PPC_OF=y CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m @@ -4989,7 +4992,6 @@ CONFIG_LUSTRE_FS=m CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER=8192 # CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK is not set CONFIG_LUSTRE_TRANSLATE_ERRNOS=y -CONFIG_LUSTRE_LLITE_LLOOP=m CONFIG_LNET=m CONFIG_LNET_MAX_PAYLOAD=1048576 # CONFIG_LNET_SELFTEST is not set diff --git a/config/ppc64/default b/config/ppc64/default index 1f9b2d8..5a98e8a 100644 --- a/config/ppc64/default +++ b/config/ppc64/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/powerpc 3.16.3 Kernel Configuration +# Linux/powerpc 3.16.6 Kernel Configuration # CONFIG_PPC64=y @@ -1989,6 +1989,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3156,6 +3157,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -4459,6 +4461,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PPC_OF=y CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m @@ -4979,7 +4982,6 @@ CONFIG_LUSTRE_FS=m CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER=8192 # CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK is not set CONFIG_LUSTRE_TRANSLATE_ERRNOS=y -CONFIG_LUSTRE_LLITE_LLOOP=m CONFIG_LNET=m CONFIG_LNET_MAX_PAYLOAD=1048576 # CONFIG_LNET_SELFTEST is not set diff --git a/config/ppc64le/debug b/config/ppc64le/debug index d10427e..031625b 100644 --- a/config/ppc64le/debug +++ b/config/ppc64le/debug @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/powerpc 3.16.3 Kernel Configuration +# Linux/powerpc 3.16.6 Kernel Configuration # CONFIG_PPC64=y @@ -1956,6 +1956,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3121,6 +3122,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -4419,6 +4421,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PPC_OF=y CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m @@ -4938,7 +4941,6 @@ CONFIG_LUSTRE_FS=m CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER=8192 # CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK is not set CONFIG_LUSTRE_TRANSLATE_ERRNOS=y -CONFIG_LUSTRE_LLITE_LLOOP=m CONFIG_LNET=m CONFIG_LNET_MAX_PAYLOAD=1048576 # CONFIG_LNET_SELFTEST is not set diff --git a/config/ppc64le/default b/config/ppc64le/default index c9c0707..5743ca8 100644 --- a/config/ppc64le/default +++ b/config/ppc64le/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/powerpc 3.16.3 Kernel Configuration +# Linux/powerpc 3.16.6 Kernel Configuration # CONFIG_PPC64=y @@ -1946,6 +1946,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_AMD_XGBE=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_ARC_EMAC=m CONFIG_NET_VENDOR_ATHEROS=y @@ -3111,6 +3112,7 @@ CONFIG_CHARGER_BQ24735=m CONFIG_CHARGER_SMB347=m CONFIG_POWER_RESET=y # CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_SYSCON is not set CONFIG_POWER_AVS=y CONFIG_HWMON=y CONFIG_HWMON_VID=m @@ -4409,6 +4411,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PPC_OF=y CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m @@ -4928,7 +4931,6 @@ CONFIG_LUSTRE_FS=m CONFIG_LUSTRE_OBD_MAX_IOCTL_BUFFER=8192 # CONFIG_LUSTRE_DEBUG_EXPENSIVE_CHECK is not set CONFIG_LUSTRE_TRANSLATE_ERRNOS=y -CONFIG_LUSTRE_LLITE_LLOOP=m CONFIG_LNET=m CONFIG_LNET_MAX_PAYLOAD=1048576 # CONFIG_LNET_SELFTEST is not set diff --git a/config/s390x/default b/config/s390x/default index 7a6f2ff..1d4c22a 100644 --- a/config/s390x/default +++ b/config/s390x/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/s390 3.16.3 Kernel Configuration +# Linux/s390 3.16.6 Kernel Configuration # CONFIG_MMU=y CONFIG_ZONE_DMA=y @@ -1375,6 +1375,7 @@ CONFIG_ETHERNET=y # CONFIG_NET_VENDOR_ALTEON is not set CONFIG_ALTERA_TSE=m # CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y # CONFIG_NET_VENDOR_ATHEROS is not set # CONFIG_NET_VENDOR_BROADCOM is not set diff --git a/config/x86_64/debug b/config/x86_64/debug index c0822d1..7a01d2c 100644 --- a/config/x86_64/debug +++ b/config/x86_64/debug @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.16.3 Kernel Configuration +# Linux/x86_64 3.16.6 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -2319,6 +2319,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5018,6 +5019,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5404,6 +5406,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/x86_64/default b/config/x86_64/default index 3b052f8..b51a561 100644 --- a/config/x86_64/default +++ b/config/x86_64/default @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.16.3 Kernel Configuration +# Linux/x86_64 3.16.6 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -2309,6 +2309,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5008,6 +5009,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5394,6 +5396,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/x86_64/desktop b/config/x86_64/desktop index a9b57d0..b8bf35c 100644 --- a/config/x86_64/desktop +++ b/config/x86_64/desktop @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.16.3 Kernel Configuration +# Linux/x86_64 3.16.6 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -2308,6 +2308,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -5000,6 +5001,7 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=y +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5385,6 +5387,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/config/x86_64/ec2 b/config/x86_64/ec2 index d6048bf..1b6237e 100644 --- a/config/x86_64/ec2 +++ b/config/x86_64/ec2 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.16.3 Kernel Configuration +# Linux/x86_64 3.16.6 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -444,7 +444,6 @@ CONFIG_COMPAT=y CONFIG_COMPAT_FOR_U64_ALIGNMENT=y CONFIG_SYSVIPC_COMPAT=y CONFIG_KEYS_COMPAT=y -CONFIG_X86_DEV_DMA_OPS=y CONFIG_NET=y # diff --git a/config/x86_64/xen b/config/x86_64/xen index ddb186d..c89e412 100644 --- a/config/x86_64/xen +++ b/config/x86_64/xen @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.16.3 Kernel Configuration +# Linux/x86_64 3.16.6 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -439,8 +439,6 @@ CONFIG_HZ=250 CONFIG_SCHED_HRTICK=y CONFIG_KEXEC=y CONFIG_PHYSICAL_START=0x4000 -CONFIG_RELOCATABLE=y -# CONFIG_RANDOMIZE_BASE is not set CONFIG_PHYSICAL_ALIGN=0x4000 CONFIG_XEN_BZIMAGE=y CONFIG_HOTPLUG_CPU=y @@ -606,7 +604,6 @@ CONFIG_COMPAT=y CONFIG_COMPAT_FOR_U64_ALIGNMENT=y CONFIG_SYSVIPC_COMPAT=y CONFIG_KEYS_COMPAT=y -CONFIG_X86_DEV_DMA_OPS=y CONFIG_IOSF_MBI=m CONFIG_NET=y CONFIG_COMPAT_NETLINK_MESSAGES=y @@ -2143,6 +2140,7 @@ CONFIG_NET_VENDOR_AMD=y CONFIG_AMD8111_ETH=m CONFIG_PCNET32=m CONFIG_PCMCIA_NMCLAN=m +# CONFIG_NET_XGENE is not set CONFIG_NET_VENDOR_ARC=y CONFIG_NET_VENDOR_ATHEROS=y CONFIG_ATL2=m @@ -4783,6 +4781,7 @@ CONFIG_USB_EHCI_HCD=m CONFIG_USB_EHCI_ROOT_HUB_TT=y CONFIG_USB_EHCI_TT_NEWSCHED=y CONFIG_USB_EHCI_PCI=m +# CONFIG_USB_EHCI_HCD_SYNOPSYS is not set CONFIG_USB_EHCI_HCD_PLATFORM=m CONFIG_USB_OXU210HP_HCD=m CONFIG_USB_ISP116X_HCD=m @@ -5162,7 +5161,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_DS1742 is not set -CONFIG_RTC_DRV_EFI=y +# CONFIG_RTC_DRV_EFI is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T35 is not set diff --git a/patches.arch/arm64-0001-usb-Add-support-for-Synopsis-H20AHB-EHCI-host-contro.patch b/patches.arch/arm64-0001-usb-Add-support-for-Synopsis-H20AHB-EHCI-host-contro.patch new file mode 100644 index 0000000..1cbdc84 --- /dev/null +++ b/patches.arch/arm64-0001-usb-Add-support-for-Synopsis-H20AHB-EHCI-host-contro.patch @@ -0,0 +1,399 @@ +From 0f67c85fd55706270add227d48c583d34d6ef28f Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Tue, 4 Mar 2014 11:03:13 +0000 +Subject: [PATCH 01/38] usb: Add support for Synopsis H20AHB EHCI host + controller. +Git-commit: 0f67c85fd55706270add227d48c583d34d6ef28f +Patch-mainline: No +References: bnc#902632 + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/usb/host/Kconfig | 7 + + drivers/usb/host/Makefile | 1 + + drivers/usb/host/ehci-h20ahb.c | 341 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 349 insertions(+) + create mode 100644 drivers/usb/host/ehci-h20ahb.c + +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index 03314f8..feab3d5 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -166,6 +166,13 @@ config USB_EHCI_HCD_SPEAR + Enables support for the on-chip EHCI controller on + ST SPEAr chips. + ++config USB_EHCI_HCD_SYNOPSYS ++ tristate "Support for Synopsys Host-AHB USB 2.0 controller" ++ depends on USB_EHCI_HCD ++ ---help--- ++ Enable support for onchip USB controllers based on DesignWare USB 2.0 ++ Host-AHB Controller IP from Synopsys. ++ + config USB_EHCI_HCD_AT91 + tristate "Support for Atmel on-chip EHCI USB controller" + depends on USB_EHCI_HCD && ARCH_AT91 +diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile +index af89a90..76efe9e 100644 +--- a/drivers/usb/host/Makefile ++++ b/drivers/usb/host/Makefile +@@ -35,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o + obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o + obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o + obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o ++obj-$(CONFIG_USB_EHCI_HCD_SYNOPSYS) += ehci-h20ahb.o + obj-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o + obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o + obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o +diff --git a/drivers/usb/host/ehci-h20ahb.c b/drivers/usb/host/ehci-h20ahb.c +new file mode 100644 +index 0000000..3ee3c7a +--- /dev/null ++++ b/drivers/usb/host/ehci-h20ahb.c +@@ -0,0 +1,341 @@ ++/* ++ * Copyright (C) 2007-2013 Texas Instruments, Inc. ++ * Author: Vikram Pandita <vikram.pandita@ti.com> ++ * Author: Anand Gadiyar <gadiyar@ti.com> ++ * Author: Keshava Munegowda <keshava_mgowda@ti.com> ++ * Author: Roger Quadros <rogerq@ti.com> ++ * ++ * Copyright (C) 2009 Nokia Corporation ++ * Contact: Felipe Balbi <felipe.balbi@nokia.com> ++ * ++ * Based on ehci-omap.c - driver for USBHOST on OMAP3/4 processors ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/io.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/usb/ulpi.h> ++#include <linux/pm_runtime.h> ++#include <linux/gpio.h> ++#include <linux/clk.h> ++#include <linux/usb.h> ++#include <linux/usb/hcd.h> ++#include <linux/of.h> ++#include <linux/dma-mapping.h> ++ ++#include "ehci.h" ++ ++#define H20AHB_HS_USB_PORTS 1 ++ ++/* EHCI Synopsys-specific Register Set */ ++#define EHCI_INSNREG04 (0xA0) ++#define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5) ++#define EHCI_INSNREG05_ULPI (0xA4) ++#define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31 ++#define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24 ++#define EHCI_INSNREG05_ULPI_OPSEL_SHIFT 22 ++#define EHCI_INSNREG05_ULPI_REGADD_SHIFT 16 ++#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 ++#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 ++ ++#define DRIVER_DESC "H20AHB-EHCI Host Controller driver" ++ ++static const char hcd_name[] = "ehci-h20ahb"; ++ ++/*-------------------------------------------------------------------------*/ ++ ++struct h20ahb_hcd { ++ struct usb_phy *phy[H20AHB_HS_USB_PORTS]; /* one PHY for each port */ ++ int nports; ++}; ++ ++static inline void ehci_write(void __iomem *base, u32 reg, u32 val) ++{ ++ __raw_writel(val, base + reg); ++} ++ ++static inline u32 ehci_read(void __iomem *base, u32 reg) ++{ ++ return __raw_readl(base + reg); ++} ++ ++/* configure so an HC device and id are always provided */ ++/* always called with process context; sleeping is OK */ ++ ++static struct hc_driver __read_mostly ehci_h20ahb_hc_driver; ++ ++static const struct ehci_driver_overrides ehci_h20ahb_overrides __initdata = { ++ .extra_priv_size = sizeof(struct h20ahb_hcd), ++}; ++ ++static int ehci_h20ahb_phy_read(struct usb_phy *x, u32 reg) ++{ ++ u32 val = (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) | ++ (1 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) | ++ (3 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) | ++ (reg << EHCI_INSNREG05_ULPI_REGADD_SHIFT); ++ ehci_write(x->io_priv, 0, val); ++ while ((val = ehci_read(x->io_priv, 0)) & ++ (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT)); ++ return val & 0xff; ++} ++ ++static int ehci_h20ahb_phy_write(struct usb_phy *x, u32 val, u32 reg) ++{ ++ u32 v = (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) | ++ (1 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) | ++ (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) | ++ (reg << EHCI_INSNREG05_ULPI_REGADD_SHIFT) | ++ (val & 0xff); ++ ehci_write(x->io_priv, 0, v); ++ while ((v = ehci_read(x->io_priv, 0)) & ++ (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT)); ++ return 0; ++} ++ ++static struct usb_phy_io_ops ehci_h20ahb_phy_io_ops = { ++ .read = ehci_h20ahb_phy_read, ++ .write = ehci_h20ahb_phy_write, ++}; ++ ++ ++/** ++ * ehci_hcd_h20ahb_probe - initialize Synopsis-based HCDs ++ * ++ * Allocates basic resources for this USB host controller, and ++ * then invokes the start() method for the HCD associated with it ++ * through the hotplug entry's driver_data. ++ */ ++static int ehci_hcd_h20ahb_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ struct usb_hcd *hcd; ++ void __iomem *regs; ++ int ret; ++ int irq; ++ int i; ++ struct h20ahb_hcd *h20ahb; ++ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ /* if (!dev->parent) { ++ dev_err(dev, "Missing parent device\n"); ++ return -ENODEV; ++ }*/ ++ ++ /* For DT boot, get platform data from parent. i.e. usbhshost */ ++ /*if (dev->of_node) { ++ pdata = dev_get_platdata(dev->parent); ++ dev->platform_data = pdata; ++ } ++ ++ if (!pdata) { ++ dev_err(dev, "Missing platform data\n"); ++ return -ENODEV; ++ }*/ ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(dev, "EHCI irq failed\n"); ++ return -ENODEV; ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ /* ++ * Right now device-tree probed devices don't get dma_mask set. ++ * Since shared usb code relies on it, set it here for now. ++ * Once we have dma capability bindings this can go away. ++ */ ++ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ if (ret) ++ return ret; ++ ++ ret = -ENODEV; ++ hcd = usb_create_hcd(&ehci_h20ahb_hc_driver, dev, ++ dev_name(dev)); ++ if (!hcd) { ++ dev_err(dev, "Failed to create HCD\n"); ++ return -ENOMEM; ++ } ++ ++ hcd->rsrc_start = res->start; ++ hcd->rsrc_len = resource_size(res); ++ hcd->regs = regs; ++ hcd_to_ehci(hcd)->caps = regs; ++ ++ h20ahb = (struct h20ahb_hcd *)hcd_to_ehci(hcd)->priv; ++ h20ahb->nports = 1; ++ ++ platform_set_drvdata(pdev, hcd); ++ ++ /* get the PHY devices if needed */ ++ for (i = 0 ; i < h20ahb->nports ; i++) { ++ struct usb_phy *phy; ++ ++ /* get the PHY device */ ++#if 0 ++ if (dev->of_node) ++ phy = devm_usb_get_phy_by_phandle(dev, "phys", i); ++ else ++ phy = devm_usb_get_phy_dev(dev, i); ++#endif ++ phy = otg_ulpi_create(&ehci_h20ahb_phy_io_ops, 0); ++ if (IS_ERR(phy)) { ++ ret = PTR_ERR(phy); ++ dev_err(dev, "Can't get PHY device for port %d: %d\n", ++ i, ret); ++ goto err_phy; ++ } ++ phy->dev = dev; ++ usb_add_phy_dev(phy); ++ ++ h20ahb->phy[i] = phy; ++ phy->io_priv = hcd->regs + EHCI_INSNREG05_ULPI; ++ ++#if 0 ++ usb_phy_init(h20ahb->phy[i]); ++ /* bring PHY out of suspend */ ++ usb_phy_set_suspend(h20ahb->phy[i], 0); ++#endif ++ } ++ ++ /* make the first port's phy the one used by hcd as well */ ++ hcd->phy = h20ahb->phy[0]; ++ ++ pm_runtime_enable(dev); ++ pm_runtime_get_sync(dev); ++ ++ /* ++ * An undocumented "feature" in the H20AHB EHCI controller, ++ * causes suspended ports to be taken out of suspend when ++ * the USBCMD.Run/Stop bit is cleared (for example when ++ * we do ehci_bus_suspend). ++ * This breaks suspend-resume if the root-hub is allowed ++ * to suspend. Writing 1 to this undocumented register bit ++ * disables this feature and restores normal behavior. ++ */ ++ ehci_write(regs, EHCI_INSNREG04, ++ EHCI_INSNREG04_DISABLE_UNSUSPEND); ++ ++ ret = usb_add_hcd(hcd, irq, IRQF_SHARED); ++ if (ret) { ++ dev_err(dev, "failed to add hcd with err %d\n", ret); ++ goto err_pm_runtime; ++ } ++ device_wakeup_enable(hcd->self.controller); ++ ++ /* ++ * Bring PHYs out of reset for non PHY modes. ++ * Even though HSIC mode is a PHY-less mode, the reset ++ * line exists between the chips and can be modelled ++ * as a PHY device for reset control. ++ */ ++ for (i = 0; i < h20ahb->nports; i++) { ++ usb_phy_init(h20ahb->phy[i]); ++ /* bring PHY out of suspend */ ++ usb_phy_set_suspend(h20ahb->phy[i], 0); ++ } ++ ++ return 0; ++ ++err_pm_runtime: ++ pm_runtime_put_sync(dev); ++ ++err_phy: ++ for (i = 0; i < h20ahb->nports; i++) { ++ if (h20ahb->phy[i]) ++ usb_phy_shutdown(h20ahb->phy[i]); ++ } ++ ++ usb_put_hcd(hcd); ++ ++ return ret; ++} ++ ++ ++/** ++ * ehci_hcd_h20ahb_remove - shutdown processing for EHCI HCDs ++ * @pdev: USB Host Controller being removed ++ * ++ * Reverses the effect of usb_ehci_hcd_h20ahb_probe(), first invoking ++ * the HCD's stop() method. It is always called from a thread ++ * context, normally "rmmod", "apmd", or something similar. ++ */ ++static int ehci_hcd_h20ahb_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct usb_hcd *hcd = dev_get_drvdata(dev); ++ struct h20ahb_hcd *h20ahb = (struct h20ahb_hcd *)hcd_to_ehci(hcd)->priv; ++ int i; ++ ++ usb_remove_hcd(hcd); ++ ++ for (i = 0; i < h20ahb->nports; i++) { ++ if (h20ahb->phy[i]) ++ usb_phy_shutdown(h20ahb->phy[i]); ++ } ++ ++ usb_put_hcd(hcd); ++ pm_runtime_put_sync(dev); ++ pm_runtime_disable(dev); ++ ++ return 0; ++} ++ ++static const struct of_device_id h20ahb_ehci_dt_ids[] = { ++ { .compatible = "snps,ehci-h20ahb" }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(of, h20ahb_ehci_dt_ids); ++ ++static struct platform_driver ehci_hcd_h20ahb_driver = { ++ .probe = ehci_hcd_h20ahb_probe, ++ .remove = ehci_hcd_h20ahb_remove, ++ .shutdown = usb_hcd_platform_shutdown, ++ /*.suspend = ehci_hcd_h20ahb_suspend, */ ++ /*.resume = ehci_hcd_h20ahb_resume, */ ++ .driver = { ++ .name = hcd_name, ++ .of_match_table = h20ahb_ehci_dt_ids, ++ } ++}; ++ ++/*-------------------------------------------------------------------------*/ ++ ++static int __init ehci_h20ahb_init(void) ++{ ++ if (usb_disabled()) ++ return -ENODEV; ++ ++ pr_info("%s: " DRIVER_DESC "\n", hcd_name); ++ ++ ehci_init_driver(&ehci_h20ahb_hc_driver, &ehci_h20ahb_overrides); ++ return platform_driver_register(&ehci_hcd_h20ahb_driver); ++} ++module_init(ehci_h20ahb_init); ++ ++static void __exit ehci_h20ahb_cleanup(void) ++{ ++ platform_driver_unregister(&ehci_hcd_h20ahb_driver); ++} ++module_exit(ehci_h20ahb_cleanup); ++ ++MODULE_ALIAS("platform:ehci-h20ahb"); ++MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL"); +-- +2.1.0 + diff --git a/patches.arch/arm64-0002-usb-fix-hcd-h20ahb-driver-depends.patch b/patches.arch/arm64-0002-usb-fix-hcd-h20ahb-driver-depends.patch new file mode 100644 index 0000000..d319c28 --- /dev/null +++ b/patches.arch/arm64-0002-usb-fix-hcd-h20ahb-driver-depends.patch @@ -0,0 +1,38 @@ +From 9576f22c421afa69a06780e72690f2bcf6e6a681 Mon Sep 17 00:00:00 2001 +From: Alex Shi <alex.shi@linaro.org> +Date: Thu, 5 Jun 2014 07:58:06 +0100 +Subject: [PATCH 02/38] usb: fix hcd h20ahb driver depends +Git-commit: 9576f22c421afa69a06780e72690f2bcf6e6a681 +Patch-mainline: No +References: bnc#902632 + +USB_EHCI_HCD_SYNOPSYS is not only dependent on USB_EHCI_HCD, but +also on USB_PHY. Otherwise kernel build has the following error: + + LD init/built-in.o +Drivers/built-in.o: In function `ehci_hcd_h20ahb_probe': +:(.text+0xb9bb4): undefined reference to `usb_add_phy_dev' + +Signed-off-by: Alex Shi <alex.shi@linaro.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/usb/host/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index feab3d5..e784898 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -168,7 +168,7 @@ config USB_EHCI_HCD_SPEAR + + config USB_EHCI_HCD_SYNOPSYS + tristate "Support for Synopsys Host-AHB USB 2.0 controller" +- depends on USB_EHCI_HCD ++ depends on USB_EHCI_HCD && USB_PHY + ---help--- + Enable support for onchip USB controllers based on DesignWare USB 2.0 + Host-AHB Controller IP from Synopsys. +-- +2.1.0 + diff --git a/patches.arch/arm64-0003-cpufreq-arm_big_little-fix-module-license-spec.patch b/patches.arch/arm64-0003-cpufreq-arm_big_little-fix-module-license-spec.patch new file mode 100644 index 0000000..042435f --- /dev/null +++ b/patches.arch/arm64-0003-cpufreq-arm_big_little-fix-module-license-spec.patch @@ -0,0 +1,48 @@ +From 100ee73c5cd8a907ea0b67f7faf966abe2ac11bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de> +Date: Thu, 31 Jul 2014 09:36:56 +0200 +Subject: [PATCH 03/38] cpufreq: arm_big_little: fix module license spec +Mime-version: 1.0 +Content-type: text/plain; charset=UTF-8 +Content-transfer-encoding: 8bit +Git-commit: 39c8bbaf67b157017929703a5eea7e83525b147c +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +Having no license specification in a module taints the kernel during load +With: + + arm_big_little: module license 'unspecified' taints kernel. + +and also the linker doesn't allow it to make use of GPL-exported symbols +which in this case also results in errors like: + + arm_big_little: Unknown symbol cpufreq_register_driver (err 0) + +. The header of the driver specifies a GPL v2 license, so note that +accordingly. While at it also add a description and an author and fix +the license in a companion file to explicit v2. + +Reported-by: Andreas Schwab <schwab@suse.de> +Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/cpufreq/arm_big_little.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c +index 1f4d4e3..ac20a3d 100644 +--- a/drivers/cpufreq/arm_big_little.c ++++ b/drivers/cpufreq/arm_big_little.c +@@ -30,6 +30,7 @@ + #include <linux/slab.h> + #include <linux/topology.h> + #include <linux/types.h> ++#include <linux/module.h> + #include <asm/bL_switcher.h> + + #include "arm_big_little.h" +-- +2.1.0 + diff --git a/patches.arch/arm64-0004-ahci-Check-and-set-64-bit-DMA-mask-for-platform-AHCI.patch b/patches.arch/arm64-0004-ahci-Check-and-set-64-bit-DMA-mask-for-platform-AHCI.patch new file mode 100644 index 0000000..9c2dd5d --- /dev/null +++ b/patches.arch/arm64-0004-ahci-Check-and-set-64-bit-DMA-mask-for-platform-AHCI.patch @@ -0,0 +1,52 @@ +From 17a8eed8a0830f5ba3143e495a7172219b5bb121 Mon Sep 17 00:00:00 2001 +From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Date: Thu, 12 Jun 2014 12:40:23 -0500 +Subject: [PATCH 04/38] ahci: Check and set 64-bit DMA mask for platform AHCI + driver +Git-commit: cc7a9e27562cd78a1dc885504086fab24addce40 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +The current platform AHCI driver does not set the dma_mask correctly +for 64-bit DMA capable AHCI controller. This patch checks the AHCI +capability bit and set the dma_mask and coherent_dma_mask accordingly. + +Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> +Reviewed-by: Hans de Goede <hdegoede@redhat.com> +Tested-by: Hans de Goede <hdegoede@redhat.com> +Tested-by: Suman Tripathi <stripathi@apm.com> +Signed-off-by: Tejun Heo <tj@kernel.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/ata/libahci_platform.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c +index b007758..28840a2 100644 +--- a/drivers/ata/libahci_platform.c ++++ b/drivers/ata/libahci_platform.c +@@ -369,6 +369,19 @@ int ahci_platform_init_host(struct platform_device *pdev, + ap->ops = &ata_dummy_port_ops; + } + ++ if (hpriv->cap & HOST_CAP_64) { ++ rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (rc) { ++ rc = dma_coerce_mask_and_coherent(dev, ++ DMA_BIT_MASK(32)); ++ if (rc) { ++ dev_err(dev, "Failed to enable 64-bit DMA.\n"); ++ return rc; ++ } ++ dev_warn(dev, "Enable 32-bit DMA instead of 64-bit.\n"); ++ } ++ } ++ + rc = ahci_reset_controller(host); + if (rc) + return rc; +-- +2.1.0 + diff --git a/patches.arch/arm64-crypto-fix-makefile-rule.patch b/patches.arch/arm64-0005-arm64-crypto-fix-makefile-rule-for-aes-glue-.o.patch similarity index 63% rename from patches.arch/arm64-crypto-fix-makefile-rule.patch rename to patches.arch/arm64-0005-arm64-crypto-fix-makefile-rule-for-aes-glue-.o.patch index 98d4168..dbaf0a3 100644 --- a/patches.arch/arm64-crypto-fix-makefile-rule.patch +++ b/patches.arch/arm64-0005-arm64-crypto-fix-makefile-rule-for-aes-glue-.o.patch @@ -1,16 +1,18 @@ -From 7c2105fbe9658d6cee18751568e29579bb58bfec Mon Sep 17 00:00:00 2001 +From 2766747072be4aa7bf34fb834610f7504cbb842a Mon Sep 17 00:00:00 2001 From: Andreas Schwab <schwab@suse.de> Date: Thu, 24 Jul 2014 17:03:26 +0100 -Subject: [PATCH] arm64/crypto: fix makefile rule for aes-glue-%.o -Patch-Mainline: v3.17 +Subject: [PATCH 05/38] arm64/crypto: fix makefile rule for aes-glue-%.o +Git-commit: 7c2105fbe9658d6cee18751568e29579bb58bfec +Patch-mainline: v3.17-rc1 +References: bnc#902632 This fixes the following build failure when building with CONFIG_MODVERSIONS -enabled: +Enabled: CC [M] arch/arm64/crypto/aes-glue-ce.o -ld: cannot find arch/arm64/crypto/aes-glue-ce.o: No such file or directory -make[1]: *** [arch/arm64/crypto/aes-ce-blk.o] Error 1 -make: *** [arch/arm64/crypto] Error 2 +Ld: cannot find arch/arm64/crypto/aes-glue-ce.o: No such file or directory +Make[1]: *** [arch/arm64/crypto/aes-ce-blk.o] Error 1 +Make: *** [arch/arm64/crypto] Error 2 The $(obj)/aes-glue-%.o rule only creates $(obj)/.tmp_aes-glue-ce.o, it should use if_changed_rule instead of if_changed_dep. @@ -19,6 +21,11 @@ Signed-off-by: Andreas Schwab <schwab@suse.de> [ardb: mention CONFIG_MODVERSIONS in commit log] Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/crypto/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 2070a56..a3f935f 100644 @@ -26,7 +33,10 @@ index 2070a56..a3f935f 100644 +++ b/arch/arm64/crypto/Makefile @@ -35,4 +35,4 @@ AFLAGS_aes-neon.o := -DINTERLEAVE=4 CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS - + $(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) +-- +2.1.0 + diff --git a/patches.arch/arm64-0006-rtc-ia64-allow-other-architectures-to-use-EFI-RTC.patch b/patches.arch/arm64-0006-rtc-ia64-allow-other-architectures-to-use-EFI-RTC.patch new file mode 100644 index 0000000..13e088b --- /dev/null +++ b/patches.arch/arm64-0006-rtc-ia64-allow-other-architectures-to-use-EFI-RTC.patch @@ -0,0 +1,123 @@ +From e9e71a6f011ce57386456f7b70c7c20ff76b71be Mon Sep 17 00:00:00 2001 +From: Mark Salter <msalter@redhat.com> +Date: Fri, 8 Aug 2014 14:20:14 -0700 +Subject: [PATCH 06/38] rtc: ia64: allow other architectures to use EFI RTC +Git-commit: da167ad7638759adb811afa3c80ff4cb67608242 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +Currently, the rtc-efi driver is restricted to ia64 only. Newer +architectures with EFI support may want to also use that driver. This +patch moves the platform device setup from ia64 into drivers/rtc and +allow any architecture with CONFIG_EFI=y to use the rtc-efi driver. + +Signed-off-by: Mark Salter <msalter@redhat.com> +Cc: Alessandro Zummo <a.zummo@towertech.it> +Cc: Tony Luck <tony.luck@intel.com> +Cc: Fenghua Yu <fenghua.yu@intel.com> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/ia64/kernel/time.c | 15 --------------- + drivers/rtc/Kconfig | 2 +- + drivers/rtc/Makefile | 4 ++++ + drivers/rtc/rtc-efi-platform.c | 31 +++++++++++++++++++++++++++++++ + 4 files changed, 36 insertions(+), 16 deletions(-) + create mode 100644 drivers/rtc/rtc-efi-platform.c + +diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c +index 71c52bc..a149c67 100644 +--- a/arch/ia64/kernel/time.c ++++ b/arch/ia64/kernel/time.c +@@ -384,21 +384,6 @@ static struct irqaction timer_irqaction = { + .name = "timer" + }; + +-static struct platform_device rtc_efi_dev = { +- .name = "rtc-efi", +- .id = -1, +-}; +- +-static int __init rtc_init(void) +-{ +- if (platform_device_register(&rtc_efi_dev) < 0) +- printk(KERN_ERR "unable to register rtc device...\n"); +- +- /* not necessarily an error */ +- return 0; +-} +-module_init(rtc_init); +- + void read_persistent_clock(struct timespec *ts) + { + efi_gettimeofday(ts); +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 0754f5c..4478a59 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -789,7 +789,7 @@ config RTC_DRV_DA9063 + + config RTC_DRV_EFI + tristate "EFI RTC" +- depends on IA64 ++ depends on EFI + help + If you say yes here you will get support for the EFI + Real Time Clock. +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 70347d0..f1dfc36 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -10,6 +10,10 @@ obj-$(CONFIG_RTC_SYSTOHC) += systohc.o + obj-$(CONFIG_RTC_CLASS) += rtc-core.o + rtc-core-y := class.o interface.o + ++ifdef CONFIG_RTC_DRV_EFI ++rtc-core-y += rtc-efi-platform.o ++endif ++ + rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o + rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o + rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o +diff --git a/drivers/rtc/rtc-efi-platform.c b/drivers/rtc/rtc-efi-platform.c +new file mode 100644 +index 0000000..b40fbe3 +--- /dev/null ++++ b/drivers/rtc/rtc-efi-platform.c +@@ -0,0 +1,31 @@ ++/* ++ * Moved from arch/ia64/kernel/time.c ++ * ++ * Copyright (C) 1998-2003 Hewlett-Packard Co ++ * Stephane Eranian <eranian@hpl.hp.com> ++ * David Mosberger <davidm@hpl.hp.com> ++ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com> ++ * Copyright (C) 1999-2000 VA Linux Systems ++ * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com> ++ */ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/efi.h> ++#include <linux/platform_device.h> ++ ++static struct platform_device rtc_efi_dev = { ++ .name = "rtc-efi", ++ .id = -1, ++}; ++ ++static int __init rtc_init(void) ++{ ++ if (efi_enabled(EFI_RUNTIME_SERVICES)) ++ if (platform_device_register(&rtc_efi_dev) < 0) ++ pr_err("unable to register rtc device...\n"); ++ ++ /* not necessarily an error */ ++ return 0; ++} ++module_init(rtc_init); +-- +2.1.0 + diff --git a/patches.arch/arm64-0007-arm64-fix-VTTBR_BADDR_MASK.patch b/patches.arch/arm64-0007-arm64-fix-VTTBR_BADDR_MASK.patch new file mode 100644 index 0000000..7bafe05 --- /dev/null +++ b/patches.arch/arm64-0007-arm64-fix-VTTBR_BADDR_MASK.patch @@ -0,0 +1,339 @@ +From 6f1f003414457bf6aacdbe7fd0232dd663b0a7b7 Mon Sep 17 00:00:00 2001 +From: Joel Schopp <joel.schopp@amd.com> +Date: Mon, 8 Sep 2014 23:08:52 +0000 +Subject: [PATCH 07/38] arm64: fix VTTBR_BADDR_MASK +Git-commit: dbff124e29fa24aff9705b354b5f4648cd96e0bb +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The current VTTBR_BADDR_MASK only masks 39 bits, which is broken on current +systems. Rather than just add a bit it seems like a good time to also set +things at run-time instead of compile time to accomodate more hardware. + +This patch sets TCR_EL2.PS, VTCR_EL2.T0SZ and vttbr_baddr_mask in runtime, +not compile time. + +In ARMv8, EL2 physical address size (TCR_EL2.PS) and stage2 input address +size (VTCR_EL2.T0SZE) cannot be determined in compile time since they +depend on hardware capability. + +According to Table D4-23 and Table D4-25 in ARM DDI 0487A.b document, +vttbr_x is calculated using different fixed values with consideration +of T0SZ, granule size and the level of translation tables. Therefore, +vttbr_baddr_mask should be determined dynamically. + +Changes since v5: +Fixed declaration of vttbr_baddr_mask to not create multiple instances +Refactored return codes based on feedback +For 32 bit included kvm_arm.h in kvm_mmu.h to explictly pick up VTTBR_BADDR_MASK + +Changes since v4: +More minor cleanups from review +Moved some functions into headers +Added runtime check in kvm_alloc_stage2_pgd + +Changes since v3: +Another rebase +Addressed minor comments from v2 + +Changes since v2: +Rebased on https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git next branch + +Changes since v1: +Rebased fix on Jungseok Lee's patch https://lkml.org/lkml/2014/5/12/189 to +provide better long term fix. Updated that patch to log error instead of +silently fail on unaligned vttbr. + +Cc: Marc Zyngier <marc.zyngier@arm.com> +Cc: Christoffer Dall <christoffer.dall@linaro.org> +Cc: Sungjinn Chung <sungjinn.chung@samsung.com> +Signed-off-by: Jungseok Lee <jays.lee@samsung.com> +Signed-off-by: Joel Schopp <joel.schopp@amd.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm/include/asm/kvm_mmu.h | 13 +++++++ + arch/arm/kvm/arm.c | 23 ++++++++++-- + arch/arm64/include/asm/kvm_arm.h | 17 ++------- + arch/arm64/include/asm/kvm_mmu.h | 75 ++++++++++++++++++++++++++++++++++++++++ + arch/arm64/kvm/hyp-init.S | 20 +++++++---- + 5 files changed, 126 insertions(+), 22 deletions(-) + +diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h +index 5c7aa3c..77500b0 100644 +--- a/arch/arm/include/asm/kvm_mmu.h ++++ b/arch/arm/include/asm/kvm_mmu.h +@@ -21,6 +21,7 @@ + + #include <asm/memory.h> + #include <asm/page.h> ++#include <asm/kvm_arm.h> + + /* + * We directly use the kernel VA for the HYP, as we can directly share +@@ -166,6 +167,18 @@ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, + + void stage2_flush_vm(struct kvm *kvm); + ++static inline int kvm_get_phys_addr_shift(void) ++{ ++ return KVM_PHYS_SHIFT; ++} ++ ++ ++static inline u32 get_vttbr_baddr_mask(void) ++{ ++ return VTTBR_BADDR_MASK; ++} ++ ++ + #endif /* !__ASSEMBLY__ */ + + #endif /* __ARM_KVM_MMU_H__ */ +diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c +index 3c82b37..9080e88 100644 +--- a/arch/arm/kvm/arm.c ++++ b/arch/arm/kvm/arm.c +@@ -37,6 +37,7 @@ + #include <asm/mman.h> + #include <asm/tlbflush.h> + #include <asm/cacheflush.h> ++#include <asm/cputype.h> + #include <asm/virt.h> + #include <asm/kvm_arm.h> + #include <asm/kvm_asm.h> +@@ -61,6 +62,12 @@ static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1); + static u8 kvm_next_vmid; + static DEFINE_SPINLOCK(kvm_vmid_lock); + ++#ifdef CONFIG_ARM64 ++static u64 vttbr_baddr_mask; ++#else ++static u32 vttbr_baddr_mask; ++#endif ++ + static bool vgic_present; + + static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu) +@@ -466,8 +473,14 @@ static void update_vttbr(struct kvm *kvm) + /* update vttbr to be used with the new vmid */ + pgd_phys = virt_to_phys(kvm->arch.pgd); + vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK; +- kvm->arch.vttbr = pgd_phys & VTTBR_BADDR_MASK; +- kvm->arch.vttbr |= vmid; ++ ++ /* ++ * If the VTTBR isn't aligned there is something wrong with the system ++ * or kernel. ++ */ ++ BUG_ON(pgd_phys & ~vttbr_baddr_mask); ++ ++ kvm->arch.vttbr = pgd_phys | vmid; + + spin_unlock(&kvm_vmid_lock); + } +@@ -1052,6 +1065,12 @@ int kvm_arch_init(void *opaque) + } + } + ++ vttbr_baddr_mask = get_vttbr_baddr_mask(); ++ if (vttbr_baddr_mask == ~0) { ++ kvm_err("Cannot set vttbr_baddr_mask\n"); ++ return -EINVAL; ++ } ++ + cpu_notifier_register_begin(); + + err = init_hyp_mode(); +diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h +index 3d69030..8dbef70 100644 +--- a/arch/arm64/include/asm/kvm_arm.h ++++ b/arch/arm64/include/asm/kvm_arm.h +@@ -94,7 +94,6 @@ + /* TCR_EL2 Registers bits */ + #define TCR_EL2_TBI (1 << 20) + #define TCR_EL2_PS (7 << 16) +-#define TCR_EL2_PS_40B (2 << 16) + #define TCR_EL2_TG0 (1 << 14) + #define TCR_EL2_SH0 (3 << 12) + #define TCR_EL2_ORGN0 (3 << 10) +@@ -103,8 +102,6 @@ + #define TCR_EL2_MASK (TCR_EL2_TG0 | TCR_EL2_SH0 | \ + TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ) + +-#define TCR_EL2_FLAGS (TCR_EL2_PS_40B) +- + /* VTCR_EL2 Registers bits */ + #define VTCR_EL2_PS_MASK (7 << 16) + #define VTCR_EL2_TG0_MASK (1 << 14) +@@ -119,36 +116,28 @@ + #define VTCR_EL2_SL0_MASK (3 << 6) + #define VTCR_EL2_SL0_LVL1 (1 << 6) + #define VTCR_EL2_T0SZ_MASK 0x3f +-#define VTCR_EL2_T0SZ_40B 24 ++#define VTCR_EL2_T0SZ(bits) (64 - (bits)) + + #ifdef CONFIG_ARM64_64K_PAGES + /* + * Stage2 translation configuration: +- * 40bits output (PS = 2) +- * 40bits input (T0SZ = 24) + * 64kB pages (TG0 = 1) + * 2 level page tables (SL = 1) + */ + #define VTCR_EL2_FLAGS (VTCR_EL2_TG0_64K | VTCR_EL2_SH0_INNER | \ + VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \ +- VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B) +-#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B) ++ VTCR_EL2_SL0_LVL1) + #else + /* + * Stage2 translation configuration: +- * 40bits output (PS = 2) +- * 40bits input (T0SZ = 24) + * 4kB pages (TG0 = 0) + * 3 level page tables (SL = 1) + */ + #define VTCR_EL2_FLAGS (VTCR_EL2_TG0_4K | VTCR_EL2_SH0_INNER | \ + VTCR_EL2_ORGN0_WBWA | VTCR_EL2_IRGN0_WBWA | \ +- VTCR_EL2_SL0_LVL1 | VTCR_EL2_T0SZ_40B) +-#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B) ++ VTCR_EL2_SL0_LVL1) + #endif + +-#define VTTBR_BADDR_SHIFT (VTTBR_X - 1) +-#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) + #define VTTBR_VMID_SHIFT (48LLU) + #define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT) + +diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h +index 7d29847..ff97a1f 100644 +--- a/arch/arm64/include/asm/kvm_mmu.h ++++ b/arch/arm64/include/asm/kvm_mmu.h +@@ -152,5 +152,80 @@ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, + + void stage2_flush_vm(struct kvm *kvm); + ++/* ++ * ARMv8 64K architecture limitations: ++ * 16 <= T0SZ <= 21 is valid under 3 level of translation tables ++ * 18 <= T0SZ <= 34 is valid under 2 level of translation tables ++ * 31 <= T0SZ <= 39 is valid under 1 level of transltaion tables ++ * ++ * ARMv8 4K architecture limitations: ++ * 16 <= T0SZ <= 24 is valid under 4 level of translation tables ++ * 21 <= T0SZ <= 33 is valid under 3 level of translation tables ++ * 30 <= T0SZ <= 39 is valid under 2 level of translation tables ++ * ++ * For 4K pages we only support 3 or 4 level, giving T0SZ a range of 16 to 33. ++ * For 64K pages we only support 2 or 3 level, giving T0SZ a range of 16 to 34. ++ * ++ * See Table D4-23 and Table D4-25 in ARM DDI 0487A.b to figure out ++ * the origin of the hardcoded values, 38 and 37. ++ */ ++ ++#ifdef CONFIG_ARM64_64K_PAGES ++static inline int t0sz_to_vttbr_x(int t0sz) ++{ ++ if (t0sz < 16 || t0sz > 34) { ++ kvm_err("Cannot support %d-bit address space\n", 64 - t0sz); ++ return -EINVAL; ++ } ++ ++ return 38 - t0sz; ++} ++#else /* 4K pages */ ++static inline int t0sz_to_vttbr_x(int t0sz) ++{ ++ if (t0sz < 16 || t0sz > 33) { ++ kvm_err("Cannot support %d-bit address space\n", 64 - t0sz); ++ return -EINVAL; ++ } ++ return 37 - t0sz; ++} ++#endif ++static inline int kvm_get_phys_addr_shift(void) ++{ ++ int pa_range = read_cpuid(ID_AA64MMFR0_EL1) & 0xf; ++ ++ switch (pa_range) { ++ case 0: return 32; ++ case 1: return 36; ++ case 2: return 40; ++ case 3: return 42; ++ case 4: return 44; ++ case 5: return 48; ++ default: ++ BUG(); ++ return 0; ++ } ++} ++ ++/** ++ * get_vttbr_baddr_mask - get mask value for vttbr base address ++ * ++ * In ARMv8, vttbr_baddr_mask cannot be determined in compile time since the ++ * stage2 input address size depends on hardware capability. Thus, we first ++ * need to read ID_AA64MMFR0_EL1.PARange and then set vttbr_baddr_mask with ++ * consideration of both the granule size and the level of translation tables. ++ */ ++static inline u64 get_vttbr_baddr_mask(void) ++{ ++ int t0sz, vttbr_x; ++ ++ t0sz = VTCR_EL2_T0SZ(kvm_get_phys_addr_shift()); ++ vttbr_x = t0sz_to_vttbr_x(t0sz); ++ if (vttbr_x < 0) ++ return ~0; ++ return GENMASK_ULL(48, (vttbr_x - 1)); ++ ++} ++ + #endif /* __ASSEMBLY__ */ + #endif /* __ARM64_KVM_MMU_H__ */ +diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S +index c319116..fa7e67e 100644 +--- a/arch/arm64/kvm/hyp-init.S ++++ b/arch/arm64/kvm/hyp-init.S +@@ -63,17 +63,21 @@ __do_hyp_init: + mrs x4, tcr_el1 + ldr x5, =TCR_EL2_MASK + and x4, x4, x5 +- ldr x5, =TCR_EL2_FLAGS +- orr x4, x4, x5 +- msr tcr_el2, x4 +- +- ldr x4, =VTCR_EL2_FLAGS + /* + * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in +- * VTCR_EL2. ++ * TCR_EL2 and both PS bits and T0SZ bits in VTCR_EL2. + */ + mrs x5, ID_AA64MMFR0_EL1 + bfi x4, x5, #16, #3 ++ msr tcr_el2, x4 ++ ++ ldr x4, =VTCR_EL2_FLAGS ++ bfi x4, x5, #16, #3 ++ and x5, x5, #0xf ++ adr x6, t0sz ++ add x6, x6, x5, lsl #2 ++ ldr w5, [x6] ++ orr x4, x4, x5 + msr vtcr_el2, x4 + + mrs x4, mair_el1 +@@ -113,6 +117,10 @@ target: /* We're now in the trampoline code, switch page tables */ + + /* Hello, World! */ + eret ++ ++t0sz: ++ .word VTCR_EL2_T0SZ(32), VTCR_EL2_T0SZ(36), VTCR_EL2_T0SZ(40) ++ .word VTCR_EL2_T0SZ(42), VTCR_EL2_T0SZ(44), VTCR_EL2_T0SZ(48) + ENDPROC(__kvm_hyp_init) + + .ltorg +-- +2.1.0 + diff --git a/patches.arch/arm64-0008-KVM-ARM-Add-arm-gic-400-compatible-support.patch b/patches.arch/arm64-0008-KVM-ARM-Add-arm-gic-400-compatible-support.patch new file mode 100644 index 0000000..4f14c30 --- /dev/null +++ b/patches.arch/arm64-0008-KVM-ARM-Add-arm-gic-400-compatible-support.patch @@ -0,0 +1,34 @@ +From 5c8a2dba556e1664a8b9281d7662e5f794720ad4 Mon Sep 17 00:00:00 2001 +From: Andreas Schwab <schwab@suse.de> +Date: Thu, 11 Sep 2014 12:02:29 +0200 +Subject: [PATCH 08/38] KVM: ARM: Add "arm,gic-400" compatible support +Git-commit: 5c8a2dba556e1664a8b9281d7662e5f794720ad4 +Patch-mainline: No +References: bnc#902632 + +Some device trees specify their GIC as compatible "arm,gic-400". The code +supports those just fine, we were only missing the compatible to make it +work. + +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + virt/kvm/arm/vgic.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c +index 476d3bf..718e8ca 100644 +--- a/virt/kvm/arm/vgic.c ++++ b/virt/kvm/arm/vgic.c +@@ -1477,6 +1477,8 @@ int kvm_vgic_hyp_init(void) + struct resource vcpu_res; + + vgic_node = of_find_compatible_node(NULL, NULL, "arm,cortex-a15-gic"); ++ if (!vgic_node) ++ vgic_node = of_find_compatible_node(NULL, NULL, "arm,gic-400"); + if (!vgic_node) { + kvm_err("error: no compatible vgic node in DT\n"); + return -ENODEV; +-- +2.1.0 + diff --git a/patches.arch/arm64-0009-net-xgbe-Add-A0-silicon-support.patch b/patches.arch/arm64-0009-net-xgbe-Add-A0-silicon-support.patch new file mode 100644 index 0000000..fabe8db --- /dev/null +++ b/patches.arch/arm64-0009-net-xgbe-Add-A0-silicon-support.patch @@ -0,0 +1,10913 @@ +From 7076a3d8fbc6fbba8522fb916fbb28d971473180 Mon Sep 17 00:00:00 2001 +From: Alexander Graf <agraf@suse.de> +Date: Tue, 21 Oct 2014 18:36:58 +0200 +Subject: [PATCH 09/38] net/xgbe: Add A0 silicon support +Git-commit: 7076a3d8fbc6fbba8522fb916fbb28d971473180 +Patch-mainline: No +References: bnc#902632 + +The AMD xgbe driver only supports B0 silicon, but some systems +already have A0 silicon. This patch adds a driver from AMD for +early A0 silicon in parallel to the B0 one. + +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/net/ethernet/amd/Makefile | 2 +- + drivers/net/ethernet/amd/xgbe-a0/Makefile | 8 + + drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h | 1104 ++++++++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c | 270 +++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c | 374 ++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c | 566 +++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c | 2643 +++++++++++++++++++++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c | 1864 ++++++++++++++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c | 544 +++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c | 566 +++++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c | 330 +++ + drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c | 285 +++ + drivers/net/ethernet/amd/xgbe-a0/xgbe.h | 769 +++++++ + drivers/net/phy/Makefile | 1 + + drivers/net/phy/amd-xgbe-a0-phy.c | 1445 +++++++++++++ + 15 files changed, 10770 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/Makefile + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c + create mode 100644 drivers/net/ethernet/amd/xgbe-a0/xgbe.h + create mode 100644 drivers/net/phy/amd-xgbe-a0-phy.c + +diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile +index a38a2dc..2dd45df 100644 +--- a/drivers/net/ethernet/amd/Makefile ++++ b/drivers/net/ethernet/amd/Makefile +@@ -17,4 +17,4 @@ obj-$(CONFIG_NI65) += ni65.o + obj-$(CONFIG_PCNET32) += pcnet32.o + obj-$(CONFIG_SUN3LANCE) += sun3lance.o + obj-$(CONFIG_SUNLANCE) += sunlance.o +-obj-$(CONFIG_AMD_XGBE) += xgbe/ ++obj-$(CONFIG_AMD_XGBE) += xgbe/ xgbe-a0/ +diff --git a/drivers/net/ethernet/amd/xgbe-a0/Makefile b/drivers/net/ethernet/amd/xgbe-a0/Makefile +new file mode 100644 +index 0000000..561116f +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/Makefile +@@ -0,0 +1,8 @@ ++obj-$(CONFIG_AMD_XGBE) += amd-xgbe-a0.o ++ ++amd-xgbe-a0-objs := xgbe-main.o xgbe-drv.o xgbe-dev.o \ ++ xgbe-desc.o xgbe-ethtool.o xgbe-mdio.o \ ++ xgbe-ptp.o ++ ++amd-xgbe-a0-$(CONFIG_AMD_XGBE_DCB) += xgbe-dcb.o ++amd-xgbe-a0-$(CONFIG_DEBUG_FS) += xgbe-debugfs.o +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h b/drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h +new file mode 100644 +index 0000000..cc25a3a +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-common.h +@@ -0,0 +1,1104 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 __XGBE_COMMON_H__ ++#define __XGBE_COMMON_H__ ++ ++/* DMA register offsets */ ++#define DMA_MR 0x3000 ++#define DMA_SBMR 0x3004 ++#define DMA_ISR 0x3008 ++#define DMA_AXIARCR 0x3010 ++#define DMA_AXIAWCR 0x3018 ++#define DMA_DSR0 0x3020 ++#define DMA_DSR1 0x3024 ++#define DMA_DSR2 0x3028 ++#define DMA_DSR3 0x302c ++#define DMA_DSR4 0x3030 ++ ++/* DMA register entry bit positions and sizes */ ++#define DMA_AXIARCR_DRC_INDEX 0 ++#define DMA_AXIARCR_DRC_WIDTH 4 ++#define DMA_AXIARCR_DRD_INDEX 4 ++#define DMA_AXIARCR_DRD_WIDTH 2 ++#define DMA_AXIARCR_TEC_INDEX 8 ++#define DMA_AXIARCR_TEC_WIDTH 4 ++#define DMA_AXIARCR_TED_INDEX 12 ++#define DMA_AXIARCR_TED_WIDTH 2 ++#define DMA_AXIARCR_THC_INDEX 16 ++#define DMA_AXIARCR_THC_WIDTH 4 ++#define DMA_AXIARCR_THD_INDEX 20 ++#define DMA_AXIARCR_THD_WIDTH 2 ++#define DMA_AXIAWCR_DWC_INDEX 0 ++#define DMA_AXIAWCR_DWC_WIDTH 4 ++#define DMA_AXIAWCR_DWD_INDEX 4 ++#define DMA_AXIAWCR_DWD_WIDTH 2 ++#define DMA_AXIAWCR_RPC_INDEX 8 ++#define DMA_AXIAWCR_RPC_WIDTH 4 ++#define DMA_AXIAWCR_RPD_INDEX 12 ++#define DMA_AXIAWCR_RPD_WIDTH 2 ++#define DMA_AXIAWCR_RHC_INDEX 16 ++#define DMA_AXIAWCR_RHC_WIDTH 4 ++#define DMA_AXIAWCR_RHD_INDEX 20 ++#define DMA_AXIAWCR_RHD_WIDTH 2 ++#define DMA_AXIAWCR_TDC_INDEX 24 ++#define DMA_AXIAWCR_TDC_WIDTH 4 ++#define DMA_AXIAWCR_TDD_INDEX 28 ++#define DMA_AXIAWCR_TDD_WIDTH 2 ++#define DMA_DSR0_RPS_INDEX 8 ++#define DMA_DSR0_RPS_WIDTH 4 ++#define DMA_DSR0_TPS_INDEX 12 ++#define DMA_DSR0_TPS_WIDTH 4 ++#define DMA_ISR_MACIS_INDEX 17 ++#define DMA_ISR_MACIS_WIDTH 1 ++#define DMA_ISR_MTLIS_INDEX 16 ++#define DMA_ISR_MTLIS_WIDTH 1 ++#define DMA_MR_SWR_INDEX 0 ++#define DMA_MR_SWR_WIDTH 1 ++#define DMA_SBMR_EAME_INDEX 11 ++#define DMA_SBMR_EAME_WIDTH 1 ++#define DMA_SBMR_BLEN_256_INDEX 7 ++#define DMA_SBMR_BLEN_256_WIDTH 1 ++#define DMA_SBMR_UNDEF_INDEX 0 ++#define DMA_SBMR_UNDEF_WIDTH 1 ++ ++/* DMA channel register offsets ++ * Multiple channels can be active. The first channel has registers ++ * that begin at 0x3100. Each subsequent channel has registers that ++ * are accessed using an offset of 0x80 from the previous channel. ++ */ ++#define DMA_CH_BASE 0x3100 ++#define DMA_CH_INC 0x80 ++ ++#define DMA_CH_CR 0x00 ++#define DMA_CH_TCR 0x04 ++#define DMA_CH_RCR 0x08 ++#define DMA_CH_TDLR_HI 0x10 ++#define DMA_CH_TDLR_LO 0x14 ++#define DMA_CH_RDLR_HI 0x18 ++#define DMA_CH_RDLR_LO 0x1c ++#define DMA_CH_TDTR_LO 0x24 ++#define DMA_CH_RDTR_LO 0x2c ++#define DMA_CH_TDRLR 0x30 ++#define DMA_CH_RDRLR 0x34 ++#define DMA_CH_IER 0x38 ++#define DMA_CH_RIWT 0x3c ++#define DMA_CH_CATDR_LO 0x44 ++#define DMA_CH_CARDR_LO 0x4c ++#define DMA_CH_CATBR_HI 0x50 ++#define DMA_CH_CATBR_LO 0x54 ++#define DMA_CH_CARBR_HI 0x58 ++#define DMA_CH_CARBR_LO 0x5c ++#define DMA_CH_SR 0x60 ++ ++/* DMA channel register entry bit positions and sizes */ ++#define DMA_CH_CR_PBLX8_INDEX 16 ++#define DMA_CH_CR_PBLX8_WIDTH 1 ++#define DMA_CH_IER_AIE_INDEX 15 ++#define DMA_CH_IER_AIE_WIDTH 1 ++#define DMA_CH_IER_FBEE_INDEX 12 ++#define DMA_CH_IER_FBEE_WIDTH 1 ++#define DMA_CH_IER_NIE_INDEX 16 ++#define DMA_CH_IER_NIE_WIDTH 1 ++#define DMA_CH_IER_RBUE_INDEX 7 ++#define DMA_CH_IER_RBUE_WIDTH 1 ++#define DMA_CH_IER_RIE_INDEX 6 ++#define DMA_CH_IER_RIE_WIDTH 1 ++#define DMA_CH_IER_RSE_INDEX 8 ++#define DMA_CH_IER_RSE_WIDTH 1 ++#define DMA_CH_IER_TBUE_INDEX 2 ++#define DMA_CH_IER_TBUE_WIDTH 1 ++#define DMA_CH_IER_TIE_INDEX 0 ++#define DMA_CH_IER_TIE_WIDTH 1 ++#define DMA_CH_IER_TXSE_INDEX 1 ++#define DMA_CH_IER_TXSE_WIDTH 1 ++#define DMA_CH_RCR_PBL_INDEX 16 ++#define DMA_CH_RCR_PBL_WIDTH 6 ++#define DMA_CH_RCR_RBSZ_INDEX 1 ++#define DMA_CH_RCR_RBSZ_WIDTH 14 ++#define DMA_CH_RCR_SR_INDEX 0 ++#define DMA_CH_RCR_SR_WIDTH 1 ++#define DMA_CH_RIWT_RWT_INDEX 0 ++#define DMA_CH_RIWT_RWT_WIDTH 8 ++#define DMA_CH_SR_FBE_INDEX 12 ++#define DMA_CH_SR_FBE_WIDTH 1 ++#define DMA_CH_SR_RBU_INDEX 7 ++#define DMA_CH_SR_RBU_WIDTH 1 ++#define DMA_CH_SR_RI_INDEX 6 ++#define DMA_CH_SR_RI_WIDTH 1 ++#define DMA_CH_SR_RPS_INDEX 8 ++#define DMA_CH_SR_RPS_WIDTH 1 ++#define DMA_CH_SR_TBU_INDEX 2 ++#define DMA_CH_SR_TBU_WIDTH 1 ++#define DMA_CH_SR_TI_INDEX 0 ++#define DMA_CH_SR_TI_WIDTH 1 ++#define DMA_CH_SR_TPS_INDEX 1 ++#define DMA_CH_SR_TPS_WIDTH 1 ++#define DMA_CH_TCR_OSP_INDEX 4 ++#define DMA_CH_TCR_OSP_WIDTH 1 ++#define DMA_CH_TCR_PBL_INDEX 16 ++#define DMA_CH_TCR_PBL_WIDTH 6 ++#define DMA_CH_TCR_ST_INDEX 0 ++#define DMA_CH_TCR_ST_WIDTH 1 ++#define DMA_CH_TCR_TSE_INDEX 12 ++#define DMA_CH_TCR_TSE_WIDTH 1 ++ ++/* DMA channel register values */ ++#define DMA_OSP_DISABLE 0x00 ++#define DMA_OSP_ENABLE 0x01 ++#define DMA_PBL_1 1 ++#define DMA_PBL_2 2 ++#define DMA_PBL_4 4 ++#define DMA_PBL_8 8 ++#define DMA_PBL_16 16 ++#define DMA_PBL_32 32 ++#define DMA_PBL_64 64 /* 8 x 8 */ ++#define DMA_PBL_128 128 /* 8 x 16 */ ++#define DMA_PBL_256 256 /* 8 x 32 */ ++#define DMA_PBL_X8_DISABLE 0x00 ++#define DMA_PBL_X8_ENABLE 0x01 ++ ++ ++/* MAC register offsets */ ++#define MAC_TCR 0x0000 ++#define MAC_RCR 0x0004 ++#define MAC_PFR 0x0008 ++#define MAC_WTR 0x000c ++#define MAC_HTR0 0x0010 ++#define MAC_VLANTR 0x0050 ++#define MAC_VLANHTR 0x0058 ++#define MAC_VLANIR 0x0060 ++#define MAC_IVLANIR 0x0064 ++#define MAC_RETMR 0x006c ++#define MAC_Q0TFCR 0x0070 ++#define MAC_RFCR 0x0090 ++#define MAC_RQC0R 0x00a0 ++#define MAC_RQC1R 0x00a4 ++#define MAC_RQC2R 0x00a8 ++#define MAC_RQC3R 0x00ac ++#define MAC_ISR 0x00b0 ++#define MAC_IER 0x00b4 ++#define MAC_RTSR 0x00b8 ++#define MAC_PMTCSR 0x00c0 ++#define MAC_RWKPFR 0x00c4 ++#define MAC_LPICSR 0x00d0 ++#define MAC_LPITCR 0x00d4 ++#define MAC_VR 0x0110 ++#define MAC_DR 0x0114 ++#define MAC_HWF0R 0x011c ++#define MAC_HWF1R 0x0120 ++#define MAC_HWF2R 0x0124 ++#define MAC_GPIOCR 0x0278 ++#define MAC_GPIOSR 0x027c ++#define MAC_MACA0HR 0x0300 ++#define MAC_MACA0LR 0x0304 ++#define MAC_MACA1HR 0x0308 ++#define MAC_MACA1LR 0x030c ++#define MAC_TSCR 0x0d00 ++#define MAC_SSIR 0x0d04 ++#define MAC_STSR 0x0d08 ++#define MAC_STNR 0x0d0c ++#define MAC_STSUR 0x0d10 ++#define MAC_STNUR 0x0d14 ++#define MAC_TSAR 0x0d18 ++#define MAC_TSSR 0x0d20 ++#define MAC_TXSNR 0x0d30 ++#define MAC_TXSSR 0x0d34 ++ ++#define MAC_QTFCR_INC 4 ++#define MAC_MACA_INC 4 ++#define MAC_HTR_INC 4 ++ ++#define MAC_RQC2_INC 4 ++#define MAC_RQC2_Q_PER_REG 4 ++ ++/* MAC register entry bit positions and sizes */ ++#define MAC_HWF0R_ADDMACADRSEL_INDEX 18 ++#define MAC_HWF0R_ADDMACADRSEL_WIDTH 5 ++#define MAC_HWF0R_ARPOFFSEL_INDEX 9 ++#define MAC_HWF0R_ARPOFFSEL_WIDTH 1 ++#define MAC_HWF0R_EEESEL_INDEX 13 ++#define MAC_HWF0R_EEESEL_WIDTH 1 ++#define MAC_HWF0R_GMIISEL_INDEX 1 ++#define MAC_HWF0R_GMIISEL_WIDTH 1 ++#define MAC_HWF0R_MGKSEL_INDEX 7 ++#define MAC_HWF0R_MGKSEL_WIDTH 1 ++#define MAC_HWF0R_MMCSEL_INDEX 8 ++#define MAC_HWF0R_MMCSEL_WIDTH 1 ++#define MAC_HWF0R_RWKSEL_INDEX 6 ++#define MAC_HWF0R_RWKSEL_WIDTH 1 ++#define MAC_HWF0R_RXCOESEL_INDEX 16 ++#define MAC_HWF0R_RXCOESEL_WIDTH 1 ++#define MAC_HWF0R_SAVLANINS_INDEX 27 ++#define MAC_HWF0R_SAVLANINS_WIDTH 1 ++#define MAC_HWF0R_SMASEL_INDEX 5 ++#define MAC_HWF0R_SMASEL_WIDTH 1 ++#define MAC_HWF0R_TSSEL_INDEX 12 ++#define MAC_HWF0R_TSSEL_WIDTH 1 ++#define MAC_HWF0R_TSSTSSEL_INDEX 25 ++#define MAC_HWF0R_TSSTSSEL_WIDTH 2 ++#define MAC_HWF0R_TXCOESEL_INDEX 14 ++#define MAC_HWF0R_TXCOESEL_WIDTH 1 ++#define MAC_HWF0R_VLHASH_INDEX 4 ++#define MAC_HWF0R_VLHASH_WIDTH 1 ++#define MAC_HWF1R_ADVTHWORD_INDEX 13 ++#define MAC_HWF1R_ADVTHWORD_WIDTH 1 ++#define MAC_HWF1R_DBGMEMA_INDEX 19 ++#define MAC_HWF1R_DBGMEMA_WIDTH 1 ++#define MAC_HWF1R_DCBEN_INDEX 16 ++#define MAC_HWF1R_DCBEN_WIDTH 1 ++#define MAC_HWF1R_HASHTBLSZ_INDEX 24 ++#define MAC_HWF1R_HASHTBLSZ_WIDTH 3 ++#define MAC_HWF1R_L3L4FNUM_INDEX 27 ++#define MAC_HWF1R_L3L4FNUM_WIDTH 4 ++#define MAC_HWF1R_NUMTC_INDEX 21 ++#define MAC_HWF1R_NUMTC_WIDTH 3 ++#define MAC_HWF1R_RSSEN_INDEX 20 ++#define MAC_HWF1R_RSSEN_WIDTH 1 ++#define MAC_HWF1R_RXFIFOSIZE_INDEX 0 ++#define MAC_HWF1R_RXFIFOSIZE_WIDTH 5 ++#define MAC_HWF1R_SPHEN_INDEX 17 ++#define MAC_HWF1R_SPHEN_WIDTH 1 ++#define MAC_HWF1R_TSOEN_INDEX 18 ++#define MAC_HWF1R_TSOEN_WIDTH 1 ++#define MAC_HWF1R_TXFIFOSIZE_INDEX 6 ++#define MAC_HWF1R_TXFIFOSIZE_WIDTH 5 ++#define MAC_HWF2R_AUXSNAPNUM_INDEX 28 ++#define MAC_HWF2R_AUXSNAPNUM_WIDTH 3 ++#define MAC_HWF2R_PPSOUTNUM_INDEX 24 ++#define MAC_HWF2R_PPSOUTNUM_WIDTH 3 ++#define MAC_HWF2R_RXCHCNT_INDEX 12 ++#define MAC_HWF2R_RXCHCNT_WIDTH 4 ++#define MAC_HWF2R_RXQCNT_INDEX 0 ++#define MAC_HWF2R_RXQCNT_WIDTH 4 ++#define MAC_HWF2R_TXCHCNT_INDEX 18 ++#define MAC_HWF2R_TXCHCNT_WIDTH 4 ++#define MAC_HWF2R_TXQCNT_INDEX 6 ++#define MAC_HWF2R_TXQCNT_WIDTH 4 ++#define MAC_IER_TSIE_INDEX 12 ++#define MAC_IER_TSIE_WIDTH 1 ++#define MAC_ISR_MMCRXIS_INDEX 9 ++#define MAC_ISR_MMCRXIS_WIDTH 1 ++#define MAC_ISR_MMCTXIS_INDEX 10 ++#define MAC_ISR_MMCTXIS_WIDTH 1 ++#define MAC_ISR_PMTIS_INDEX 4 ++#define MAC_ISR_PMTIS_WIDTH 1 ++#define MAC_ISR_TSIS_INDEX 12 ++#define MAC_ISR_TSIS_WIDTH 1 ++#define MAC_MACA1HR_AE_INDEX 31 ++#define MAC_MACA1HR_AE_WIDTH 1 ++#define MAC_PFR_HMC_INDEX 2 ++#define MAC_PFR_HMC_WIDTH 1 ++#define MAC_PFR_HPF_INDEX 10 ++#define MAC_PFR_HPF_WIDTH 1 ++#define MAC_PFR_HUC_INDEX 1 ++#define MAC_PFR_HUC_WIDTH 1 ++#define MAC_PFR_PM_INDEX 4 ++#define MAC_PFR_PM_WIDTH 1 ++#define MAC_PFR_PR_INDEX 0 ++#define MAC_PFR_PR_WIDTH 1 ++#define MAC_PFR_VTFE_INDEX 16 ++#define MAC_PFR_VTFE_WIDTH 1 ++#define MAC_PMTCSR_MGKPKTEN_INDEX 1 ++#define MAC_PMTCSR_MGKPKTEN_WIDTH 1 ++#define MAC_PMTCSR_PWRDWN_INDEX 0 ++#define MAC_PMTCSR_PWRDWN_WIDTH 1 ++#define MAC_PMTCSR_RWKFILTRST_INDEX 31 ++#define MAC_PMTCSR_RWKFILTRST_WIDTH 1 ++#define MAC_PMTCSR_RWKPKTEN_INDEX 2 ++#define MAC_PMTCSR_RWKPKTEN_WIDTH 1 ++#define MAC_Q0TFCR_PT_INDEX 16 ++#define MAC_Q0TFCR_PT_WIDTH 16 ++#define MAC_Q0TFCR_TFE_INDEX 1 ++#define MAC_Q0TFCR_TFE_WIDTH 1 ++#define MAC_RCR_ACS_INDEX 1 ++#define MAC_RCR_ACS_WIDTH 1 ++#define MAC_RCR_CST_INDEX 2 ++#define MAC_RCR_CST_WIDTH 1 ++#define MAC_RCR_DCRCC_INDEX 3 ++#define MAC_RCR_DCRCC_WIDTH 1 ++#define MAC_RCR_IPC_INDEX 9 ++#define MAC_RCR_IPC_WIDTH 1 ++#define MAC_RCR_JE_INDEX 8 ++#define MAC_RCR_JE_WIDTH 1 ++#define MAC_RCR_LM_INDEX 10 ++#define MAC_RCR_LM_WIDTH 1 ++#define MAC_RCR_RE_INDEX 0 ++#define MAC_RCR_RE_WIDTH 1 ++#define MAC_RFCR_PFCE_INDEX 8 ++#define MAC_RFCR_PFCE_WIDTH 1 ++#define MAC_RFCR_RFE_INDEX 0 ++#define MAC_RFCR_RFE_WIDTH 1 ++#define MAC_RFCR_UP_INDEX 1 ++#define MAC_RFCR_UP_WIDTH 1 ++#define MAC_RQC0R_RXQ0EN_INDEX 0 ++#define MAC_RQC0R_RXQ0EN_WIDTH 2 ++#define MAC_SSIR_SNSINC_INDEX 8 ++#define MAC_SSIR_SNSINC_WIDTH 8 ++#define MAC_SSIR_SSINC_INDEX 16 ++#define MAC_SSIR_SSINC_WIDTH 8 ++#define MAC_TCR_SS_INDEX 29 ++#define MAC_TCR_SS_WIDTH 2 ++#define MAC_TCR_TE_INDEX 0 ++#define MAC_TCR_TE_WIDTH 1 ++#define MAC_TSCR_AV8021ASMEN_INDEX 28 ++#define MAC_TSCR_AV8021ASMEN_WIDTH 1 ++#define MAC_TSCR_SNAPTYPSEL_INDEX 16 ++#define MAC_TSCR_SNAPTYPSEL_WIDTH 2 ++#define MAC_TSCR_TSADDREG_INDEX 5 ++#define MAC_TSCR_TSADDREG_WIDTH 1 ++#define MAC_TSCR_TSCFUPDT_INDEX 1 ++#define MAC_TSCR_TSCFUPDT_WIDTH 1 ++#define MAC_TSCR_TSCTRLSSR_INDEX 9 ++#define MAC_TSCR_TSCTRLSSR_WIDTH 1 ++#define MAC_TSCR_TSENA_INDEX 0 ++#define MAC_TSCR_TSENA_WIDTH 1 ++#define MAC_TSCR_TSENALL_INDEX 8 ++#define MAC_TSCR_TSENALL_WIDTH 1 ++#define MAC_TSCR_TSEVNTENA_INDEX 14 ++#define MAC_TSCR_TSEVNTENA_WIDTH 1 ++#define MAC_TSCR_TSINIT_INDEX 2 ++#define MAC_TSCR_TSINIT_WIDTH 1 ++#define MAC_TSCR_TSIPENA_INDEX 11 ++#define MAC_TSCR_TSIPENA_WIDTH 1 ++#define MAC_TSCR_TSIPV4ENA_INDEX 13 ++#define MAC_TSCR_TSIPV4ENA_WIDTH 1 ++#define MAC_TSCR_TSIPV6ENA_INDEX 12 ++#define MAC_TSCR_TSIPV6ENA_WIDTH 1 ++#define MAC_TSCR_TSMSTRENA_INDEX 15 ++#define MAC_TSCR_TSMSTRENA_WIDTH 1 ++#define MAC_TSCR_TSVER2ENA_INDEX 10 ++#define MAC_TSCR_TSVER2ENA_WIDTH 1 ++#define MAC_TSCR_TXTSSTSM_INDEX 24 ++#define MAC_TSCR_TXTSSTSM_WIDTH 1 ++#define MAC_TSSR_TXTSC_INDEX 15 ++#define MAC_TSSR_TXTSC_WIDTH 1 ++#define MAC_TXSNR_TXTSSTSMIS_INDEX 31 ++#define MAC_TXSNR_TXTSSTSMIS_WIDTH 1 ++#define MAC_VLANHTR_VLHT_INDEX 0 ++#define MAC_VLANHTR_VLHT_WIDTH 16 ++#define MAC_VLANIR_VLTI_INDEX 20 ++#define MAC_VLANIR_VLTI_WIDTH 1 ++#define MAC_VLANIR_CSVL_INDEX 19 ++#define MAC_VLANIR_CSVL_WIDTH 1 ++#define MAC_VLANTR_DOVLTC_INDEX 20 ++#define MAC_VLANTR_DOVLTC_WIDTH 1 ++#define MAC_VLANTR_ERSVLM_INDEX 19 ++#define MAC_VLANTR_ERSVLM_WIDTH 1 ++#define MAC_VLANTR_ESVL_INDEX 18 ++#define MAC_VLANTR_ESVL_WIDTH 1 ++#define MAC_VLANTR_ETV_INDEX 16 ++#define MAC_VLANTR_ETV_WIDTH 1 ++#define MAC_VLANTR_EVLS_INDEX 21 ++#define MAC_VLANTR_EVLS_WIDTH 2 ++#define MAC_VLANTR_EVLRXS_INDEX 24 ++#define MAC_VLANTR_EVLRXS_WIDTH 1 ++#define MAC_VLANTR_VL_INDEX 0 ++#define MAC_VLANTR_VL_WIDTH 16 ++#define MAC_VLANTR_VTHM_INDEX 25 ++#define MAC_VLANTR_VTHM_WIDTH 1 ++#define MAC_VLANTR_VTIM_INDEX 17 ++#define MAC_VLANTR_VTIM_WIDTH 1 ++#define MAC_VR_DEVID_INDEX 8 ++#define MAC_VR_DEVID_WIDTH 8 ++#define MAC_VR_SNPSVER_INDEX 0 ++#define MAC_VR_SNPSVER_WIDTH 8 ++#define MAC_VR_USERVER_INDEX 16 ++#define MAC_VR_USERVER_WIDTH 8 ++ ++/* MMC register offsets */ ++#define MMC_CR 0x0800 ++#define MMC_RISR 0x0804 ++#define MMC_TISR 0x0808 ++#define MMC_RIER 0x080c ++#define MMC_TIER 0x0810 ++#define MMC_TXOCTETCOUNT_GB_LO 0x0814 ++#define MMC_TXOCTETCOUNT_GB_HI 0x0818 ++#define MMC_TXFRAMECOUNT_GB_LO 0x081c ++#define MMC_TXFRAMECOUNT_GB_HI 0x0820 ++#define MMC_TXBROADCASTFRAMES_G_LO 0x0824 ++#define MMC_TXBROADCASTFRAMES_G_HI 0x0828 ++#define MMC_TXMULTICASTFRAMES_G_LO 0x082c ++#define MMC_TXMULTICASTFRAMES_G_HI 0x0830 ++#define MMC_TX64OCTETS_GB_LO 0x0834 ++#define MMC_TX64OCTETS_GB_HI 0x0838 ++#define MMC_TX65TO127OCTETS_GB_LO 0x083c ++#define MMC_TX65TO127OCTETS_GB_HI 0x0840 ++#define MMC_TX128TO255OCTETS_GB_LO 0x0844 ++#define MMC_TX128TO255OCTETS_GB_HI 0x0848 ++#define MMC_TX256TO511OCTETS_GB_LO 0x084c ++#define MMC_TX256TO511OCTETS_GB_HI 0x0850 ++#define MMC_TX512TO1023OCTETS_GB_LO 0x0854 ++#define MMC_TX512TO1023OCTETS_GB_HI 0x0858 ++#define MMC_TX1024TOMAXOCTETS_GB_LO 0x085c ++#define MMC_TX1024TOMAXOCTETS_GB_HI 0x0860 ++#define MMC_TXUNICASTFRAMES_GB_LO 0x0864 ++#define MMC_TXUNICASTFRAMES_GB_HI 0x0868 ++#define MMC_TXMULTICASTFRAMES_GB_LO 0x086c ++#define MMC_TXMULTICASTFRAMES_GB_HI 0x0870 ++#define MMC_TXBROADCASTFRAMES_GB_LO 0x0874 ++#define MMC_TXBROADCASTFRAMES_GB_HI 0x0878 ++#define MMC_TXUNDERFLOWERROR_LO 0x087c ++#define MMC_TXUNDERFLOWERROR_HI 0x0880 ++#define MMC_TXOCTETCOUNT_G_LO 0x0884 ++#define MMC_TXOCTETCOUNT_G_HI 0x0888 ++#define MMC_TXFRAMECOUNT_G_LO 0x088c ++#define MMC_TXFRAMECOUNT_G_HI 0x0890 ++#define MMC_TXPAUSEFRAMES_LO 0x0894 ++#define MMC_TXPAUSEFRAMES_HI 0x0898 ++#define MMC_TXVLANFRAMES_G_LO 0x089c ++#define MMC_TXVLANFRAMES_G_HI 0x08a0 ++#define MMC_RXFRAMECOUNT_GB_LO 0x0900 ++#define MMC_RXFRAMECOUNT_GB_HI 0x0904 ++#define MMC_RXOCTETCOUNT_GB_LO 0x0908 ++#define MMC_RXOCTETCOUNT_GB_HI 0x090c ++#define MMC_RXOCTETCOUNT_G_LO 0x0910 ++#define MMC_RXOCTETCOUNT_G_HI 0x0914 ++#define MMC_RXBROADCASTFRAMES_G_LO 0x0918 ++#define MMC_RXBROADCASTFRAMES_G_HI 0x091c ++#define MMC_RXMULTICASTFRAMES_G_LO 0x0920 ++#define MMC_RXMULTICASTFRAMES_G_HI 0x0924 ++#define MMC_RXCRCERROR_LO 0x0928 ++#define MMC_RXCRCERROR_HI 0x092c ++#define MMC_RXRUNTERROR 0x0930 ++#define MMC_RXJABBERERROR 0x0934 ++#define MMC_RXUNDERSIZE_G 0x0938 ++#define MMC_RXOVERSIZE_G 0x093c ++#define MMC_RX64OCTETS_GB_LO 0x0940 ++#define MMC_RX64OCTETS_GB_HI 0x0944 ++#define MMC_RX65TO127OCTETS_GB_LO 0x0948 ++#define MMC_RX65TO127OCTETS_GB_HI 0x094c ++#define MMC_RX128TO255OCTETS_GB_LO 0x0950 ++#define MMC_RX128TO255OCTETS_GB_HI 0x0954 ++#define MMC_RX256TO511OCTETS_GB_LO 0x0958 ++#define MMC_RX256TO511OCTETS_GB_HI 0x095c ++#define MMC_RX512TO1023OCTETS_GB_LO 0x0960 ++#define MMC_RX512TO1023OCTETS_GB_HI 0x0964 ++#define MMC_RX1024TOMAXOCTETS_GB_LO 0x0968 ++#define MMC_RX1024TOMAXOCTETS_GB_HI 0x096c ++#define MMC_RXUNICASTFRAMES_G_LO 0x0970 ++#define MMC_RXUNICASTFRAMES_G_HI 0x0974 ++#define MMC_RXLENGTHERROR_LO 0x0978 ++#define MMC_RXLENGTHERROR_HI 0x097c ++#define MMC_RXOUTOFRANGETYPE_LO 0x0980 ++#define MMC_RXOUTOFRANGETYPE_HI 0x0984 ++#define MMC_RXPAUSEFRAMES_LO 0x0988 ++#define MMC_RXPAUSEFRAMES_HI 0x098c ++#define MMC_RXFIFOOVERFLOW_LO 0x0990 ++#define MMC_RXFIFOOVERFLOW_HI 0x0994 ++#define MMC_RXVLANFRAMES_GB_LO 0x0998 ++#define MMC_RXVLANFRAMES_GB_HI 0x099c ++#define MMC_RXWATCHDOGERROR 0x09a0 ++ ++/* MMC register entry bit positions and sizes */ ++#define MMC_CR_CR_INDEX 0 ++#define MMC_CR_CR_WIDTH 1 ++#define MMC_CR_CSR_INDEX 1 ++#define MMC_CR_CSR_WIDTH 1 ++#define MMC_CR_ROR_INDEX 2 ++#define MMC_CR_ROR_WIDTH 1 ++#define MMC_CR_MCF_INDEX 3 ++#define MMC_CR_MCF_WIDTH 1 ++#define MMC_CR_MCT_INDEX 4 ++#define MMC_CR_MCT_WIDTH 2 ++#define MMC_RIER_ALL_INTERRUPTS_INDEX 0 ++#define MMC_RIER_ALL_INTERRUPTS_WIDTH 23 ++#define MMC_RISR_RXFRAMECOUNT_GB_INDEX 0 ++#define MMC_RISR_RXFRAMECOUNT_GB_WIDTH 1 ++#define MMC_RISR_RXOCTETCOUNT_GB_INDEX 1 ++#define MMC_RISR_RXOCTETCOUNT_GB_WIDTH 1 ++#define MMC_RISR_RXOCTETCOUNT_G_INDEX 2 ++#define MMC_RISR_RXOCTETCOUNT_G_WIDTH 1 ++#define MMC_RISR_RXBROADCASTFRAMES_G_INDEX 3 ++#define MMC_RISR_RXBROADCASTFRAMES_G_WIDTH 1 ++#define MMC_RISR_RXMULTICASTFRAMES_G_INDEX 4 ++#define MMC_RISR_RXMULTICASTFRAMES_G_WIDTH 1 ++#define MMC_RISR_RXCRCERROR_INDEX 5 ++#define MMC_RISR_RXCRCERROR_WIDTH 1 ++#define MMC_RISR_RXRUNTERROR_INDEX 6 ++#define MMC_RISR_RXRUNTERROR_WIDTH 1 ++#define MMC_RISR_RXJABBERERROR_INDEX 7 ++#define MMC_RISR_RXJABBERERROR_WIDTH 1 ++#define MMC_RISR_RXUNDERSIZE_G_INDEX 8 ++#define MMC_RISR_RXUNDERSIZE_G_WIDTH 1 ++#define MMC_RISR_RXOVERSIZE_G_INDEX 9 ++#define MMC_RISR_RXOVERSIZE_G_WIDTH 1 ++#define MMC_RISR_RX64OCTETS_GB_INDEX 10 ++#define MMC_RISR_RX64OCTETS_GB_WIDTH 1 ++#define MMC_RISR_RX65TO127OCTETS_GB_INDEX 11 ++#define MMC_RISR_RX65TO127OCTETS_GB_WIDTH 1 ++#define MMC_RISR_RX128TO255OCTETS_GB_INDEX 12 ++#define MMC_RISR_RX128TO255OCTETS_GB_WIDTH 1 ++#define MMC_RISR_RX256TO511OCTETS_GB_INDEX 13 ++#define MMC_RISR_RX256TO511OCTETS_GB_WIDTH 1 ++#define MMC_RISR_RX512TO1023OCTETS_GB_INDEX 14 ++#define MMC_RISR_RX512TO1023OCTETS_GB_WIDTH 1 ++#define MMC_RISR_RX1024TOMAXOCTETS_GB_INDEX 15 ++#define MMC_RISR_RX1024TOMAXOCTETS_GB_WIDTH 1 ++#define MMC_RISR_RXUNICASTFRAMES_G_INDEX 16 ++#define MMC_RISR_RXUNICASTFRAMES_G_WIDTH 1 ++#define MMC_RISR_RXLENGTHERROR_INDEX 17 ++#define MMC_RISR_RXLENGTHERROR_WIDTH 1 ++#define MMC_RISR_RXOUTOFRANGETYPE_INDEX 18 ++#define MMC_RISR_RXOUTOFRANGETYPE_WIDTH 1 ++#define MMC_RISR_RXPAUSEFRAMES_INDEX 19 ++#define MMC_RISR_RXPAUSEFRAMES_WIDTH 1 ++#define MMC_RISR_RXFIFOOVERFLOW_INDEX 20 ++#define MMC_RISR_RXFIFOOVERFLOW_WIDTH 1 ++#define MMC_RISR_RXVLANFRAMES_GB_INDEX 21 ++#define MMC_RISR_RXVLANFRAMES_GB_WIDTH 1 ++#define MMC_RISR_RXWATCHDOGERROR_INDEX 22 ++#define MMC_RISR_RXWATCHDOGERROR_WIDTH 1 ++#define MMC_TIER_ALL_INTERRUPTS_INDEX 0 ++#define MMC_TIER_ALL_INTERRUPTS_WIDTH 18 ++#define MMC_TISR_TXOCTETCOUNT_GB_INDEX 0 ++#define MMC_TISR_TXOCTETCOUNT_GB_WIDTH 1 ++#define MMC_TISR_TXFRAMECOUNT_GB_INDEX 1 ++#define MMC_TISR_TXFRAMECOUNT_GB_WIDTH 1 ++#define MMC_TISR_TXBROADCASTFRAMES_G_INDEX 2 ++#define MMC_TISR_TXBROADCASTFRAMES_G_WIDTH 1 ++#define MMC_TISR_TXMULTICASTFRAMES_G_INDEX 3 ++#define MMC_TISR_TXMULTICASTFRAMES_G_WIDTH 1 ++#define MMC_TISR_TX64OCTETS_GB_INDEX 4 ++#define MMC_TISR_TX64OCTETS_GB_WIDTH 1 ++#define MMC_TISR_TX65TO127OCTETS_GB_INDEX 5 ++#define MMC_TISR_TX65TO127OCTETS_GB_WIDTH 1 ++#define MMC_TISR_TX128TO255OCTETS_GB_INDEX 6 ++#define MMC_TISR_TX128TO255OCTETS_GB_WIDTH 1 ++#define MMC_TISR_TX256TO511OCTETS_GB_INDEX 7 ++#define MMC_TISR_TX256TO511OCTETS_GB_WIDTH 1 ++#define MMC_TISR_TX512TO1023OCTETS_GB_INDEX 8 ++#define MMC_TISR_TX512TO1023OCTETS_GB_WIDTH 1 ++#define MMC_TISR_TX1024TOMAXOCTETS_GB_INDEX 9 ++#define MMC_TISR_TX1024TOMAXOCTETS_GB_WIDTH 1 ++#define MMC_TISR_TXUNICASTFRAMES_GB_INDEX 10 ++#define MMC_TISR_TXUNICASTFRAMES_GB_WIDTH 1 ++#define MMC_TISR_TXMULTICASTFRAMES_GB_INDEX 11 ++#define MMC_TISR_TXMULTICASTFRAMES_GB_WIDTH 1 ++#define MMC_TISR_TXBROADCASTFRAMES_GB_INDEX 12 ++#define MMC_TISR_TXBROADCASTFRAMES_GB_WIDTH 1 ++#define MMC_TISR_TXUNDERFLOWERROR_INDEX 13 ++#define MMC_TISR_TXUNDERFLOWERROR_WIDTH 1 ++#define MMC_TISR_TXOCTETCOUNT_G_INDEX 14 ++#define MMC_TISR_TXOCTETCOUNT_G_WIDTH 1 ++#define MMC_TISR_TXFRAMECOUNT_G_INDEX 15 ++#define MMC_TISR_TXFRAMECOUNT_G_WIDTH 1 ++#define MMC_TISR_TXPAUSEFRAMES_INDEX 16 ++#define MMC_TISR_TXPAUSEFRAMES_WIDTH 1 ++#define MMC_TISR_TXVLANFRAMES_G_INDEX 17 ++#define MMC_TISR_TXVLANFRAMES_G_WIDTH 1 ++ ++/* MTL register offsets */ ++#define MTL_OMR 0x1000 ++#define MTL_FDCR 0x1008 ++#define MTL_FDSR 0x100c ++#define MTL_FDDR 0x1010 ++#define MTL_ISR 0x1020 ++#define MTL_RQDCM0R 0x1030 ++#define MTL_TCPM0R 0x1040 ++#define MTL_TCPM1R 0x1044 ++ ++#define MTL_RQDCM_INC 4 ++#define MTL_RQDCM_Q_PER_REG 4 ++#define MTL_TCPM_INC 4 ++#define MTL_TCPM_TC_PER_REG 4 ++ ++/* MTL register entry bit positions and sizes */ ++#define MTL_OMR_ETSALG_INDEX 5 ++#define MTL_OMR_ETSALG_WIDTH 2 ++#define MTL_OMR_RAA_INDEX 2 ++#define MTL_OMR_RAA_WIDTH 1 ++ ++/* MTL queue register offsets ++ * Multiple queues can be active. The first queue has registers ++ * that begin at 0x1100. Each subsequent queue has registers that ++ * are accessed using an offset of 0x80 from the previous queue. ++ */ ++#define MTL_Q_BASE 0x1100 ++#define MTL_Q_INC 0x80 ++ ++#define MTL_Q_TQOMR 0x00 ++#define MTL_Q_TQUR 0x04 ++#define MTL_Q_TQDR 0x08 ++#define MTL_Q_RQOMR 0x40 ++#define MTL_Q_RQMPOCR 0x44 ++#define MTL_Q_RQDR 0x4c ++#define MTL_Q_IER 0x70 ++#define MTL_Q_ISR 0x74 ++ ++/* MTL queue register entry bit positions and sizes */ ++#define MTL_Q_RQOMR_EHFC_INDEX 7 ++#define MTL_Q_RQOMR_EHFC_WIDTH 1 ++#define MTL_Q_RQOMR_RFA_INDEX 8 ++#define MTL_Q_RQOMR_RFA_WIDTH 3 ++#define MTL_Q_RQOMR_RFD_INDEX 13 ++#define MTL_Q_RQOMR_RFD_WIDTH 3 ++#define MTL_Q_RQOMR_RQS_INDEX 16 ++#define MTL_Q_RQOMR_RQS_WIDTH 9 ++#define MTL_Q_RQOMR_RSF_INDEX 5 ++#define MTL_Q_RQOMR_RSF_WIDTH 1 ++#define MTL_Q_RQOMR_RTC_INDEX 0 ++#define MTL_Q_RQOMR_RTC_WIDTH 2 ++#define MTL_Q_TQOMR_FTQ_INDEX 0 ++#define MTL_Q_TQOMR_FTQ_WIDTH 1 ++#define MTL_Q_TQOMR_Q2TCMAP_INDEX 8 ++#define MTL_Q_TQOMR_Q2TCMAP_WIDTH 3 ++#define MTL_Q_TQOMR_TQS_INDEX 16 ++#define MTL_Q_TQOMR_TQS_WIDTH 10 ++#define MTL_Q_TQOMR_TSF_INDEX 1 ++#define MTL_Q_TQOMR_TSF_WIDTH 1 ++#define MTL_Q_TQOMR_TTC_INDEX 4 ++#define MTL_Q_TQOMR_TTC_WIDTH 3 ++#define MTL_Q_TQOMR_TXQEN_INDEX 2 ++#define MTL_Q_TQOMR_TXQEN_WIDTH 2 ++ ++/* MTL queue register value */ ++#define MTL_RSF_DISABLE 0x00 ++#define MTL_RSF_ENABLE 0x01 ++#define MTL_TSF_DISABLE 0x00 ++#define MTL_TSF_ENABLE 0x01 ++ ++#define MTL_RX_THRESHOLD_64 0x00 ++#define MTL_RX_THRESHOLD_96 0x02 ++#define MTL_RX_THRESHOLD_128 0x03 ++#define MTL_TX_THRESHOLD_32 0x01 ++#define MTL_TX_THRESHOLD_64 0x00 ++#define MTL_TX_THRESHOLD_96 0x02 ++#define MTL_TX_THRESHOLD_128 0x03 ++#define MTL_TX_THRESHOLD_192 0x04 ++#define MTL_TX_THRESHOLD_256 0x05 ++#define MTL_TX_THRESHOLD_384 0x06 ++#define MTL_TX_THRESHOLD_512 0x07 ++ ++#define MTL_ETSALG_WRR 0x00 ++#define MTL_ETSALG_WFQ 0x01 ++#define MTL_ETSALG_DWRR 0x02 ++#define MTL_RAA_SP 0x00 ++#define MTL_RAA_WSP 0x01 ++ ++#define MTL_Q_DISABLED 0x00 ++#define MTL_Q_ENABLED 0x02 ++ ++ ++/* MTL traffic class register offsets ++ * Multiple traffic classes can be active. The first class has registers ++ * that begin at 0x1100. Each subsequent queue has registers that ++ * are accessed using an offset of 0x80 from the previous queue. ++ */ ++#define MTL_TC_BASE MTL_Q_BASE ++#define MTL_TC_INC MTL_Q_INC ++ ++#define MTL_TC_ETSCR 0x10 ++#define MTL_TC_ETSSR 0x14 ++#define MTL_TC_QWR 0x18 ++ ++/* MTL traffic class register entry bit positions and sizes */ ++#define MTL_TC_ETSCR_TSA_INDEX 0 ++#define MTL_TC_ETSCR_TSA_WIDTH 2 ++#define MTL_TC_QWR_QW_INDEX 0 ++#define MTL_TC_QWR_QW_WIDTH 21 ++ ++/* MTL traffic class register value */ ++#define MTL_TSA_SP 0x00 ++#define MTL_TSA_ETS 0x02 ++ ++ ++/* PCS MMD select register offset ++ * The MMD select register is used for accessing PCS registers ++ * when the underlying APB3 interface is using indirect addressing. ++ * Indirect addressing requires accessing registers in two phases, ++ * an address phase and a data phase. The address phases requires ++ * writing an address selection value to the MMD select regiesters. ++ */ ++#define PCS_MMD_SELECT 0xff ++ ++ ++/* Descriptor/Packet entry bit positions and sizes */ ++#define RX_PACKET_ERRORS_CRC_INDEX 2 ++#define RX_PACKET_ERRORS_CRC_WIDTH 1 ++#define RX_PACKET_ERRORS_FRAME_INDEX 3 ++#define RX_PACKET_ERRORS_FRAME_WIDTH 1 ++#define RX_PACKET_ERRORS_LENGTH_INDEX 0 ++#define RX_PACKET_ERRORS_LENGTH_WIDTH 1 ++#define RX_PACKET_ERRORS_OVERRUN_INDEX 1 ++#define RX_PACKET_ERRORS_OVERRUN_WIDTH 1 ++ ++#define RX_PACKET_ATTRIBUTES_CSUM_DONE_INDEX 0 ++#define RX_PACKET_ATTRIBUTES_CSUM_DONE_WIDTH 1 ++#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX 1 ++#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1 ++#define RX_PACKET_ATTRIBUTES_INCOMPLETE_INDEX 2 ++#define RX_PACKET_ATTRIBUTES_INCOMPLETE_WIDTH 1 ++#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_INDEX 3 ++#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_WIDTH 1 ++#define RX_PACKET_ATTRIBUTES_CONTEXT_INDEX 4 ++#define RX_PACKET_ATTRIBUTES_CONTEXT_WIDTH 1 ++#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_INDEX 5 ++#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_WIDTH 1 ++ ++#define RX_NORMAL_DESC0_OVT_INDEX 0 ++#define RX_NORMAL_DESC0_OVT_WIDTH 16 ++#define RX_NORMAL_DESC3_CDA_INDEX 27 ++#define RX_NORMAL_DESC3_CDA_WIDTH 1 ++#define RX_NORMAL_DESC3_CTXT_INDEX 30 ++#define RX_NORMAL_DESC3_CTXT_WIDTH 1 ++#define RX_NORMAL_DESC3_ES_INDEX 15 ++#define RX_NORMAL_DESC3_ES_WIDTH 1 ++#define RX_NORMAL_DESC3_ETLT_INDEX 16 ++#define RX_NORMAL_DESC3_ETLT_WIDTH 4 ++#define RX_NORMAL_DESC3_INTE_INDEX 30 ++#define RX_NORMAL_DESC3_INTE_WIDTH 1 ++#define RX_NORMAL_DESC3_LD_INDEX 28 ++#define RX_NORMAL_DESC3_LD_WIDTH 1 ++#define RX_NORMAL_DESC3_OWN_INDEX 31 ++#define RX_NORMAL_DESC3_OWN_WIDTH 1 ++#define RX_NORMAL_DESC3_PL_INDEX 0 ++#define RX_NORMAL_DESC3_PL_WIDTH 14 ++ ++#define RX_CONTEXT_DESC3_TSA_INDEX 4 ++#define RX_CONTEXT_DESC3_TSA_WIDTH 1 ++#define RX_CONTEXT_DESC3_TSD_INDEX 6 ++#define RX_CONTEXT_DESC3_TSD_WIDTH 1 ++ ++#define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_INDEX 0 ++#define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_WIDTH 1 ++#define TX_PACKET_ATTRIBUTES_TSO_ENABLE_INDEX 1 ++#define TX_PACKET_ATTRIBUTES_TSO_ENABLE_WIDTH 1 ++#define TX_PACKET_ATTRIBUTES_VLAN_CTAG_INDEX 2 ++#define TX_PACKET_ATTRIBUTES_VLAN_CTAG_WIDTH 1 ++#define TX_PACKET_ATTRIBUTES_PTP_INDEX 3 ++#define TX_PACKET_ATTRIBUTES_PTP_WIDTH 1 ++ ++#define TX_CONTEXT_DESC2_MSS_INDEX 0 ++#define TX_CONTEXT_DESC2_MSS_WIDTH 15 ++#define TX_CONTEXT_DESC3_CTXT_INDEX 30 ++#define TX_CONTEXT_DESC3_CTXT_WIDTH 1 ++#define TX_CONTEXT_DESC3_TCMSSV_INDEX 26 ++#define TX_CONTEXT_DESC3_TCMSSV_WIDTH 1 ++#define TX_CONTEXT_DESC3_VLTV_INDEX 16 ++#define TX_CONTEXT_DESC3_VLTV_WIDTH 1 ++#define TX_CONTEXT_DESC3_VT_INDEX 0 ++#define TX_CONTEXT_DESC3_VT_WIDTH 16 ++ ++#define TX_NORMAL_DESC2_HL_B1L_INDEX 0 ++#define TX_NORMAL_DESC2_HL_B1L_WIDTH 14 ++#define TX_NORMAL_DESC2_IC_INDEX 31 ++#define TX_NORMAL_DESC2_IC_WIDTH 1 ++#define TX_NORMAL_DESC2_TTSE_INDEX 30 ++#define TX_NORMAL_DESC2_TTSE_WIDTH 1 ++#define TX_NORMAL_DESC2_VTIR_INDEX 14 ++#define TX_NORMAL_DESC2_VTIR_WIDTH 2 ++#define TX_NORMAL_DESC3_CIC_INDEX 16 ++#define TX_NORMAL_DESC3_CIC_WIDTH 2 ++#define TX_NORMAL_DESC3_CPC_INDEX 26 ++#define TX_NORMAL_DESC3_CPC_WIDTH 2 ++#define TX_NORMAL_DESC3_CTXT_INDEX 30 ++#define TX_NORMAL_DESC3_CTXT_WIDTH 1 ++#define TX_NORMAL_DESC3_FD_INDEX 29 ++#define TX_NORMAL_DESC3_FD_WIDTH 1 ++#define TX_NORMAL_DESC3_FL_INDEX 0 ++#define TX_NORMAL_DESC3_FL_WIDTH 15 ++#define TX_NORMAL_DESC3_LD_INDEX 28 ++#define TX_NORMAL_DESC3_LD_WIDTH 1 ++#define TX_NORMAL_DESC3_OWN_INDEX 31 ++#define TX_NORMAL_DESC3_OWN_WIDTH 1 ++#define TX_NORMAL_DESC3_TCPHDRLEN_INDEX 19 ++#define TX_NORMAL_DESC3_TCPHDRLEN_WIDTH 4 ++#define TX_NORMAL_DESC3_TCPPL_INDEX 0 ++#define TX_NORMAL_DESC3_TCPPL_WIDTH 18 ++#define TX_NORMAL_DESC3_TSE_INDEX 18 ++#define TX_NORMAL_DESC3_TSE_WIDTH 1 ++ ++#define TX_NORMAL_DESC2_VLAN_INSERT 0x2 ++ ++/* MDIO undefined or vendor specific registers */ ++#ifndef MDIO_AN_COMP_STAT ++#define MDIO_AN_COMP_STAT 0x0030 ++#endif ++ ++ ++/* Bit setting and getting macros ++ * The get macro will extract the current bit field value from within ++ * the variable ++ * ++ * The set macro will clear the current bit field value within the ++ * variable and then set the bit field of the variable to the ++ * specified value ++ */ ++#define GET_BITS(_var, _index, _width) \ ++ (((_var) >> (_index)) & ((0x1 << (_width)) - 1)) ++ ++#define SET_BITS(_var, _index, _width, _val) \ ++do { \ ++ (_var) &= ~(((0x1 << (_width)) - 1) << (_index)); \ ++ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \ ++} while (0) ++ ++#define GET_BITS_LE(_var, _index, _width) \ ++ ((le32_to_cpu((_var)) >> (_index)) & ((0x1 << (_width)) - 1)) ++ ++#define SET_BITS_LE(_var, _index, _width, _val) \ ++do { \ ++ (_var) &= cpu_to_le32(~(((0x1 << (_width)) - 1) << (_index))); \ ++ (_var) |= cpu_to_le32((((_val) & \ ++ ((0x1 << (_width)) - 1)) << (_index))); \ ++} while (0) ++ ++ ++/* Bit setting and getting macros based on register fields ++ * The get macro uses the bit field definitions formed using the input ++ * names to extract the current bit field value from within the ++ * variable ++ * ++ * The set macro uses the bit field definitions formed using the input ++ * names to set the bit field of the variable to the specified value ++ */ ++#define XGMAC_GET_BITS(_var, _prefix, _field) \ ++ GET_BITS((_var), \ ++ _prefix##_##_field##_INDEX, \ ++ _prefix##_##_field##_WIDTH) ++ ++#define XGMAC_SET_BITS(_var, _prefix, _field, _val) \ ++ SET_BITS((_var), \ ++ _prefix##_##_field##_INDEX, \ ++ _prefix##_##_field##_WIDTH, (_val)) ++ ++#define XGMAC_GET_BITS_LE(_var, _prefix, _field) \ ++ GET_BITS_LE((_var), \ ++ _prefix##_##_field##_INDEX, \ ++ _prefix##_##_field##_WIDTH) ++ ++#define XGMAC_SET_BITS_LE(_var, _prefix, _field, _val) \ ++ SET_BITS_LE((_var), \ ++ _prefix##_##_field##_INDEX, \ ++ _prefix##_##_field##_WIDTH, (_val)) ++ ++ ++/* Macros for reading or writing registers ++ * The ioread macros will get bit fields or full values using the ++ * register definitions formed using the input names ++ * ++ * The iowrite macros will set bit fields or full values using the ++ * register definitions formed using the input names ++ */ ++#define XGMAC_IOREAD(_pdata, _reg) \ ++ ioread32((_pdata)->xgmac_regs + _reg) ++ ++#define XGMAC_IOREAD_BITS(_pdata, _reg, _field) \ ++ GET_BITS(XGMAC_IOREAD((_pdata), _reg), \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH) ++ ++#define XGMAC_IOWRITE(_pdata, _reg, _val) \ ++ iowrite32((_val), (_pdata)->xgmac_regs + _reg) ++ ++#define XGMAC_IOWRITE_BITS(_pdata, _reg, _field, _val) \ ++do { \ ++ u32 reg_val = XGMAC_IOREAD((_pdata), _reg); \ ++ SET_BITS(reg_val, \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH, (_val)); \ ++ XGMAC_IOWRITE((_pdata), _reg, reg_val); \ ++} while (0) ++ ++ ++/* Macros for reading or writing MTL queue or traffic class registers ++ * Similar to the standard read and write macros except that the ++ * base register value is calculated by the queue or traffic class number ++ */ ++#define XGMAC_MTL_IOREAD(_pdata, _n, _reg) \ ++ ioread32((_pdata)->xgmac_regs + \ ++ MTL_Q_BASE + ((_n) * MTL_Q_INC) + _reg) ++ ++#define XGMAC_MTL_IOREAD_BITS(_pdata, _n, _reg, _field) \ ++ GET_BITS(XGMAC_MTL_IOREAD((_pdata), (_n), _reg), \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH) ++ ++#define XGMAC_MTL_IOWRITE(_pdata, _n, _reg, _val) \ ++ iowrite32((_val), (_pdata)->xgmac_regs + \ ++ MTL_Q_BASE + ((_n) * MTL_Q_INC) + _reg) ++ ++#define XGMAC_MTL_IOWRITE_BITS(_pdata, _n, _reg, _field, _val) \ ++do { \ ++ u32 reg_val = XGMAC_MTL_IOREAD((_pdata), (_n), _reg); \ ++ SET_BITS(reg_val, \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH, (_val)); \ ++ XGMAC_MTL_IOWRITE((_pdata), (_n), _reg, reg_val); \ ++} while (0) ++ ++ ++/* Macros for reading or writing DMA channel registers ++ * Similar to the standard read and write macros except that the ++ * base register value is obtained from the ring ++ */ ++#define XGMAC_DMA_IOREAD(_channel, _reg) \ ++ ioread32((_channel)->dma_regs + _reg) ++ ++#define XGMAC_DMA_IOREAD_BITS(_channel, _reg, _field) \ ++ GET_BITS(XGMAC_DMA_IOREAD((_channel), _reg), \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH) ++ ++#define XGMAC_DMA_IOWRITE(_channel, _reg, _val) \ ++ iowrite32((_val), (_channel)->dma_regs + _reg) ++ ++#define XGMAC_DMA_IOWRITE_BITS(_channel, _reg, _field, _val) \ ++do { \ ++ u32 reg_val = XGMAC_DMA_IOREAD((_channel), _reg); \ ++ SET_BITS(reg_val, \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH, (_val)); \ ++ XGMAC_DMA_IOWRITE((_channel), _reg, reg_val); \ ++} while (0) ++ ++ ++/* Macros for building, reading or writing register values or bits ++ * within the register values of XPCS registers. ++ */ ++#define XPCS_IOWRITE(_pdata, _off, _val) \ ++ iowrite32(_val, (_pdata)->xpcs_regs + (_off)) ++ ++#define XPCS_IOREAD(_pdata, _off) \ ++ ioread32((_pdata)->xpcs_regs + (_off)) ++ ++ ++/* Macros for building, reading or writing register values or bits ++ * using MDIO. Different from above because of the use of standardized ++ * Linux include values. No shifting is performed with the bit ++ * operations, everything works on mask values. ++ */ ++#define XMDIO_READ(_pdata, _mmd, _reg) \ ++ ((_pdata)->hw_if.read_mmd_regs((_pdata), 0, \ ++ MII_ADDR_C45 | (_mmd << 16) | ((_reg) & 0xffff))) ++ ++#define XMDIO_READ_BITS(_pdata, _mmd, _reg, _mask) \ ++ (XMDIO_READ((_pdata), _mmd, _reg) & _mask) ++ ++#define XMDIO_WRITE(_pdata, _mmd, _reg, _val) \ ++ ((_pdata)->hw_if.write_mmd_regs((_pdata), 0, \ ++ MII_ADDR_C45 | (_mmd << 16) | ((_reg) & 0xffff), (_val))) ++ ++#define XMDIO_WRITE_BITS(_pdata, _mmd, _reg, _mask, _val) \ ++do { \ ++ u32 mmd_val = XMDIO_READ((_pdata), _mmd, _reg); \ ++ mmd_val &= ~_mask; \ ++ mmd_val |= (_val); \ ++ XMDIO_WRITE((_pdata), _mmd, _reg, mmd_val); \ ++} while (0) ++ ++#endif +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c +new file mode 100644 +index 0000000..7d6a49b +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-dcb.c +@@ -0,0 +1,270 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/netdevice.h> ++#include <net/dcbnl.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static int xgbe_dcb_ieee_getets(struct net_device *netdev, ++ struct ieee_ets *ets) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ /* Set number of supported traffic classes */ ++ ets->ets_cap = pdata->hw_feat.tc_cnt; ++ ++ if (pdata->ets) { ++ ets->cbs = pdata->ets->cbs; ++ memcpy(ets->tc_tx_bw, pdata->ets->tc_tx_bw, ++ sizeof(ets->tc_tx_bw)); ++ memcpy(ets->tc_tsa, pdata->ets->tc_tsa, ++ sizeof(ets->tc_tsa)); ++ memcpy(ets->prio_tc, pdata->ets->prio_tc, ++ sizeof(ets->prio_tc)); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_dcb_ieee_setets(struct net_device *netdev, ++ struct ieee_ets *ets) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ unsigned int i, tc_ets, tc_ets_weight; ++ ++ tc_ets = 0; ++ tc_ets_weight = 0; ++ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { ++ DBGPR(" TC%u: tx_bw=%hhu, rx_bw=%hhu, tsa=%hhu\n", i, ++ ets->tc_tx_bw[i], ets->tc_rx_bw[i], ets->tc_tsa[i]); ++ DBGPR(" PRIO%u: TC=%hhu\n", i, ets->prio_tc[i]); ++ ++ if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && ++ (i >= pdata->hw_feat.tc_cnt)) ++ return -EINVAL; ++ ++ if (ets->prio_tc[i] >= pdata->hw_feat.tc_cnt) ++ return -EINVAL; ++ ++ switch (ets->tc_tsa[i]) { ++ case IEEE_8021QAZ_TSA_STRICT: ++ break; ++ case IEEE_8021QAZ_TSA_ETS: ++ tc_ets = 1; ++ tc_ets_weight += ets->tc_tx_bw[i]; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ /* Weights must add up to 100% */ ++ if (tc_ets && (tc_ets_weight != 100)) ++ return -EINVAL; ++ ++ if (!pdata->ets) { ++ pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets), ++ GFP_KERNEL); ++ if (!pdata->ets) ++ return -ENOMEM; ++ } ++ ++ memcpy(pdata->ets, ets, sizeof(*pdata->ets)); ++ ++ pdata->hw_if.config_dcb_tc(pdata); ++ ++ return 0; ++} ++ ++static int xgbe_dcb_ieee_getpfc(struct net_device *netdev, ++ struct ieee_pfc *pfc) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ /* Set number of supported PFC traffic classes */ ++ pfc->pfc_cap = pdata->hw_feat.tc_cnt; ++ ++ if (pdata->pfc) { ++ pfc->pfc_en = pdata->pfc->pfc_en; ++ pfc->mbc = pdata->pfc->mbc; ++ pfc->delay = pdata->pfc->delay; ++ } ++ ++ return 0; ++} ++ ++static int xgbe_dcb_ieee_setpfc(struct net_device *netdev, ++ struct ieee_pfc *pfc) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ DBGPR(" cap=%hhu, en=%hhx, mbc=%hhu, delay=%hhu\n", ++ pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay); ++ ++ if (!pdata->pfc) { ++ pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc), ++ GFP_KERNEL); ++ if (!pdata->pfc) ++ return -ENOMEM; ++ } ++ ++ memcpy(pdata->pfc, pfc, sizeof(*pdata->pfc)); ++ ++ pdata->hw_if.config_dcb_pfc(pdata); ++ ++ return 0; ++} ++ ++static u8 xgbe_dcb_getdcbx(struct net_device *netdev) ++{ ++ return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; ++} ++ ++static u8 xgbe_dcb_setdcbx(struct net_device *netdev, u8 dcbx) ++{ ++ u8 support = xgbe_dcb_getdcbx(netdev); ++ ++ DBGPR(" DCBX=%#hhx\n", dcbx); ++ ++ if (dcbx & ~support) ++ return 1; ++ ++ if ((dcbx & support) != support) ++ return 1; ++ ++ return 0; ++} ++ ++static const struct dcbnl_rtnl_ops xgbe_dcbnl_ops = { ++ /* IEEE 802.1Qaz std */ ++ .ieee_getets = xgbe_dcb_ieee_getets, ++ .ieee_setets = xgbe_dcb_ieee_setets, ++ .ieee_getpfc = xgbe_dcb_ieee_getpfc, ++ .ieee_setpfc = xgbe_dcb_ieee_setpfc, ++ ++ /* DCBX configuration */ ++ .getdcbx = xgbe_dcb_getdcbx, ++ .setdcbx = xgbe_dcb_setdcbx, ++}; ++ ++const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void) ++{ ++ return &xgbe_dcbnl_ops; ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c +new file mode 100644 +index 0000000..346592d +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-debugfs.c +@@ -0,0 +1,374 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/debugfs.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static ssize_t xgbe_common_read(char __user *buffer, size_t count, ++ loff_t *ppos, unsigned int value) ++{ ++ char *buf; ++ ssize_t len; ++ ++ if (*ppos != 0) ++ return 0; ++ ++ buf = kasprintf(GFP_KERNEL, "0x%08x\n", value); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (count < strlen(buf)) { ++ kfree(buf); ++ return -ENOSPC; ++ } ++ ++ len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); ++ kfree(buf); ++ ++ return len; ++} ++ ++static ssize_t xgbe_common_write(const char __user *buffer, size_t count, ++ loff_t *ppos, unsigned int *value) ++{ ++ char workarea[32]; ++ ssize_t len; ++ int ret; ++ ++ if (*ppos != 0) ++ return 0; ++ ++ if (count >= sizeof(workarea)) ++ return -ENOSPC; ++ ++ len = simple_write_to_buffer(workarea, sizeof(workarea) - 1, ppos, ++ buffer, count); ++ if (len < 0) ++ return len; ++ ++ workarea[len] = '\0'; ++ ret = kstrtouint(workarea, 16, value); ++ if (ret) ++ return -EIO; ++ ++ return len; ++} ++ ++static ssize_t xgmac_reg_addr_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xgmac_reg); ++} ++ ++static ssize_t xgmac_reg_addr_write(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_write(buffer, count, ppos, ++ &pdata->debugfs_xgmac_reg); ++} ++ ++static ssize_t xgmac_reg_value_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ unsigned int value; ++ ++ value = XGMAC_IOREAD(pdata, pdata->debugfs_xgmac_reg); ++ ++ return xgbe_common_read(buffer, count, ppos, value); ++} ++ ++static ssize_t xgmac_reg_value_write(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ unsigned int value; ++ ssize_t len; ++ ++ len = xgbe_common_write(buffer, count, ppos, &value); ++ if (len < 0) ++ return len; ++ ++ XGMAC_IOWRITE(pdata, pdata->debugfs_xgmac_reg, value); ++ ++ return len; ++} ++ ++static const struct file_operations xgmac_reg_addr_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = xgmac_reg_addr_read, ++ .write = xgmac_reg_addr_write, ++}; ++ ++static const struct file_operations xgmac_reg_value_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = xgmac_reg_value_read, ++ .write = xgmac_reg_value_write, ++}; ++ ++static ssize_t xpcs_mmd_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_mmd); ++} ++ ++static ssize_t xpcs_mmd_write(struct file *filp, const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_write(buffer, count, ppos, ++ &pdata->debugfs_xpcs_mmd); ++} ++ ++static ssize_t xpcs_reg_addr_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_read(buffer, count, ppos, pdata->debugfs_xpcs_reg); ++} ++ ++static ssize_t xpcs_reg_addr_write(struct file *filp, const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ ++ return xgbe_common_write(buffer, count, ppos, ++ &pdata->debugfs_xpcs_reg); ++} ++ ++static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ unsigned int value; ++ ++ value = pdata->hw_if.read_mmd_regs(pdata, pdata->debugfs_xpcs_mmd, ++ pdata->debugfs_xpcs_reg); ++ ++ return xgbe_common_read(buffer, count, ppos, value); ++} ++ ++static ssize_t xpcs_reg_value_write(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct xgbe_prv_data *pdata = filp->private_data; ++ unsigned int value; ++ ssize_t len; ++ ++ len = xgbe_common_write(buffer, count, ppos, &value); ++ if (len < 0) ++ return len; ++ ++ pdata->hw_if.write_mmd_regs(pdata, pdata->debugfs_xpcs_mmd, ++ pdata->debugfs_xpcs_reg, value); ++ ++ return len; ++} ++ ++static const struct file_operations xpcs_mmd_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = xpcs_mmd_read, ++ .write = xpcs_mmd_write, ++}; ++ ++static const struct file_operations xpcs_reg_addr_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = xpcs_reg_addr_read, ++ .write = xpcs_reg_addr_write, ++}; ++ ++static const struct file_operations xpcs_reg_value_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = xpcs_reg_value_read, ++ .write = xpcs_reg_value_write, ++}; ++ ++void xgbe_debugfs_init(struct xgbe_prv_data *pdata) ++{ ++ struct dentry *pfile; ++ char *buf; ++ ++ /* Set defaults */ ++ pdata->debugfs_xgmac_reg = 0; ++ pdata->debugfs_xpcs_mmd = 1; ++ pdata->debugfs_xpcs_reg = 0; ++ ++ buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name); ++ pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL); ++ if (pdata->xgbe_debugfs == NULL) { ++ netdev_err(pdata->netdev, "debugfs_create_dir failed\n"); ++ return; ++ } ++ ++ pfile = debugfs_create_file("xgmac_register", 0600, ++ pdata->xgbe_debugfs, pdata, ++ &xgmac_reg_addr_fops); ++ if (!pfile) ++ netdev_err(pdata->netdev, "debugfs_create_file failed\n"); ++ ++ pfile = debugfs_create_file("xgmac_register_value", 0600, ++ pdata->xgbe_debugfs, pdata, ++ &xgmac_reg_value_fops); ++ if (!pfile) ++ netdev_err(pdata->netdev, "debugfs_create_file failed\n"); ++ ++ pfile = debugfs_create_file("xpcs_mmd", 0600, ++ pdata->xgbe_debugfs, pdata, ++ &xpcs_mmd_fops); ++ if (!pfile) ++ netdev_err(pdata->netdev, "debugfs_create_file failed\n"); ++ ++ pfile = debugfs_create_file("xpcs_register", 0600, ++ pdata->xgbe_debugfs, pdata, ++ &xpcs_reg_addr_fops); ++ if (!pfile) ++ netdev_err(pdata->netdev, "debugfs_create_file failed\n"); ++ ++ pfile = debugfs_create_file("xpcs_register_value", 0600, ++ pdata->xgbe_debugfs, pdata, ++ &xpcs_reg_value_fops); ++ if (!pfile) ++ netdev_err(pdata->netdev, "debugfs_create_file failed\n"); ++ ++ kfree(buf); ++} ++ ++void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) ++{ ++ debugfs_remove_recursive(pdata->xgbe_debugfs); ++ pdata->xgbe_debugfs = NULL; ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c +new file mode 100644 +index 0000000..1c5d62e +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-desc.c +@@ -0,0 +1,566 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static void xgbe_unmap_skb(struct xgbe_prv_data *, struct xgbe_ring_data *); ++ ++static void xgbe_free_ring(struct xgbe_prv_data *pdata, ++ struct xgbe_ring *ring) ++{ ++ struct xgbe_ring_data *rdata; ++ unsigned int i; ++ ++ if (!ring) ++ return; ++ ++ if (ring->rdata) { ++ for (i = 0; i < ring->rdesc_count; i++) { ++ rdata = XGBE_GET_DESC_DATA(ring, i); ++ xgbe_unmap_skb(pdata, rdata); ++ } ++ ++ kfree(ring->rdata); ++ ring->rdata = NULL; ++ } ++ ++ if (ring->rdesc) { ++ dma_free_coherent(pdata->dev, ++ (sizeof(struct xgbe_ring_desc) * ++ ring->rdesc_count), ++ ring->rdesc, ring->rdesc_dma); ++ ring->rdesc = NULL; ++ } ++} ++ ++static void xgbe_free_ring_resources(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ DBGPR("-->xgbe_free_ring_resources\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ xgbe_free_ring(pdata, channel->tx_ring); ++ xgbe_free_ring(pdata, channel->rx_ring); ++ } ++ ++ DBGPR("<--xgbe_free_ring_resources\n"); ++} ++ ++static int xgbe_init_ring(struct xgbe_prv_data *pdata, ++ struct xgbe_ring *ring, unsigned int rdesc_count) ++{ ++ DBGPR("-->xgbe_init_ring\n"); ++ ++ if (!ring) ++ return 0; ++ ++ /* Descriptors */ ++ ring->rdesc_count = rdesc_count; ++ ring->rdesc = dma_alloc_coherent(pdata->dev, ++ (sizeof(struct xgbe_ring_desc) * ++ rdesc_count), &ring->rdesc_dma, ++ GFP_KERNEL); ++ if (!ring->rdesc) ++ return -ENOMEM; ++ ++ /* Descriptor information */ ++ ring->rdata = kcalloc(rdesc_count, sizeof(struct xgbe_ring_data), ++ GFP_KERNEL); ++ if (!ring->rdata) ++ return -ENOMEM; ++ ++ DBGPR(" rdesc=0x%p, rdesc_dma=0x%llx, rdata=0x%p\n", ++ ring->rdesc, ring->rdesc_dma, ring->rdata); ++ ++ DBGPR("<--xgbe_init_ring\n"); ++ ++ return 0; ++} ++ ++static int xgbe_alloc_ring_resources(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ int ret; ++ ++ DBGPR("-->xgbe_alloc_ring_resources\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ DBGPR(" %s - tx_ring:\n", channel->name); ++ ret = xgbe_init_ring(pdata, channel->tx_ring, ++ pdata->tx_desc_count); ++ if (ret) { ++ netdev_alert(pdata->netdev, ++ "error initializing Tx ring\n"); ++ goto err_ring; ++ } ++ ++ DBGPR(" %s - rx_ring:\n", channel->name); ++ ret = xgbe_init_ring(pdata, channel->rx_ring, ++ pdata->rx_desc_count); ++ if (ret) { ++ netdev_alert(pdata->netdev, ++ "error initializing Tx ring\n"); ++ goto err_ring; ++ } ++ } ++ ++ DBGPR("<--xgbe_alloc_ring_resources\n"); ++ ++ return 0; ++ ++err_ring: ++ xgbe_free_ring_resources(pdata); ++ ++ return ret; ++} ++ ++static void xgbe_wrapper_tx_descriptor_init(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_channel *channel; ++ struct xgbe_ring *ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ dma_addr_t rdesc_dma; ++ unsigned int i, j; ++ ++ DBGPR("-->xgbe_wrapper_tx_descriptor_init\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ ring = channel->tx_ring; ++ if (!ring) ++ break; ++ ++ rdesc = ring->rdesc; ++ rdesc_dma = ring->rdesc_dma; ++ ++ for (j = 0; j < ring->rdesc_count; j++) { ++ rdata = XGBE_GET_DESC_DATA(ring, j); ++ ++ rdata->rdesc = rdesc; ++ rdata->rdesc_dma = rdesc_dma; ++ ++ rdesc++; ++ rdesc_dma += sizeof(struct xgbe_ring_desc); ++ } ++ ++ ring->cur = 0; ++ ring->dirty = 0; ++ ring->tx.queue_stopped = 0; ++ ++ hw_if->tx_desc_init(channel); ++ } ++ ++ DBGPR("<--xgbe_wrapper_tx_descriptor_init\n"); ++} ++ ++static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_channel *channel; ++ struct xgbe_ring *ring; ++ struct xgbe_ring_desc *rdesc; ++ struct xgbe_ring_data *rdata; ++ dma_addr_t rdesc_dma, skb_dma; ++ struct sk_buff *skb = NULL; ++ unsigned int i, j; ++ ++ DBGPR("-->xgbe_wrapper_rx_descriptor_init\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ ring = channel->rx_ring; ++ if (!ring) ++ break; ++ ++ rdesc = ring->rdesc; ++ rdesc_dma = ring->rdesc_dma; ++ ++ for (j = 0; j < ring->rdesc_count; j++) { ++ rdata = XGBE_GET_DESC_DATA(ring, j); ++ ++ rdata->rdesc = rdesc; ++ rdata->rdesc_dma = rdesc_dma; ++ ++ /* Allocate skb & assign to each rdesc */ ++ skb = dev_alloc_skb(pdata->rx_buf_size); ++ if (skb == NULL) ++ break; ++ skb_dma = dma_map_single(pdata->dev, skb->data, ++ pdata->rx_buf_size, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(pdata->dev, skb_dma)) { ++ netdev_alert(pdata->netdev, ++ "failed to do the dma map\n"); ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ rdata->skb = skb; ++ rdata->skb_dma = skb_dma; ++ rdata->skb_dma_len = pdata->rx_buf_size; ++ ++ rdesc++; ++ rdesc_dma += sizeof(struct xgbe_ring_desc); ++ } ++ ++ ring->cur = 0; ++ ring->dirty = 0; ++ ring->rx.realloc_index = 0; ++ ring->rx.realloc_threshold = 0; ++ ++ hw_if->rx_desc_init(channel); ++ } ++ ++ DBGPR("<--xgbe_wrapper_rx_descriptor_init\n"); ++} ++ ++static void xgbe_unmap_skb(struct xgbe_prv_data *pdata, ++ struct xgbe_ring_data *rdata) ++{ ++ if (rdata->skb_dma) { ++ if (rdata->mapped_as_page) { ++ dma_unmap_page(pdata->dev, rdata->skb_dma, ++ rdata->skb_dma_len, DMA_TO_DEVICE); ++ } else { ++ dma_unmap_single(pdata->dev, rdata->skb_dma, ++ rdata->skb_dma_len, DMA_TO_DEVICE); ++ } ++ rdata->skb_dma = 0; ++ rdata->skb_dma_len = 0; ++ } ++ ++ if (rdata->skb) { ++ dev_kfree_skb_any(rdata->skb); ++ rdata->skb = NULL; ++ } ++ ++ rdata->tso_header = 0; ++ rdata->len = 0; ++ rdata->interrupt = 0; ++ rdata->mapped_as_page = 0; ++ ++ if (rdata->state_saved) { ++ rdata->state_saved = 0; ++ rdata->state.incomplete = 0; ++ rdata->state.context_next = 0; ++ rdata->state.skb = NULL; ++ rdata->state.len = 0; ++ rdata->state.error = 0; ++ } ++} ++ ++static int xgbe_map_tx_skb(struct xgbe_channel *channel, struct sk_buff *skb) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_packet_data *packet; ++ struct skb_frag_struct *frag; ++ dma_addr_t skb_dma; ++ unsigned int start_index, cur_index; ++ unsigned int offset, tso, vlan, datalen, len; ++ unsigned int i; ++ ++ DBGPR("-->xgbe_map_tx_skb: cur = %d\n", ring->cur); ++ ++ offset = 0; ++ start_index = ring->cur; ++ cur_index = ring->cur; ++ ++ packet = &ring->packet_data; ++ packet->rdesc_count = 0; ++ packet->length = 0; ++ ++ tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ TSO_ENABLE); ++ vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ VLAN_CTAG); ++ ++ /* Save space for a context descriptor if needed */ ++ if ((tso && (packet->mss != ring->tx.cur_mss)) || ++ (vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag))) ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); ++ ++ if (tso) { ++ DBGPR(" TSO packet\n"); ++ ++ /* Map the TSO header */ ++ skb_dma = dma_map_single(pdata->dev, skb->data, ++ packet->header_len, DMA_TO_DEVICE); ++ if (dma_mapping_error(pdata->dev, skb_dma)) { ++ netdev_alert(pdata->netdev, "dma_map_single failed\n"); ++ goto err_out; ++ } ++ rdata->skb_dma = skb_dma; ++ rdata->skb_dma_len = packet->header_len; ++ rdata->tso_header = 1; ++ ++ offset = packet->header_len; ++ ++ packet->length += packet->header_len; ++ ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); ++ } ++ ++ /* Map the (remainder of the) packet */ ++ for (datalen = skb_headlen(skb) - offset; datalen; ) { ++ len = min_t(unsigned int, datalen, XGBE_TX_MAX_BUF_SIZE); ++ ++ skb_dma = dma_map_single(pdata->dev, skb->data + offset, len, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(pdata->dev, skb_dma)) { ++ netdev_alert(pdata->netdev, "dma_map_single failed\n"); ++ goto err_out; ++ } ++ rdata->skb_dma = skb_dma; ++ rdata->skb_dma_len = len; ++ DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n", ++ cur_index, skb_dma, len); ++ ++ datalen -= len; ++ offset += len; ++ ++ packet->length += len; ++ ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); ++ } ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ DBGPR(" mapping frag %u\n", i); ++ ++ frag = &skb_shinfo(skb)->frags[i]; ++ offset = 0; ++ ++ for (datalen = skb_frag_size(frag); datalen; ) { ++ len = min_t(unsigned int, datalen, ++ XGBE_TX_MAX_BUF_SIZE); ++ ++ skb_dma = skb_frag_dma_map(pdata->dev, frag, offset, ++ len, DMA_TO_DEVICE); ++ if (dma_mapping_error(pdata->dev, skb_dma)) { ++ netdev_alert(pdata->netdev, ++ "skb_frag_dma_map failed\n"); ++ goto err_out; ++ } ++ rdata->skb_dma = skb_dma; ++ rdata->skb_dma_len = len; ++ rdata->mapped_as_page = 1; ++ DBGPR(" skb data: index=%u, dma=0x%llx, len=%u\n", ++ cur_index, skb_dma, len); ++ ++ datalen -= len; ++ offset += len; ++ ++ packet->length += len; ++ ++ cur_index++; ++ rdata = XGBE_GET_DESC_DATA(ring, cur_index); ++ } ++ } ++ ++ /* Save the skb address in the last entry */ ++ rdata->skb = skb; ++ ++ /* Save the number of descriptor entries used */ ++ packet->rdesc_count = cur_index - start_index; ++ ++ DBGPR("<--xgbe_map_tx_skb: count=%u\n", packet->rdesc_count); ++ ++ return packet->rdesc_count; ++ ++err_out: ++ while (start_index < cur_index) { ++ rdata = XGBE_GET_DESC_DATA(ring, start_index++); ++ xgbe_unmap_skb(pdata, rdata); ++ } ++ ++ DBGPR("<--xgbe_map_tx_skb: count=0\n"); ++ ++ return 0; ++} ++ ++static void xgbe_realloc_skb(struct xgbe_channel *channel) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_ring *ring = channel->rx_ring; ++ struct xgbe_ring_data *rdata; ++ struct sk_buff *skb = NULL; ++ dma_addr_t skb_dma; ++ int i; ++ ++ DBGPR("-->xgbe_realloc_skb: rx_ring->rx.realloc_index = %u\n", ++ ring->rx.realloc_index); ++ ++ for (i = 0; i < ring->dirty; i++) { ++ rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index); ++ ++ /* Reset rdata values */ ++ xgbe_unmap_skb(pdata, rdata); ++ ++ /* Allocate skb & assign to each rdesc */ ++ skb = dev_alloc_skb(pdata->rx_buf_size); ++ if (skb == NULL) { ++ netdev_alert(pdata->netdev, ++ "failed to allocate skb\n"); ++ break; ++ } ++ skb_dma = dma_map_single(pdata->dev, skb->data, ++ pdata->rx_buf_size, DMA_FROM_DEVICE); ++ if (dma_mapping_error(pdata->dev, skb_dma)) { ++ netdev_alert(pdata->netdev, ++ "failed to do the dma map\n"); ++ dev_kfree_skb_any(skb); ++ break; ++ } ++ rdata->skb = skb; ++ rdata->skb_dma = skb_dma; ++ rdata->skb_dma_len = pdata->rx_buf_size; ++ ++ hw_if->rx_desc_reset(rdata); ++ ++ ring->rx.realloc_index++; ++ } ++ ring->dirty = 0; ++ ++ DBGPR("<--xgbe_realloc_skb\n"); ++} ++ ++void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if) ++{ ++ DBGPR("-->xgbe_init_function_ptrs_desc\n"); ++ ++ desc_if->alloc_ring_resources = xgbe_alloc_ring_resources; ++ desc_if->free_ring_resources = xgbe_free_ring_resources; ++ desc_if->map_tx_skb = xgbe_map_tx_skb; ++ desc_if->realloc_skb = xgbe_realloc_skb; ++ desc_if->unmap_skb = xgbe_unmap_skb; ++ desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init; ++ desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init; ++ ++ DBGPR("<--xgbe_init_function_ptrs_desc\n"); ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c +new file mode 100644 +index 0000000..24b5d9e +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-dev.c +@@ -0,0 +1,2643 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/phy.h> ++#include <linux/clk.h> ++#include <linux/bitrev.h> ++#include <linux/crc32.h> ++#include <asm/cputype.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata, ++ unsigned int usec) ++{ ++ unsigned long rate; ++ unsigned int ret; ++ ++ DBGPR("-->xgbe_usec_to_riwt\n"); ++ ++ rate = clk_get_rate(pdata->sysclk); ++ ++ /* ++ * Convert the input usec value to the watchdog timer value. Each ++ * watchdog timer value is equivalent to 256 clock cycles. ++ * Calculate the required value as: ++ * ( usec * ( system_clock_mhz / 10^6 ) / 256 ++ */ ++ ret = (usec * (rate / 1000000)) / 256; ++ ++ DBGPR("<--xgbe_usec_to_riwt\n"); ++ ++ return ret; ++} ++ ++static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata, ++ unsigned int riwt) ++{ ++ unsigned long rate; ++ unsigned int ret; ++ ++ DBGPR("-->xgbe_riwt_to_usec\n"); ++ ++ rate = clk_get_rate(pdata->sysclk); ++ ++ /* ++ * Convert the input watchdog timer value to the usec value. Each ++ * watchdog timer value is equivalent to 256 clock cycles. ++ * Calculate the required value as: ++ * ( riwt * 256 ) / ( system_clock_mhz / 10^6 ) ++ */ ++ ret = (riwt * 256) / (rate / 1000000); ++ ++ DBGPR("<--xgbe_riwt_to_usec\n"); ++ ++ return ret; ++} ++ ++static int xgbe_config_pblx8(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_CR, PBLX8, ++ pdata->pblx8); ++ ++ return 0; ++} ++ ++static int xgbe_get_tx_pbl_val(struct xgbe_prv_data *pdata) ++{ ++ return XGMAC_DMA_IOREAD_BITS(pdata->channel, DMA_CH_TCR, PBL); ++} ++ ++static int xgbe_config_tx_pbl_val(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, PBL, ++ pdata->tx_pbl); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_get_rx_pbl_val(struct xgbe_prv_data *pdata) ++{ ++ return XGMAC_DMA_IOREAD_BITS(pdata->channel, DMA_CH_RCR, PBL); ++} ++ ++static int xgbe_config_rx_pbl_val(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, PBL, ++ pdata->rx_pbl); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_config_osp_mode(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, OSP, ++ pdata->tx_osp_mode); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_config_rsf_mode(struct xgbe_prv_data *pdata, unsigned int val) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->rx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RSF, val); ++ ++ return 0; ++} ++ ++static int xgbe_config_tsf_mode(struct xgbe_prv_data *pdata, unsigned int val) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TSF, val); ++ ++ return 0; ++} ++ ++static int xgbe_config_rx_threshold(struct xgbe_prv_data *pdata, ++ unsigned int val) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->rx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RTC, val); ++ ++ return 0; ++} ++ ++static int xgbe_config_tx_threshold(struct xgbe_prv_data *pdata, ++ unsigned int val) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TTC, val); ++ ++ return 0; ++} ++ ++static int xgbe_config_rx_coalesce(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RIWT, RWT, ++ pdata->rx_riwt); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_config_tx_coalesce(struct xgbe_prv_data *pdata) ++{ ++ return 0; ++} ++ ++static void xgbe_config_rx_buffer_size(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, RBSZ, ++ pdata->rx_buf_size); ++ } ++} ++ ++static void xgbe_config_tso_mode(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, TSE, 1); ++ } ++} ++ ++static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ unsigned int max_q_count, q_count; ++ unsigned int reg, reg_val; ++ unsigned int i; ++ ++ /* Clear MTL flow control */ ++ for (i = 0; i < pdata->rx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 0); ++ ++ /* Clear MAC flow control */ ++ max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; ++ q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count); ++ reg = MAC_Q0TFCR; ++ for (i = 0; i < q_count; i++) { ++ reg_val = XGMAC_IOREAD(pdata, reg); ++ XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, TFE, 0); ++ XGMAC_IOWRITE(pdata, reg, reg_val); ++ ++ reg += MAC_QTFCR_INC; ++ } ++ ++ return 0; ++} ++ ++static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ unsigned int max_q_count, q_count; ++ unsigned int reg, reg_val; ++ unsigned int i; ++ ++ /* Set MTL flow control */ ++ for (i = 0; i < pdata->rx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 1); ++ ++ /* Set MAC flow control */ ++ max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES; ++ q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count); ++ reg = MAC_Q0TFCR; ++ for (i = 0; i < q_count; i++) { ++ reg_val = XGMAC_IOREAD(pdata, reg); ++ ++ /* Enable transmit flow control */ ++ XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, TFE, 1); ++ /* Set pause time */ ++ XGMAC_SET_BITS(reg_val, MAC_Q0TFCR, PT, 0xffff); ++ ++ XGMAC_IOWRITE(pdata, reg, reg_val); ++ ++ reg += MAC_QTFCR_INC; ++ } ++ ++ return 0; ++} ++ ++static int xgbe_disable_rx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, RFE, 0); ++ ++ return 0; ++} ++ ++static int xgbe_enable_rx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, RFE, 1); ++ ++ return 0; ++} ++ ++static int xgbe_config_tx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ struct ieee_pfc *pfc = pdata->pfc; ++ ++ if (pdata->tx_pause || (pfc && pfc->pfc_en)) ++ xgbe_enable_tx_flow_control(pdata); ++ else ++ xgbe_disable_tx_flow_control(pdata); ++ ++ return 0; ++} ++ ++static int xgbe_config_rx_flow_control(struct xgbe_prv_data *pdata) ++{ ++ struct ieee_pfc *pfc = pdata->pfc; ++ ++ if (pdata->rx_pause || (pfc && pfc->pfc_en)) ++ xgbe_enable_rx_flow_control(pdata); ++ else ++ xgbe_disable_rx_flow_control(pdata); ++ ++ return 0; ++} ++ ++static void xgbe_config_flow_control(struct xgbe_prv_data *pdata) ++{ ++ struct ieee_pfc *pfc = pdata->pfc; ++ ++ xgbe_config_tx_flow_control(pdata); ++ xgbe_config_rx_flow_control(pdata); ++ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RFCR, PFCE, ++ (pfc && pfc->pfc_en) ? 1 : 0); ++} ++ ++static void xgbe_enable_dma_interrupts(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int dma_ch_isr, dma_ch_ier; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ /* Clear all the interrupts which are set */ ++ dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_SR, dma_ch_isr); ++ ++ /* Clear all interrupt enable bits */ ++ dma_ch_ier = 0; ++ ++ /* Enable following interrupts ++ * NIE - Normal Interrupt Summary Enable ++ * AIE - Abnormal Interrupt Summary Enable ++ * FBEE - Fatal Bus Error Enable ++ */ ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, NIE, 1); ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, AIE, 1); ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); ++ ++ if (channel->tx_ring) { ++ /* Enable the following Tx interrupts ++ * TIE - Transmit Interrupt Enable (unless polling) ++ */ ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); ++ } ++ if (channel->rx_ring) { ++ /* Enable following Rx interrupts ++ * RBUE - Receive Buffer Unavailable Enable ++ * RIE - Receive Interrupt Enable ++ */ ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); ++ } ++ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); ++ } ++} ++ ++static void xgbe_enable_mtl_interrupts(struct xgbe_prv_data *pdata) ++{ ++ unsigned int mtl_q_isr; ++ unsigned int q_count, i; ++ ++ q_count = max(pdata->hw_feat.tx_q_cnt, pdata->hw_feat.rx_q_cnt); ++ for (i = 0; i < q_count; i++) { ++ /* Clear all the interrupts which are set */ ++ mtl_q_isr = XGMAC_MTL_IOREAD(pdata, i, MTL_Q_ISR); ++ XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_ISR, mtl_q_isr); ++ ++ /* No MTL interrupts to be enabled */ ++ XGMAC_MTL_IOWRITE(pdata, i, MTL_Q_IER, 0); ++ } ++} ++ ++static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata) ++{ ++ unsigned int mac_ier = 0; ++ ++ /* Enable Timestamp interrupt */ ++ XGMAC_SET_BITS(mac_ier, MAC_IER, TSIE, 1); ++ ++ XGMAC_IOWRITE(pdata, MAC_IER, mac_ier); ++ ++ /* Enable all counter interrupts */ ++ XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xff); ++ XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xff); ++} ++ ++static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3); ++ ++ return 0; ++} ++ ++static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2); ++ ++ return 0; ++} ++ ++static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0); ++ ++ return 0; ++} ++ ++static int xgbe_set_promiscuous_mode(struct xgbe_prv_data *pdata, ++ unsigned int enable) ++{ ++ unsigned int val = enable ? 1 : 0; ++ ++ if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PR) == val) ++ return 0; ++ ++ DBGPR(" %s promiscuous mode\n", enable ? "entering" : "leaving"); ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, val); ++ ++ return 0; ++} ++ ++static int xgbe_set_all_multicast_mode(struct xgbe_prv_data *pdata, ++ unsigned int enable) ++{ ++ unsigned int val = enable ? 1 : 0; ++ ++ if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PM) == val) ++ return 0; ++ ++ DBGPR(" %s allmulti mode\n", enable ? "entering" : "leaving"); ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PM, val); ++ ++ return 0; ++} ++ ++static void xgbe_set_mac_reg(struct xgbe_prv_data *pdata, ++ struct netdev_hw_addr *ha, unsigned int *mac_reg) ++{ ++ unsigned int mac_addr_hi, mac_addr_lo; ++ u8 *mac_addr; ++ ++ mac_addr_lo = 0; ++ mac_addr_hi = 0; ++ ++ if (ha) { ++ mac_addr = (u8 *)&mac_addr_lo; ++ mac_addr[0] = ha->addr[0]; ++ mac_addr[1] = ha->addr[1]; ++ mac_addr[2] = ha->addr[2]; ++ mac_addr[3] = ha->addr[3]; ++ mac_addr = (u8 *)&mac_addr_hi; ++ mac_addr[0] = ha->addr[4]; ++ mac_addr[1] = ha->addr[5]; ++ ++ DBGPR(" adding mac address %pM at 0x%04x\n", ha->addr, ++ *mac_reg); ++ ++ XGMAC_SET_BITS(mac_addr_hi, MAC_MACA1HR, AE, 1); ++ } ++ ++ XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_hi); ++ *mac_reg += MAC_MACA_INC; ++ XGMAC_IOWRITE(pdata, *mac_reg, mac_addr_lo); ++ *mac_reg += MAC_MACA_INC; ++} ++ ++static void xgbe_set_mac_addn_addrs(struct xgbe_prv_data *pdata) ++{ ++ struct net_device *netdev = pdata->netdev; ++ struct netdev_hw_addr *ha; ++ unsigned int mac_reg; ++ unsigned int addn_macs; ++ ++ mac_reg = MAC_MACA1HR; ++ addn_macs = pdata->hw_feat.addn_mac; ++ ++ if (netdev_uc_count(netdev) > addn_macs) { ++ xgbe_set_promiscuous_mode(pdata, 1); ++ } else { ++ netdev_for_each_uc_addr(ha, netdev) { ++ xgbe_set_mac_reg(pdata, ha, &mac_reg); ++ addn_macs--; ++ } ++ ++ if (netdev_mc_count(netdev) > addn_macs) { ++ xgbe_set_all_multicast_mode(pdata, 1); ++ } else { ++ netdev_for_each_mc_addr(ha, netdev) { ++ xgbe_set_mac_reg(pdata, ha, &mac_reg); ++ addn_macs--; ++ } ++ } ++ } ++ ++ /* Clear remaining additional MAC address entries */ ++ while (addn_macs--) ++ xgbe_set_mac_reg(pdata, NULL, &mac_reg); ++} ++ ++static void xgbe_set_mac_hash_table(struct xgbe_prv_data *pdata) ++{ ++ struct net_device *netdev = pdata->netdev; ++ struct netdev_hw_addr *ha; ++ unsigned int hash_reg; ++ unsigned int hash_table_shift, hash_table_count; ++ u32 hash_table[XGBE_MAC_HASH_TABLE_SIZE]; ++ u32 crc; ++ unsigned int i; ++ ++ hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7); ++ hash_table_count = pdata->hw_feat.hash_table_size / 32; ++ memset(hash_table, 0, sizeof(hash_table)); ++ ++ /* Build the MAC Hash Table register values */ ++ netdev_for_each_uc_addr(ha, netdev) { ++ crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); ++ crc >>= hash_table_shift; ++ hash_table[crc >> 5] |= (1 << (crc & 0x1f)); ++ } ++ ++ netdev_for_each_mc_addr(ha, netdev) { ++ crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); ++ crc >>= hash_table_shift; ++ hash_table[crc >> 5] |= (1 << (crc & 0x1f)); ++ } ++ ++ /* Set the MAC Hash Table registers */ ++ hash_reg = MAC_HTR0; ++ for (i = 0; i < hash_table_count; i++) { ++ XGMAC_IOWRITE(pdata, hash_reg, hash_table[i]); ++ hash_reg += MAC_HTR_INC; ++ } ++} ++ ++static int xgbe_add_mac_addresses(struct xgbe_prv_data *pdata) ++{ ++ if (pdata->hw_feat.hash_table_size) ++ xgbe_set_mac_hash_table(pdata); ++ else ++ xgbe_set_mac_addn_addrs(pdata); ++ ++ return 0; ++} ++ ++static int xgbe_set_mac_address(struct xgbe_prv_data *pdata, u8 *addr) ++{ ++ unsigned int mac_addr_hi, mac_addr_lo; ++ ++ mac_addr_hi = (addr[5] << 8) | (addr[4] << 0); ++ mac_addr_lo = (addr[3] << 24) | (addr[2] << 16) | ++ (addr[1] << 8) | (addr[0] << 0); ++ ++ XGMAC_IOWRITE(pdata, MAC_MACA0HR, mac_addr_hi); ++ XGMAC_IOWRITE(pdata, MAC_MACA0LR, mac_addr_lo); ++ ++ return 0; ++} ++ ++static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad, ++ int mmd_reg) ++{ ++ unsigned int mmd_address; ++ int mmd_data; ++ ++ if (mmd_reg & MII_ADDR_C45) ++ mmd_address = mmd_reg & ~MII_ADDR_C45; ++ else ++ mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); ++ ++ if (XGBE_SEATTLE_A0) { ++ /* The PCS implementation has reversed the devices in ++ * package registers so we need to change 05 to 06 and ++ * 06 to 05 if being read (these registers are readonly ++ * so no need to do this in the write function) ++ */ ++ if ((mmd_address & 0xffff) == 0x05) ++ mmd_address = (mmd_address & ~0xffff) | 0x06; ++ else if ((mmd_address & 0xffff) == 0x06) ++ mmd_address = (mmd_address & ~0xffff) | 0x05; ++ } ++ ++ /* The PCS registers are accessed using mmio. The underlying APB3 ++ * management interface uses indirect addressing to access the MMD ++ * register sets. This requires accessing of the PCS register in two ++ * phases, an address phase and a data phase. ++ * ++ * The mmio interface is based on 32-bit offsets and values. All ++ * register offsets must therefore be adjusted by left shifting the ++ * offset 2 bits and reading 32 bits of data. ++ */ ++ mutex_lock(&pdata->xpcs_mutex); ++ XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8); ++ mmd_data = XPCS_IOREAD(pdata, (mmd_address & 0xff) << 2); ++ mutex_unlock(&pdata->xpcs_mutex); ++ ++ return mmd_data; ++} ++ ++static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad, ++ int mmd_reg, int mmd_data) ++{ ++ unsigned int mmd_address; ++ ++ if (mmd_reg & MII_ADDR_C45) ++ mmd_address = mmd_reg & ~MII_ADDR_C45; ++ else ++ mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff); ++ ++ /* The PCS registers are accessed using mmio. The underlying APB3 ++ * management interface uses indirect addressing to access the MMD ++ * register sets. This requires accessing of the PCS register in two ++ * phases, an address phase and a data phase. ++ * ++ * The mmio interface is based on 32-bit offsets and values. All ++ * register offsets must therefore be adjusted by left shifting the ++ * offset 2 bits and reading 32 bits of data. ++ */ ++ mutex_lock(&pdata->xpcs_mutex); ++ XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8); ++ XPCS_IOWRITE(pdata, (mmd_address & 0xff) << 2, mmd_data); ++ mutex_unlock(&pdata->xpcs_mutex); ++} ++ ++static int xgbe_tx_complete(struct xgbe_ring_desc *rdesc) ++{ ++ return !XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN); ++} ++ ++static int xgbe_disable_rx_csum(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, IPC, 0); ++ ++ return 0; ++} ++ ++static int xgbe_enable_rx_csum(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, IPC, 1); ++ ++ return 0; ++} ++ ++static int xgbe_enable_rx_vlan_stripping(struct xgbe_prv_data *pdata) ++{ ++ /* Put the VLAN tag in the Rx descriptor */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLRXS, 1); ++ ++ /* Don't check the VLAN type */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, DOVLTC, 1); ++ ++ /* Check only C-TAG (0x8100) packets */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ERSVLM, 0); ++ ++ /* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ESVL, 0); ++ ++ /* Enable VLAN tag stripping */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0x3); ++ ++ return 0; ++} ++ ++static int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata) ++{ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0); ++ ++ return 0; ++} ++ ++static int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata) ++{ ++ /* Enable VLAN filtering */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1); ++ ++ /* Enable VLAN Hash Table filtering */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1); ++ ++ /* Disable VLAN tag inverse matching */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0); ++ ++ /* Only filter on the lower 12-bits of the VLAN tag */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1); ++ ++ /* In order for the VLAN Hash Table filtering to be effective, ++ * the VLAN tag identifier in the VLAN Tag Register must not ++ * be zero. Set the VLAN tag identifier to "1" to enable the ++ * VLAN Hash Table filtering. This implies that a VLAN tag of ++ * 1 will always pass filtering. ++ */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1); ++ ++ return 0; ++} ++ ++static int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata) ++{ ++ /* Disable VLAN filtering */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0); ++ ++ return 0; ++} ++ ++#ifndef CRCPOLY_LE ++#define CRCPOLY_LE 0xedb88320 ++#endif ++static u32 xgbe_vid_crc32_le(__le16 vid_le) ++{ ++ u32 poly = CRCPOLY_LE; ++ u32 crc = ~0; ++ u32 temp = 0; ++ unsigned char *data = (unsigned char *)&vid_le; ++ unsigned char data_byte = 0; ++ int i, bits; ++ ++ bits = get_bitmask_order(VLAN_VID_MASK); ++ for (i = 0; i < bits; i++) { ++ if ((i % 8) == 0) ++ data_byte = data[i / 8]; ++ ++ temp = ((crc & 1) ^ data_byte) & 1; ++ crc >>= 1; ++ data_byte >>= 1; ++ ++ if (temp) ++ crc ^= poly; ++ } ++ ++ return crc; ++} ++ ++static int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata) ++{ ++ u32 crc; ++ u16 vid; ++ __le16 vid_le; ++ u16 vlan_hash_table = 0; ++ ++ /* Generate the VLAN Hash Table value */ ++ for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) { ++ /* Get the CRC32 value of the VLAN ID */ ++ vid_le = cpu_to_le16(vid); ++ crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28; ++ ++ vlan_hash_table |= (1 << crc); ++ } ++ ++ /* Set the VLAN Hash Table filtering register */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table); ++ ++ return 0; ++} ++ ++static void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata) ++{ ++ struct xgbe_ring_desc *rdesc = rdata->rdesc; ++ ++ /* Reset the Tx descriptor ++ * Set buffer 1 (lo) address to zero ++ * Set buffer 1 (hi) address to zero ++ * Reset all other control bits (IC, TTSE, B2L & B1L) ++ * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, etc) ++ */ ++ rdesc->desc0 = 0; ++ rdesc->desc1 = 0; ++ rdesc->desc2 = 0; ++ rdesc->desc3 = 0; ++} ++ ++static void xgbe_tx_desc_init(struct xgbe_channel *channel) ++{ ++ struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ int i; ++ int start_index = ring->cur; ++ ++ DBGPR("-->tx_desc_init\n"); ++ ++ /* Initialze all descriptors */ ++ for (i = 0; i < ring->rdesc_count; i++) { ++ rdata = XGBE_GET_DESC_DATA(ring, i); ++ rdesc = rdata->rdesc; ++ ++ /* Initialize Tx descriptor ++ * Set buffer 1 (lo) address to zero ++ * Set buffer 1 (hi) address to zero ++ * Reset all other control bits (IC, TTSE, B2L & B1L) ++ * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, ++ * etc) ++ */ ++ rdesc->desc0 = 0; ++ rdesc->desc1 = 0; ++ rdesc->desc2 = 0; ++ rdesc->desc3 = 0; ++ } ++ ++ /* Make sure everything is written to the descriptor(s) before ++ * telling the device about them ++ */ ++ wmb(); ++ ++ /* Update the total number of Tx descriptors */ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_TDRLR, ring->rdesc_count - 1); ++ ++ /* Update the starting address of descriptor ring */ ++ rdata = XGBE_GET_DESC_DATA(ring, start_index); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_HI, ++ upper_32_bits(rdata->rdesc_dma)); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_TDLR_LO, ++ lower_32_bits(rdata->rdesc_dma)); ++ ++ DBGPR("<--tx_desc_init\n"); ++} ++ ++static void xgbe_rx_desc_reset(struct xgbe_ring_data *rdata) ++{ ++ struct xgbe_ring_desc *rdesc = rdata->rdesc; ++ ++ /* Reset the Rx descriptor ++ * Set buffer 1 (lo) address to dma address (lo) ++ * Set buffer 1 (hi) address to dma address (hi) ++ * Set buffer 2 (lo) address to zero ++ * Set buffer 2 (hi) address to zero and set control bits ++ * OWN and INTE ++ */ ++ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma)); ++ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma)); ++ rdesc->desc2 = 0; ++ ++ rdesc->desc3 = 0; ++ if (rdata->interrupt) ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, 1); ++ ++ /* Since the Rx DMA engine is likely running, make sure everything ++ * is written to the descriptor(s) before setting the OWN bit ++ * for the descriptor ++ */ ++ wmb(); ++ ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1); ++ ++ /* Make sure ownership is written to the descriptor */ ++ wmb(); ++} ++ ++static void xgbe_rx_desc_init(struct xgbe_channel *channel) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_ring *ring = channel->rx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ unsigned int start_index = ring->cur; ++ unsigned int rx_coalesce, rx_frames; ++ unsigned int i; ++ ++ DBGPR("-->rx_desc_init\n"); ++ ++ rx_coalesce = (pdata->rx_riwt || pdata->rx_frames) ? 1 : 0; ++ rx_frames = pdata->rx_frames; ++ ++ /* Initialize all descriptors */ ++ for (i = 0; i < ring->rdesc_count; i++) { ++ rdata = XGBE_GET_DESC_DATA(ring, i); ++ rdesc = rdata->rdesc; ++ ++ /* Initialize Rx descriptor ++ * Set buffer 1 (lo) address to dma address (lo) ++ * Set buffer 1 (hi) address to dma address (hi) ++ * Set buffer 2 (lo) address to zero ++ * Set buffer 2 (hi) address to zero and set control ++ * bits OWN and INTE appropriateley ++ */ ++ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma)); ++ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma)); ++ rdesc->desc2 = 0; ++ rdesc->desc3 = 0; ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN, 1); ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, 1); ++ rdata->interrupt = 1; ++ if (rx_coalesce && (!rx_frames || ((i + 1) % rx_frames))) { ++ /* Clear interrupt on completion bit */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, INTE, ++ 0); ++ rdata->interrupt = 0; ++ } ++ } ++ ++ /* Make sure everything is written to the descriptors before ++ * telling the device about them ++ */ ++ wmb(); ++ ++ /* Update the total number of Rx descriptors */ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_RDRLR, ring->rdesc_count - 1); ++ ++ /* Update the starting address of descriptor ring */ ++ rdata = XGBE_GET_DESC_DATA(ring, start_index); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_HI, ++ upper_32_bits(rdata->rdesc_dma)); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_RDLR_LO, ++ lower_32_bits(rdata->rdesc_dma)); ++ ++ /* Update the Rx Descriptor Tail Pointer */ ++ rdata = XGBE_GET_DESC_DATA(ring, start_index + ring->rdesc_count - 1); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, ++ lower_32_bits(rdata->rdesc_dma)); ++ ++ DBGPR("<--rx_desc_init\n"); ++} ++ ++static void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, ++ unsigned int addend) ++{ ++ /* Set the addend register value and tell the device */ ++ XGMAC_IOWRITE(pdata, MAC_TSAR, addend); ++ XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSADDREG, 1); ++ ++ /* Wait for addend update to complete */ ++ while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSADDREG)) ++ udelay(5); ++} ++ ++static void xgbe_set_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, ++ unsigned int nsec) ++{ ++ /* Set the time values and tell the device */ ++ XGMAC_IOWRITE(pdata, MAC_STSUR, sec); ++ XGMAC_IOWRITE(pdata, MAC_STNUR, nsec); ++ XGMAC_IOWRITE_BITS(pdata, MAC_TSCR, TSINIT, 1); ++ ++ /* Wait for time update to complete */ ++ while (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSINIT)) ++ udelay(5); ++} ++ ++static u64 xgbe_get_tstamp_time(struct xgbe_prv_data *pdata) ++{ ++ u64 nsec; ++ ++ nsec = XGMAC_IOREAD(pdata, MAC_STSR); ++ nsec *= NSEC_PER_SEC; ++ nsec += XGMAC_IOREAD(pdata, MAC_STNR); ++ ++ return nsec; ++} ++ ++static u64 xgbe_get_tx_tstamp(struct xgbe_prv_data *pdata) ++{ ++ unsigned int tx_snr; ++ u64 nsec; ++ ++ tx_snr = XGMAC_IOREAD(pdata, MAC_TXSNR); ++ if (XGMAC_GET_BITS(tx_snr, MAC_TXSNR, TXTSSTSMIS)) ++ return 0; ++ ++ nsec = XGMAC_IOREAD(pdata, MAC_TXSSR); ++ nsec *= NSEC_PER_SEC; ++ nsec += tx_snr; ++ ++ return nsec; ++} ++ ++static void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, ++ struct xgbe_ring_desc *rdesc) ++{ ++ u64 nsec; ++ ++ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) && ++ !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) { ++ nsec = le32_to_cpu(rdesc->desc1); ++ nsec <<= 32; ++ nsec |= le32_to_cpu(rdesc->desc0); ++ if (nsec != 0xffffffffffffffffULL) { ++ packet->rx_tstamp = nsec; ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ RX_TSTAMP, 1); ++ } ++ } ++} ++ ++static int xgbe_config_tstamp(struct xgbe_prv_data *pdata, ++ unsigned int mac_tscr) ++{ ++ /* Set one nano-second accuracy */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); ++ ++ /* Set fine timestamp update */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); ++ ++ /* Overwrite earlier timestamps */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); ++ ++ XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr); ++ ++ /* Exit if timestamping is not enabled */ ++ if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) ++ return 0; ++ ++ /* Initialize time registers */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); ++ xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); ++ xgbe_set_tstamp_time(pdata, 0, 0); ++ ++ /* Initialize the timecounter */ ++ timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, ++ ktime_to_ns(ktime_get_real())); ++ ++ return 0; ++} ++ ++static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata) ++{ ++ struct ieee_ets *ets = pdata->ets; ++ unsigned int total_weight, min_weight, weight; ++ unsigned int i; ++ ++ if (!ets) ++ return; ++ ++ /* Set Tx to deficit weighted round robin scheduling algorithm (when ++ * traffic class is using ETS algorithm) ++ */ ++ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_DWRR); ++ ++ /* Set Traffic Class algorithms */ ++ total_weight = pdata->netdev->mtu * pdata->hw_feat.tc_cnt; ++ min_weight = total_weight / 100; ++ if (!min_weight) ++ min_weight = 1; ++ ++ for (i = 0; i < pdata->hw_feat.tc_cnt; i++) { ++ switch (ets->tc_tsa[i]) { ++ case IEEE_8021QAZ_TSA_STRICT: ++ DBGPR(" TC%u using SP\n", i); ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, ++ MTL_TSA_SP); ++ break; ++ case IEEE_8021QAZ_TSA_ETS: ++ weight = total_weight * ets->tc_tx_bw[i] / 100; ++ weight = clamp(weight, min_weight, total_weight); ++ ++ DBGPR(" TC%u using DWRR (weight %u)\n", i, weight); ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, ++ MTL_TSA_ETS); ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, ++ weight); ++ break; ++ } ++ } ++} ++ ++static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata) ++{ ++ struct ieee_pfc *pfc = pdata->pfc; ++ struct ieee_ets *ets = pdata->ets; ++ unsigned int mask, reg, reg_val; ++ unsigned int tc, prio; ++ ++ if (!pfc || !ets) ++ return; ++ ++ for (tc = 0; tc < pdata->hw_feat.tc_cnt; tc++) { ++ mask = 0; ++ for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) { ++ if ((pfc->pfc_en & (1 << prio)) && ++ (ets->prio_tc[prio] == tc)) ++ mask |= (1 << prio); ++ } ++ mask &= 0xff; ++ ++ DBGPR(" TC%u PFC mask=%#x\n", tc, mask); ++ reg = MTL_TCPM0R + (MTL_TCPM_INC * (tc / MTL_TCPM_TC_PER_REG)); ++ reg_val = XGMAC_IOREAD(pdata, reg); ++ ++ reg_val &= ~(0xff << ((tc % MTL_TCPM_TC_PER_REG) << 3)); ++ reg_val |= (mask << ((tc % MTL_TCPM_TC_PER_REG) << 3)); ++ ++ XGMAC_IOWRITE(pdata, reg, reg_val); ++ } ++ ++ xgbe_config_flow_control(pdata); ++} ++ ++static void xgbe_pre_xmit(struct xgbe_channel *channel) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ struct xgbe_packet_data *packet = &ring->packet_data; ++ unsigned int csum, tso, vlan; ++ unsigned int tso_context, vlan_context; ++ unsigned int tx_coalesce, tx_frames; ++ int start_index = ring->cur; ++ int i; ++ ++ DBGPR("-->xgbe_pre_xmit\n"); ++ ++ csum = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ CSUM_ENABLE); ++ tso = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ TSO_ENABLE); ++ vlan = XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ VLAN_CTAG); ++ ++ if (tso && (packet->mss != ring->tx.cur_mss)) ++ tso_context = 1; ++ else ++ tso_context = 0; ++ ++ if (vlan && (packet->vlan_ctag != ring->tx.cur_vlan_ctag)) ++ vlan_context = 1; ++ else ++ vlan_context = 0; ++ ++ tx_coalesce = (pdata->tx_usecs || pdata->tx_frames) ? 1 : 0; ++ tx_frames = pdata->tx_frames; ++ if (tx_coalesce && !channel->tx_timer_active) ++ ring->coalesce_count = 0; ++ ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdesc = rdata->rdesc; ++ ++ /* Create a context descriptor if this is a TSO packet */ ++ if (tso_context || vlan_context) { ++ if (tso_context) { ++ DBGPR(" TSO context descriptor, mss=%u\n", ++ packet->mss); ++ ++ /* Set the MSS size */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_CONTEXT_DESC2, ++ MSS, packet->mss); ++ ++ /* Mark it as a CONTEXT descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3, ++ CTXT, 1); ++ ++ /* Indicate this descriptor contains the MSS */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3, ++ TCMSSV, 1); ++ ++ ring->tx.cur_mss = packet->mss; ++ } ++ ++ if (vlan_context) { ++ DBGPR(" VLAN context descriptor, ctag=%u\n", ++ packet->vlan_ctag); ++ ++ /* Mark it as a CONTEXT descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3, ++ CTXT, 1); ++ ++ /* Set the VLAN tag */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3, ++ VT, packet->vlan_ctag); ++ ++ /* Indicate this descriptor contains the VLAN tag */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_CONTEXT_DESC3, ++ VLTV, 1); ++ ++ ring->tx.cur_vlan_ctag = packet->vlan_ctag; ++ } ++ ++ ring->cur++; ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdesc = rdata->rdesc; ++ } ++ ++ /* Update buffer address (for TSO this is the header) */ ++ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma)); ++ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma)); ++ ++ /* Update the buffer length */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, HL_B1L, ++ rdata->skb_dma_len); ++ ++ /* VLAN tag insertion check */ ++ if (vlan) ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, VTIR, ++ TX_NORMAL_DESC2_VLAN_INSERT); ++ ++ /* Timestamp enablement check */ ++ if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, TTSE, 1); ++ ++ /* Set IC bit based on Tx coalescing settings */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1); ++ if (tx_coalesce && (!tx_frames || ++ (++ring->coalesce_count % tx_frames))) ++ /* Clear IC bit */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 0); ++ ++ /* Mark it as First Descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, FD, 1); ++ ++ /* Mark it as a NORMAL descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0); ++ ++ /* Set OWN bit if not the first descriptor */ ++ if (ring->cur != start_index) ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); ++ ++ if (tso) { ++ /* Enable TSO */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TSE, 1); ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPPL, ++ packet->tcp_payload_len); ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, TCPHDRLEN, ++ packet->tcp_header_len / 4); ++ } else { ++ /* Enable CRC and Pad Insertion */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CPC, 0); ++ ++ /* Enable HW CSUM */ ++ if (csum) ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, ++ CIC, 0x3); ++ ++ /* Set the total length to be transmitted */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, FL, ++ packet->length); ++ } ++ ++ for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) { ++ ring->cur++; ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdesc = rdata->rdesc; ++ ++ /* Update buffer address */ ++ rdesc->desc0 = cpu_to_le32(lower_32_bits(rdata->skb_dma)); ++ rdesc->desc1 = cpu_to_le32(upper_32_bits(rdata->skb_dma)); ++ ++ /* Update the buffer length */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, HL_B1L, ++ rdata->skb_dma_len); ++ ++ /* Set IC bit based on Tx coalescing settings */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 1); ++ if (tx_coalesce && (!tx_frames || ++ (++ring->coalesce_count % tx_frames))) ++ /* Clear IC bit */ ++ XGMAC_SET_BITS_LE(rdesc->desc2, TX_NORMAL_DESC2, IC, 0); ++ ++ /* Set OWN bit */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); ++ ++ /* Mark it as NORMAL descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0); ++ ++ /* Enable HW CSUM */ ++ if (csum) ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, ++ CIC, 0x3); ++ } ++ ++ /* Set LAST bit for the last descriptor */ ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD, 1); ++ ++ /* In case the Tx DMA engine is running, make sure everything ++ * is written to the descriptor(s) before setting the OWN bit ++ * for the first descriptor ++ */ ++ wmb(); ++ ++ /* Set OWN bit for the first descriptor */ ++ rdata = XGBE_GET_DESC_DATA(ring, start_index); ++ rdesc = rdata->rdesc; ++ XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1); ++ ++#ifdef XGMAC_ENABLE_TX_DESC_DUMP ++ xgbe_dump_tx_desc(ring, start_index, packet->rdesc_count, 1); ++#endif ++ ++ /* Make sure ownership is written to the descriptor */ ++ wmb(); ++ ++ /* Issue a poll command to Tx DMA by writing address ++ * of next immediate free descriptor */ ++ ring->cur++; ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, ++ lower_32_bits(rdata->rdesc_dma)); ++ ++ /* Start the Tx coalescing timer */ ++ if (tx_coalesce && !channel->tx_timer_active) { ++ channel->tx_timer_active = 1; ++ hrtimer_start(&channel->tx_timer, ++ ktime_set(0, pdata->tx_usecs * NSEC_PER_USEC), ++ HRTIMER_MODE_REL); ++ } ++ ++ DBGPR(" %s: descriptors %u to %u written\n", ++ channel->name, start_index & (ring->rdesc_count - 1), ++ (ring->cur - 1) & (ring->rdesc_count - 1)); ++ ++ DBGPR("<--xgbe_pre_xmit\n"); ++} ++ ++static int xgbe_dev_read(struct xgbe_channel *channel) ++{ ++ struct xgbe_ring *ring = channel->rx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ struct xgbe_packet_data *packet = &ring->packet_data; ++ struct net_device *netdev = channel->pdata->netdev; ++ unsigned int err, etlt; ++ ++ DBGPR("-->xgbe_dev_read: cur = %d\n", ring->cur); ++ ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdesc = rdata->rdesc; ++ ++ /* Check for data availability */ ++ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, OWN)) ++ return 1; ++ ++#ifdef XGMAC_ENABLE_RX_DESC_DUMP ++ xgbe_dump_rx_desc(ring, rdesc, ring->cur); ++#endif ++ ++ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) { ++ /* Timestamp Context Descriptor */ ++ xgbe_get_rx_tstamp(packet, rdesc); ++ ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ CONTEXT, 1); ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ CONTEXT_NEXT, 0); ++ return 0; ++ } ++ ++ /* Normal Descriptor, be sure Context Descriptor bit is off */ ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 0); ++ ++ /* Indicate if a Context Descriptor is next */ ++ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CDA)) ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ CONTEXT_NEXT, 1); ++ ++ /* Get the packet length */ ++ rdata->len = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, PL); ++ ++ if (!XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, LD)) { ++ /* Not all the data has been transferred for this packet */ ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ INCOMPLETE, 1); ++ return 0; ++ } ++ ++ /* This is the last of the data for this packet */ ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ INCOMPLETE, 0); ++ ++ /* Set checksum done indicator as appropriate */ ++ if (channel->pdata->netdev->features & NETIF_F_RXCSUM) ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ CSUM_DONE, 1); ++ ++ /* Check for errors (only valid in last descriptor) */ ++ err = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ES); ++ etlt = XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, ETLT); ++ DBGPR(" err=%u, etlt=%#x\n", err, etlt); ++ ++ if (!err || (err && !etlt)) { ++ if ((etlt == 0x09) && ++ (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ VLAN_CTAG, 1); ++ packet->vlan_ctag = XGMAC_GET_BITS_LE(rdesc->desc0, ++ RX_NORMAL_DESC0, ++ OVT); ++ DBGPR(" vlan-ctag=0x%04x\n", packet->vlan_ctag); ++ } ++ } else { ++ if ((etlt == 0x05) || (etlt == 0x06)) ++ XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, ++ CSUM_DONE, 0); ++ else ++ XGMAC_SET_BITS(packet->errors, RX_PACKET_ERRORS, ++ FRAME, 1); ++ } ++ ++ DBGPR("<--xgbe_dev_read: %s - descriptor=%u (cur=%d)\n", channel->name, ++ ring->cur & (ring->rdesc_count - 1), ring->cur); ++ ++ return 0; ++} ++ ++static int xgbe_is_context_desc(struct xgbe_ring_desc *rdesc) ++{ ++ /* Rx and Tx share CTXT bit, so check TDES3.CTXT bit */ ++ return XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT); ++} ++ ++static int xgbe_is_last_desc(struct xgbe_ring_desc *rdesc) ++{ ++ /* Rx and Tx share LD bit, so check TDES3.LD bit */ ++ return XGMAC_GET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, LD); ++} ++ ++static int xgbe_enable_int(struct xgbe_channel *channel, ++ enum xgbe_int int_id) ++{ ++ unsigned int dma_ch_ier; ++ ++ dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); ++ ++ switch (int_id) { ++ case XGMAC_INT_DMA_CH_SR_TI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TPS: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TBU: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RBU: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RPS: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TI_RI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 1); ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 1); ++ break; ++ case XGMAC_INT_DMA_CH_SR_FBE: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); ++ break; ++ case XGMAC_INT_DMA_ALL: ++ dma_ch_ier |= channel->saved_ier; ++ break; ++ default: ++ return -1; ++ } ++ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); ++ ++ return 0; ++} ++ ++static int xgbe_disable_int(struct xgbe_channel *channel, ++ enum xgbe_int int_id) ++{ ++ unsigned int dma_ch_ier; ++ ++ dma_ch_ier = XGMAC_DMA_IOREAD(channel, DMA_CH_IER); ++ ++ switch (int_id) { ++ case XGMAC_INT_DMA_CH_SR_TI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TPS: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TXSE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TBU: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TBUE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RBU: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_RPS: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RSE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_TI_RI: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, TIE, 0); ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0); ++ break; ++ case XGMAC_INT_DMA_CH_SR_FBE: ++ XGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 0); ++ break; ++ case XGMAC_INT_DMA_ALL: ++ channel->saved_ier = dma_ch_ier & XGBE_DMA_INTERRUPT_MASK; ++ dma_ch_ier &= ~XGBE_DMA_INTERRUPT_MASK; ++ break; ++ default: ++ return -1; ++ } ++ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_IER, dma_ch_ier); ++ ++ return 0; ++} ++ ++static int xgbe_exit(struct xgbe_prv_data *pdata) ++{ ++ unsigned int count = 2000; ++ ++ DBGPR("-->xgbe_exit\n"); ++ ++ /* Issue a software reset */ ++ XGMAC_IOWRITE_BITS(pdata, DMA_MR, SWR, 1); ++ usleep_range(10, 15); ++ ++ /* Poll Until Poll Condition */ ++ while (count-- && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR)) ++ usleep_range(500, 600); ++ ++ if (!count) ++ return -EBUSY; ++ ++ DBGPR("<--xgbe_exit\n"); ++ ++ return 0; ++} ++ ++static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata) ++{ ++ unsigned int i, count; ++ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1); ++ ++ /* Poll Until Poll Condition */ ++ for (i = 0; i < pdata->tx_q_count; i++) { ++ count = 2000; ++ while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i, ++ MTL_Q_TQOMR, FTQ)) ++ usleep_range(500, 600); ++ ++ if (!count) ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static void xgbe_config_dma_bus(struct xgbe_prv_data *pdata) ++{ ++ /* Set enhanced addressing mode */ ++ XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, EAME, 1); ++ ++ /* Set the System Bus mode */ ++ XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, UNDEF, 1); ++ XGMAC_IOWRITE_BITS(pdata, DMA_SBMR, BLEN_256, 1); ++} ++ ++static void xgbe_config_dma_cache(struct xgbe_prv_data *pdata) ++{ ++ unsigned int arcache, awcache; ++ ++ arcache = 0; ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRC, pdata->arcache); ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, DRD, pdata->axdomain); ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, TEC, pdata->arcache); ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, TED, pdata->axdomain); ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, THC, pdata->arcache); ++ XGMAC_SET_BITS(arcache, DMA_AXIARCR, THD, pdata->axdomain); ++ XGMAC_IOWRITE(pdata, DMA_AXIARCR, arcache); ++ ++ awcache = 0; ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWC, pdata->awcache); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, DWD, pdata->axdomain); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPC, pdata->awcache); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RPD, pdata->axdomain); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHC, pdata->awcache); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, RHD, pdata->axdomain); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDC, pdata->awcache); ++ XGMAC_SET_BITS(awcache, DMA_AXIAWCR, TDD, pdata->axdomain); ++ XGMAC_IOWRITE(pdata, DMA_AXIAWCR, awcache); ++} ++ ++static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata) ++{ ++ unsigned int i; ++ ++ /* Set Tx to weighted round robin scheduling algorithm */ ++ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, ETSALG, MTL_ETSALG_WRR); ++ ++ /* Set Tx traffic classes to use WRR algorithm with equal weights */ ++ for (i = 0; i < pdata->hw_feat.tc_cnt; i++) { ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_ETSCR, TSA, ++ MTL_TSA_ETS); ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_TC_QWR, QW, 1); ++ } ++ ++ /* Set Rx to strict priority algorithm */ ++ XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP); ++} ++ ++static unsigned int xgbe_calculate_per_queue_fifo(unsigned int fifo_size, ++ unsigned int queue_count) ++{ ++ unsigned int q_fifo_size = 0; ++ enum xgbe_mtl_fifo_size p_fifo = XGMAC_MTL_FIFO_SIZE_256; ++ ++ /* Calculate Tx/Rx fifo share per queue */ ++ switch (fifo_size) { ++ case 0: ++ q_fifo_size = XGBE_FIFO_SIZE_B(128); ++ break; ++ case 1: ++ q_fifo_size = XGBE_FIFO_SIZE_B(256); ++ break; ++ case 2: ++ q_fifo_size = XGBE_FIFO_SIZE_B(512); ++ break; ++ case 3: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(1); ++ break; ++ case 4: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(2); ++ break; ++ case 5: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(4); ++ break; ++ case 6: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(8); ++ break; ++ case 7: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(16); ++ break; ++ case 8: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(32); ++ break; ++ case 9: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(64); ++ break; ++ case 10: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(128); ++ break; ++ case 11: ++ q_fifo_size = XGBE_FIFO_SIZE_KB(256); ++ break; ++ } ++ ++ /* The configured value is not the actual amount of fifo RAM */ ++ q_fifo_size = min_t(unsigned int, XGBE_FIFO_MAX, q_fifo_size); ++ ++ q_fifo_size = q_fifo_size / queue_count; ++ ++ /* Set the queue fifo size programmable value */ ++ if (q_fifo_size >= XGBE_FIFO_SIZE_KB(256)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_256K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(128)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_128K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(64)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_64K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(32)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_32K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(16)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_16K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(8)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_8K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(4)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_4K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(2)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_2K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_KB(1)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_1K; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_B(512)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_512; ++ else if (q_fifo_size >= XGBE_FIFO_SIZE_B(256)) ++ p_fifo = XGMAC_MTL_FIFO_SIZE_256; ++ ++ return p_fifo; ++} ++ ++static void xgbe_config_tx_fifo_size(struct xgbe_prv_data *pdata) ++{ ++ enum xgbe_mtl_fifo_size fifo_size; ++ unsigned int i; ++ ++ fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.tx_fifo_size, ++ pdata->tx_q_count); ++ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TQS, fifo_size); ++ ++ netdev_notice(pdata->netdev, "%d Tx queues, %d byte fifo per queue\n", ++ pdata->tx_q_count, ((fifo_size + 1) * 256)); ++} ++ ++static void xgbe_config_rx_fifo_size(struct xgbe_prv_data *pdata) ++{ ++ enum xgbe_mtl_fifo_size fifo_size; ++ unsigned int i; ++ ++ fifo_size = xgbe_calculate_per_queue_fifo(pdata->hw_feat.rx_fifo_size, ++ pdata->rx_q_count); ++ ++ for (i = 0; i < pdata->rx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RQS, fifo_size); ++ ++ netdev_notice(pdata->netdev, "%d Rx queues, %d byte fifo per queue\n", ++ pdata->rx_q_count, ((fifo_size + 1) * 256)); ++} ++ ++static void xgbe_config_queue_mapping(struct xgbe_prv_data *pdata) ++{ ++ unsigned int qptc, qptc_extra, queue; ++ unsigned int prio_queues; ++ unsigned int ppq, ppq_extra, prio; ++ unsigned int mask; ++ unsigned int i, j, reg, reg_val; ++ ++ /* Map the MTL Tx Queues to Traffic Classes ++ * Note: Tx Queues >= Traffic Classes ++ */ ++ qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt; ++ qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt; ++ ++ for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) { ++ for (j = 0; j < qptc; j++) { ++ DBGPR(" TXq%u mapped to TC%u\n", queue, i); ++ XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR, ++ Q2TCMAP, i); ++ pdata->q2tc_map[queue++] = i; ++ } ++ ++ if (i < qptc_extra) { ++ DBGPR(" TXq%u mapped to TC%u\n", queue, i); ++ XGMAC_MTL_IOWRITE_BITS(pdata, queue, MTL_Q_TQOMR, ++ Q2TCMAP, i); ++ pdata->q2tc_map[queue++] = i; ++ } ++ } ++ ++ /* Map the 8 VLAN priority values to available MTL Rx queues */ ++ prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, ++ pdata->rx_q_count); ++ ppq = IEEE_8021QAZ_MAX_TCS / prio_queues; ++ ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues; ++ ++ reg = MAC_RQC2R; ++ reg_val = 0; ++ for (i = 0, prio = 0; i < prio_queues;) { ++ mask = 0; ++ for (j = 0; j < ppq; j++) { ++ DBGPR(" PRIO%u mapped to RXq%u\n", prio, i); ++ mask |= (1 << prio); ++ pdata->prio2q_map[prio++] = i; ++ } ++ ++ if (i < ppq_extra) { ++ DBGPR(" PRIO%u mapped to RXq%u\n", prio, i); ++ mask |= (1 << prio); ++ pdata->prio2q_map[prio++] = i; ++ } ++ ++ reg_val |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3)); ++ ++ if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues)) ++ continue; ++ ++ XGMAC_IOWRITE(pdata, reg, reg_val); ++ reg += MAC_RQC2_INC; ++ reg_val = 0; ++ } ++ ++ /* Select dynamic mapping of MTL Rx queue to DMA Rx channel */ ++ reg = MTL_RQDCM0R; ++ reg_val = 0; ++ for (i = 0; i < pdata->rx_q_count;) { ++ reg_val |= (0x80 << ((i++ % MTL_RQDCM_Q_PER_REG) << 3)); ++ ++ if ((i % MTL_RQDCM_Q_PER_REG) && (i != pdata->rx_q_count)) ++ continue; ++ ++ XGMAC_IOWRITE(pdata, reg, reg_val); ++ ++ reg += MTL_RQDCM_INC; ++ reg_val = 0; ++ } ++} ++ ++static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < pdata->rx_q_count; i++) { ++ /* Activate flow control when less than 4k left in fifo */ ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2); ++ ++ /* De-activate flow control when more than 6k left in fifo */ ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFD, 4); ++ } ++} ++ ++static void xgbe_config_mac_address(struct xgbe_prv_data *pdata) ++{ ++ xgbe_set_mac_address(pdata, pdata->netdev->dev_addr); ++ ++ /* Filtering is done using perfect filtering and hash filtering */ ++ if (pdata->hw_feat.hash_table_size) { ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HPF, 1); ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HUC, 1); ++ XGMAC_IOWRITE_BITS(pdata, MAC_PFR, HMC, 1); ++ } ++} ++ ++static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata) ++{ ++ unsigned int val; ++ ++ val = (pdata->netdev->mtu > XGMAC_STD_PACKET_MTU) ? 1 : 0; ++ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val); ++} ++ ++static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata) ++{ ++ if (pdata->netdev->features & NETIF_F_RXCSUM) ++ xgbe_enable_rx_csum(pdata); ++ else ++ xgbe_disable_rx_csum(pdata); ++} ++ ++static void xgbe_config_vlan_support(struct xgbe_prv_data *pdata) ++{ ++ /* Indicate that VLAN Tx CTAGs come from context descriptors */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, CSVL, 0); ++ XGMAC_IOWRITE_BITS(pdata, MAC_VLANIR, VLTI, 1); ++ ++ /* Set the current VLAN Hash Table register value */ ++ xgbe_update_vlan_hash_table(pdata); ++ ++ if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) ++ xgbe_enable_rx_vlan_filtering(pdata); ++ else ++ xgbe_disable_rx_vlan_filtering(pdata); ++ ++ if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ++ xgbe_enable_rx_vlan_stripping(pdata); ++ else ++ xgbe_disable_rx_vlan_stripping(pdata); ++} ++ ++static void xgbe_tx_mmc_int(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_mmc_stats *stats = &pdata->mmc_stats; ++ unsigned int mmc_isr = XGMAC_IOREAD(pdata, MMC_TISR); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_GB)) ++ stats->txoctetcount_gb += ++ XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_GB)) ++ stats->txframecount_gb += ++ XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_G)) ++ stats->txbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_G)) ++ stats->txmulticastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX64OCTETS_GB)) ++ stats->tx64octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX64OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX65TO127OCTETS_GB)) ++ stats->tx65to127octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX65TO127OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX128TO255OCTETS_GB)) ++ stats->tx128to255octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX128TO255OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX256TO511OCTETS_GB)) ++ stats->tx256to511octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX256TO511OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX512TO1023OCTETS_GB)) ++ stats->tx512to1023octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX512TO1023OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX1024TOMAXOCTETS_GB)) ++ stats->tx1024tomaxoctets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNICASTFRAMES_GB)) ++ stats->txunicastframes_gb += ++ XGMAC_IOREAD(pdata, MMC_TXUNICASTFRAMES_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_GB)) ++ stats->txmulticastframes_gb += ++ XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_GB)) ++ stats->txbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNDERFLOWERROR)) ++ stats->txunderflowerror += ++ XGMAC_IOREAD(pdata, MMC_TXUNDERFLOWERROR_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_G)) ++ stats->txoctetcount_g += ++ XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_G)) ++ stats->txframecount_g += ++ XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXPAUSEFRAMES)) ++ stats->txpauseframes += ++ XGMAC_IOREAD(pdata, MMC_TXPAUSEFRAMES_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXVLANFRAMES_G)) ++ stats->txvlanframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXVLANFRAMES_G_LO); ++} ++ ++static void xgbe_rx_mmc_int(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_mmc_stats *stats = &pdata->mmc_stats; ++ unsigned int mmc_isr = XGMAC_IOREAD(pdata, MMC_RISR); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFRAMECOUNT_GB)) ++ stats->rxframecount_gb += ++ XGMAC_IOREAD(pdata, MMC_RXFRAMECOUNT_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_GB)) ++ stats->rxoctetcount_gb += ++ XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_G)) ++ stats->rxoctetcount_g += ++ XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXBROADCASTFRAMES_G)) ++ stats->rxbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXBROADCASTFRAMES_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXMULTICASTFRAMES_G)) ++ stats->rxmulticastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXMULTICASTFRAMES_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXCRCERROR)) ++ stats->rxcrcerror += ++ XGMAC_IOREAD(pdata, MMC_RXCRCERROR_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXRUNTERROR)) ++ stats->rxrunterror += ++ XGMAC_IOREAD(pdata, MMC_RXRUNTERROR); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXJABBERERROR)) ++ stats->rxjabbererror += ++ XGMAC_IOREAD(pdata, MMC_RXJABBERERROR); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNDERSIZE_G)) ++ stats->rxundersize_g += ++ XGMAC_IOREAD(pdata, MMC_RXUNDERSIZE_G); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOVERSIZE_G)) ++ stats->rxoversize_g += ++ XGMAC_IOREAD(pdata, MMC_RXOVERSIZE_G); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX64OCTETS_GB)) ++ stats->rx64octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX64OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX65TO127OCTETS_GB)) ++ stats->rx65to127octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX65TO127OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX128TO255OCTETS_GB)) ++ stats->rx128to255octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX128TO255OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX256TO511OCTETS_GB)) ++ stats->rx256to511octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX256TO511OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX512TO1023OCTETS_GB)) ++ stats->rx512to1023octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX512TO1023OCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX1024TOMAXOCTETS_GB)) ++ stats->rx1024tomaxoctets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNICASTFRAMES_G)) ++ stats->rxunicastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXUNICASTFRAMES_G_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXLENGTHERROR)) ++ stats->rxlengtherror += ++ XGMAC_IOREAD(pdata, MMC_RXLENGTHERROR_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOUTOFRANGETYPE)) ++ stats->rxoutofrangetype += ++ XGMAC_IOREAD(pdata, MMC_RXOUTOFRANGETYPE_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXPAUSEFRAMES)) ++ stats->rxpauseframes += ++ XGMAC_IOREAD(pdata, MMC_RXPAUSEFRAMES_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFIFOOVERFLOW)) ++ stats->rxfifooverflow += ++ XGMAC_IOREAD(pdata, MMC_RXFIFOOVERFLOW_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXVLANFRAMES_GB)) ++ stats->rxvlanframes_gb += ++ XGMAC_IOREAD(pdata, MMC_RXVLANFRAMES_GB_LO); ++ ++ if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXWATCHDOGERROR)) ++ stats->rxwatchdogerror += ++ XGMAC_IOREAD(pdata, MMC_RXWATCHDOGERROR); ++} ++ ++static void xgbe_read_mmc_stats(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_mmc_stats *stats = &pdata->mmc_stats; ++ ++ /* Freeze counters */ ++ XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 1); ++ ++ stats->txoctetcount_gb += ++ XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_GB_LO); ++ ++ stats->txframecount_gb += ++ XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_GB_LO); ++ ++ stats->txbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_G_LO); ++ ++ stats->txmulticastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_G_LO); ++ ++ stats->tx64octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX64OCTETS_GB_LO); ++ ++ stats->tx65to127octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX65TO127OCTETS_GB_LO); ++ ++ stats->tx128to255octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX128TO255OCTETS_GB_LO); ++ ++ stats->tx256to511octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX256TO511OCTETS_GB_LO); ++ ++ stats->tx512to1023octets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX512TO1023OCTETS_GB_LO); ++ ++ stats->tx1024tomaxoctets_gb += ++ XGMAC_IOREAD(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); ++ ++ stats->txunicastframes_gb += ++ XGMAC_IOREAD(pdata, MMC_TXUNICASTFRAMES_GB_LO); ++ ++ stats->txmulticastframes_gb += ++ XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_GB_LO); ++ ++ stats->txbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_GB_LO); ++ ++ stats->txunderflowerror += ++ XGMAC_IOREAD(pdata, MMC_TXUNDERFLOWERROR_LO); ++ ++ stats->txoctetcount_g += ++ XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_G_LO); ++ ++ stats->txframecount_g += ++ XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_G_LO); ++ ++ stats->txpauseframes += ++ XGMAC_IOREAD(pdata, MMC_TXPAUSEFRAMES_LO); ++ ++ stats->txvlanframes_g += ++ XGMAC_IOREAD(pdata, MMC_TXVLANFRAMES_G_LO); ++ ++ stats->rxframecount_gb += ++ XGMAC_IOREAD(pdata, MMC_RXFRAMECOUNT_GB_LO); ++ ++ stats->rxoctetcount_gb += ++ XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_GB_LO); ++ ++ stats->rxoctetcount_g += ++ XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_G_LO); ++ ++ stats->rxbroadcastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXBROADCASTFRAMES_G_LO); ++ ++ stats->rxmulticastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXMULTICASTFRAMES_G_LO); ++ ++ stats->rxcrcerror += ++ XGMAC_IOREAD(pdata, MMC_RXCRCERROR_LO); ++ ++ stats->rxrunterror += ++ XGMAC_IOREAD(pdata, MMC_RXRUNTERROR); ++ ++ stats->rxjabbererror += ++ XGMAC_IOREAD(pdata, MMC_RXJABBERERROR); ++ ++ stats->rxundersize_g += ++ XGMAC_IOREAD(pdata, MMC_RXUNDERSIZE_G); ++ ++ stats->rxoversize_g += ++ XGMAC_IOREAD(pdata, MMC_RXOVERSIZE_G); ++ ++ stats->rx64octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX64OCTETS_GB_LO); ++ ++ stats->rx65to127octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX65TO127OCTETS_GB_LO); ++ ++ stats->rx128to255octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX128TO255OCTETS_GB_LO); ++ ++ stats->rx256to511octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX256TO511OCTETS_GB_LO); ++ ++ stats->rx512to1023octets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX512TO1023OCTETS_GB_LO); ++ ++ stats->rx1024tomaxoctets_gb += ++ XGMAC_IOREAD(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); ++ ++ stats->rxunicastframes_g += ++ XGMAC_IOREAD(pdata, MMC_RXUNICASTFRAMES_G_LO); ++ ++ stats->rxlengtherror += ++ XGMAC_IOREAD(pdata, MMC_RXLENGTHERROR_LO); ++ ++ stats->rxoutofrangetype += ++ XGMAC_IOREAD(pdata, MMC_RXOUTOFRANGETYPE_LO); ++ ++ stats->rxpauseframes += ++ XGMAC_IOREAD(pdata, MMC_RXPAUSEFRAMES_LO); ++ ++ stats->rxfifooverflow += ++ XGMAC_IOREAD(pdata, MMC_RXFIFOOVERFLOW_LO); ++ ++ stats->rxvlanframes_gb += ++ XGMAC_IOREAD(pdata, MMC_RXVLANFRAMES_GB_LO); ++ ++ stats->rxwatchdogerror += ++ XGMAC_IOREAD(pdata, MMC_RXWATCHDOGERROR); ++ ++ /* Un-freeze counters */ ++ XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 0); ++} ++ ++static void xgbe_config_mmc(struct xgbe_prv_data *pdata) ++{ ++ /* Set counters to reset on read */ ++ XGMAC_IOWRITE_BITS(pdata, MMC_CR, ROR, 1); ++ ++ /* Reset the counters */ ++ XGMAC_IOWRITE_BITS(pdata, MMC_CR, CR, 1); ++} ++ ++static void xgbe_enable_tx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Enable each Tx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 1); ++ } ++ ++ /* Enable each Tx queue */ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, ++ MTL_Q_ENABLED); ++ ++ /* Enable MAC Tx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 1); ++} ++ ++static void xgbe_disable_tx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Disable MAC Tx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0); ++ ++ /* Disable each Tx queue */ ++ for (i = 0; i < pdata->tx_q_count; i++) ++ XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, TXQEN, 0); ++ ++ /* Disable each Tx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 0); ++ } ++ ++ /*TODO: Poll to be sure the channels have stopped? ++ while (count--) { ++ if (XGMAC_IOREAD_BITS(pdata, DMA_DSR0, TPS) == 6) ++ break; ++ mdelay(1); ++ } ++ */ ++} ++ ++static void xgbe_enable_rx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int reg_val, i; ++ ++ /* Enable each Rx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 1); ++ } ++ ++ /* Enable each Rx queue */ ++ reg_val = 0; ++ for (i = 0; i < pdata->rx_q_count; i++) ++ reg_val |= (0x02 << (i << 1)); ++ XGMAC_IOWRITE(pdata, MAC_RQC0R, reg_val); ++ ++ /* Enable MAC Rx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, DCRCC, 1); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, CST, 1); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 1); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 1); ++} ++ ++static void xgbe_disable_rx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Disable MAC Rx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, DCRCC, 0); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, CST, 0); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 0); ++ XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 0); ++ ++ /* Disable each Rx queue */ ++ XGMAC_IOWRITE(pdata, MAC_RQC0R, 0); ++ ++ /* Disable each Rx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 0); ++ } ++ ++ /*TODO: Poll to be sure the channels have stopped? ++ while (count--) { ++ dma_sr0 = XGMAC_IOREAD_BITS(pdata, DMA_DSR0, RPS); ++ if (dma_sr0 == 3 || dma_sr0 == 4) ++ break; ++ mdelay(1); ++ } ++ */ ++} ++ ++static void xgbe_powerup_tx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Enable each Tx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 1); ++ } ++ ++ /* Enable MAC Tx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 1); ++} ++ ++static void xgbe_powerdown_tx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Disable MAC Tx */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_TCR, TE, 0); ++ ++ /* Disable each Tx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_TCR, ST, 0); ++ } ++ ++ /*TODO: Poll to be sure the channels have stopped? ++ while (count--) { ++ if (XGMAC_IOREAD_BITS(pdata, DMA_DSR0, TPS) == 6) ++ break; ++ mdelay(1); ++ } ++ */ ++} ++ ++static void xgbe_powerup_rx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Enable each Rx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 1); ++ } ++} ++ ++static void xgbe_powerdown_rx(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ /* Disable each Rx DMA channel */ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->rx_ring) ++ break; ++ ++ XGMAC_DMA_IOWRITE_BITS(channel, DMA_CH_RCR, SR, 0); ++ } ++ ++ /*TODO: Poll to be sure the channels have stopped? ++ while (count--) { ++ dma_sr0 = XGMAC_IOREAD_BITS(pdata, DMA_DSR0, RPS); ++ if (dma_sr0 == 3 || dma_sr0 == 4) ++ break; ++ mdelay(1); ++ } ++ */ ++} ++ ++static int xgbe_init(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ int ret; ++ ++ DBGPR("-->xgbe_init\n"); ++ ++ /* Flush Tx queues */ ++ ret = xgbe_flush_tx_queues(pdata); ++ if (ret) ++ return ret; ++ ++ /* ++ * Initialize DMA related features ++ */ ++ xgbe_config_dma_bus(pdata); ++ xgbe_config_dma_cache(pdata); ++ xgbe_config_osp_mode(pdata); ++ xgbe_config_pblx8(pdata); ++ xgbe_config_tx_pbl_val(pdata); ++ xgbe_config_rx_pbl_val(pdata); ++ xgbe_config_rx_coalesce(pdata); ++ xgbe_config_tx_coalesce(pdata); ++ xgbe_config_rx_buffer_size(pdata); ++ xgbe_config_tso_mode(pdata); ++ desc_if->wrapper_tx_desc_init(pdata); ++ desc_if->wrapper_rx_desc_init(pdata); ++ xgbe_enable_dma_interrupts(pdata); ++ ++ /* ++ * Initialize MTL related features ++ */ ++ xgbe_config_mtl_mode(pdata); ++ xgbe_config_queue_mapping(pdata); ++ xgbe_config_tsf_mode(pdata, pdata->tx_sf_mode); ++ xgbe_config_rsf_mode(pdata, pdata->rx_sf_mode); ++ xgbe_config_tx_threshold(pdata, pdata->tx_threshold); ++ xgbe_config_rx_threshold(pdata, pdata->rx_threshold); ++ xgbe_config_tx_fifo_size(pdata); ++ xgbe_config_rx_fifo_size(pdata); ++ xgbe_config_flow_control_threshold(pdata); ++ /*TODO: Error Packet and undersized good Packet forwarding enable ++ (FEP and FUP) ++ */ ++ xgbe_config_dcb_tc(pdata); ++ xgbe_config_dcb_pfc(pdata); ++ xgbe_enable_mtl_interrupts(pdata); ++ ++ /* ++ * Initialize MAC related features ++ */ ++ xgbe_config_mac_address(pdata); ++ xgbe_config_jumbo_enable(pdata); ++ xgbe_config_flow_control(pdata); ++ xgbe_config_checksum_offload(pdata); ++ xgbe_config_vlan_support(pdata); ++ xgbe_config_mmc(pdata); ++ xgbe_enable_mac_interrupts(pdata); ++ ++ DBGPR("<--xgbe_init\n"); ++ ++ return 0; ++} ++ ++void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) ++{ ++ DBGPR("-->xgbe_init_function_ptrs\n"); ++ ++ hw_if->tx_complete = xgbe_tx_complete; ++ ++ hw_if->set_promiscuous_mode = xgbe_set_promiscuous_mode; ++ hw_if->set_all_multicast_mode = xgbe_set_all_multicast_mode; ++ hw_if->add_mac_addresses = xgbe_add_mac_addresses; ++ hw_if->set_mac_address = xgbe_set_mac_address; ++ ++ hw_if->enable_rx_csum = xgbe_enable_rx_csum; ++ hw_if->disable_rx_csum = xgbe_disable_rx_csum; ++ ++ hw_if->enable_rx_vlan_stripping = xgbe_enable_rx_vlan_stripping; ++ hw_if->disable_rx_vlan_stripping = xgbe_disable_rx_vlan_stripping; ++ hw_if->enable_rx_vlan_filtering = xgbe_enable_rx_vlan_filtering; ++ hw_if->disable_rx_vlan_filtering = xgbe_disable_rx_vlan_filtering; ++ hw_if->update_vlan_hash_table = xgbe_update_vlan_hash_table; ++ ++ hw_if->read_mmd_regs = xgbe_read_mmd_regs; ++ hw_if->write_mmd_regs = xgbe_write_mmd_regs; ++ ++ hw_if->set_gmii_speed = xgbe_set_gmii_speed; ++ hw_if->set_gmii_2500_speed = xgbe_set_gmii_2500_speed; ++ hw_if->set_xgmii_speed = xgbe_set_xgmii_speed; ++ ++ hw_if->enable_tx = xgbe_enable_tx; ++ hw_if->disable_tx = xgbe_disable_tx; ++ hw_if->enable_rx = xgbe_enable_rx; ++ hw_if->disable_rx = xgbe_disable_rx; ++ ++ hw_if->powerup_tx = xgbe_powerup_tx; ++ hw_if->powerdown_tx = xgbe_powerdown_tx; ++ hw_if->powerup_rx = xgbe_powerup_rx; ++ hw_if->powerdown_rx = xgbe_powerdown_rx; ++ ++ hw_if->pre_xmit = xgbe_pre_xmit; ++ hw_if->dev_read = xgbe_dev_read; ++ hw_if->enable_int = xgbe_enable_int; ++ hw_if->disable_int = xgbe_disable_int; ++ hw_if->init = xgbe_init; ++ hw_if->exit = xgbe_exit; ++ ++ /* Descriptor related Sequences have to be initialized here */ ++ hw_if->tx_desc_init = xgbe_tx_desc_init; ++ hw_if->rx_desc_init = xgbe_rx_desc_init; ++ hw_if->tx_desc_reset = xgbe_tx_desc_reset; ++ hw_if->rx_desc_reset = xgbe_rx_desc_reset; ++ hw_if->is_last_desc = xgbe_is_last_desc; ++ hw_if->is_context_desc = xgbe_is_context_desc; ++ ++ /* For FLOW ctrl */ ++ hw_if->config_tx_flow_control = xgbe_config_tx_flow_control; ++ hw_if->config_rx_flow_control = xgbe_config_rx_flow_control; ++ ++ /* For RX coalescing */ ++ hw_if->config_rx_coalesce = xgbe_config_rx_coalesce; ++ hw_if->config_tx_coalesce = xgbe_config_tx_coalesce; ++ hw_if->usec_to_riwt = xgbe_usec_to_riwt; ++ hw_if->riwt_to_usec = xgbe_riwt_to_usec; ++ ++ /* For RX and TX threshold config */ ++ hw_if->config_rx_threshold = xgbe_config_rx_threshold; ++ hw_if->config_tx_threshold = xgbe_config_tx_threshold; ++ ++ /* For RX and TX Store and Forward Mode config */ ++ hw_if->config_rsf_mode = xgbe_config_rsf_mode; ++ hw_if->config_tsf_mode = xgbe_config_tsf_mode; ++ ++ /* For TX DMA Operating on Second Frame config */ ++ hw_if->config_osp_mode = xgbe_config_osp_mode; ++ ++ /* For RX and TX PBL config */ ++ hw_if->config_rx_pbl_val = xgbe_config_rx_pbl_val; ++ hw_if->get_rx_pbl_val = xgbe_get_rx_pbl_val; ++ hw_if->config_tx_pbl_val = xgbe_config_tx_pbl_val; ++ hw_if->get_tx_pbl_val = xgbe_get_tx_pbl_val; ++ hw_if->config_pblx8 = xgbe_config_pblx8; ++ ++ /* For MMC statistics support */ ++ hw_if->tx_mmc_int = xgbe_tx_mmc_int; ++ hw_if->rx_mmc_int = xgbe_rx_mmc_int; ++ hw_if->read_mmc_stats = xgbe_read_mmc_stats; ++ ++ /* For PTP config */ ++ hw_if->config_tstamp = xgbe_config_tstamp; ++ hw_if->update_tstamp_addend = xgbe_update_tstamp_addend; ++ hw_if->set_tstamp_time = xgbe_set_tstamp_time; ++ hw_if->get_tstamp_time = xgbe_get_tstamp_time; ++ hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; ++ ++ /* For Data Center Bridging config */ ++ hw_if->config_dcb_tc = xgbe_config_dcb_tc; ++ hw_if->config_dcb_pfc = xgbe_config_dcb_pfc; ++ ++ DBGPR("<--xgbe_init_function_ptrs\n"); ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c +new file mode 100644 +index 0000000..80dd451 +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-drv.c +@@ -0,0 +1,1864 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/spinlock.h> ++#include <linux/tcp.h> ++#include <linux/if_vlan.h> ++#include <linux/phy.h> ++#include <net/busy_poll.h> ++#include <linux/clk.h> ++#include <linux/if_ether.h> ++#include <linux/net_tstamp.h> ++#include <linux/phy.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static int xgbe_poll(struct napi_struct *, int); ++static void xgbe_set_rx_mode(struct net_device *); ++ ++static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring) ++{ ++ return (ring->rdesc_count - (ring->cur - ring->dirty)); ++} ++ ++static int xgbe_calc_rx_buf_size(struct net_device *netdev, unsigned int mtu) ++{ ++ unsigned int rx_buf_size; ++ ++ if (mtu > XGMAC_JUMBO_PACKET_MTU) { ++ netdev_alert(netdev, "MTU exceeds maximum supported value\n"); ++ return -EINVAL; ++ } ++ ++ rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; ++ if (rx_buf_size < XGBE_RX_MIN_BUF_SIZE) ++ rx_buf_size = XGBE_RX_MIN_BUF_SIZE; ++ rx_buf_size = (rx_buf_size + XGBE_RX_BUF_ALIGN - 1) & ++ ~(XGBE_RX_BUF_ALIGN - 1); ++ ++ return rx_buf_size; ++} ++ ++static void xgbe_enable_rx_tx_ints(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_channel *channel; ++ enum xgbe_int int_id; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (channel->tx_ring && channel->rx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_TI_RI; ++ else if (channel->tx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_TI; ++ else if (channel->rx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_RI; ++ else ++ continue; ++ ++ hw_if->enable_int(channel, int_id); ++ } ++} ++ ++static void xgbe_disable_rx_tx_ints(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_channel *channel; ++ enum xgbe_int int_id; ++ unsigned int i; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (channel->tx_ring && channel->rx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_TI_RI; ++ else if (channel->tx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_TI; ++ else if (channel->rx_ring) ++ int_id = XGMAC_INT_DMA_CH_SR_RI; ++ else ++ continue; ++ ++ hw_if->disable_int(channel, int_id); ++ } ++} ++ ++static irqreturn_t xgbe_isr(int irq, void *data) ++{ ++ struct xgbe_prv_data *pdata = data; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_channel *channel; ++ unsigned int dma_isr, dma_ch_isr; ++ unsigned int mac_isr, mac_tssr; ++ unsigned int i; ++ ++ /* The DMA interrupt status register also reports MAC and MTL ++ * interrupts. So for polling mode, we just need to check for ++ * this register to be non-zero ++ */ ++ dma_isr = XGMAC_IOREAD(pdata, DMA_ISR); ++ if (!dma_isr) ++ goto isr_done; ++ ++ DBGPR("-->xgbe_isr\n"); ++ ++ DBGPR(" DMA_ISR = %08x\n", dma_isr); ++ DBGPR(" DMA_DS0 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR0)); ++ DBGPR(" DMA_DS1 = %08x\n", XGMAC_IOREAD(pdata, DMA_DSR1)); ++ ++ for (i = 0; i < pdata->channel_count; i++) { ++ if (!(dma_isr & (1 << i))) ++ continue; ++ ++ channel = pdata->channel + i; ++ ++ dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR); ++ DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr); ++ ++ if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) || ++ XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) { ++ if (napi_schedule_prep(&pdata->napi)) { ++ /* Disable Tx and Rx interrupts */ ++ xgbe_disable_rx_tx_ints(pdata); ++ ++ /* Turn on polling */ ++ __napi_schedule(&pdata->napi); ++ } ++ } ++ ++ /* Restart the device on a Fatal Bus Error */ ++ if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, FBE)) ++ schedule_work(&pdata->restart_work); ++ ++ /* Clear all interrupt signals */ ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_SR, dma_ch_isr); ++ } ++ ++ if (XGMAC_GET_BITS(dma_isr, DMA_ISR, MACIS)) { ++ mac_isr = XGMAC_IOREAD(pdata, MAC_ISR); ++ ++ if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCTXIS)) ++ hw_if->tx_mmc_int(pdata); ++ ++ if (XGMAC_GET_BITS(mac_isr, MAC_ISR, MMCRXIS)) ++ hw_if->rx_mmc_int(pdata); ++ ++ if (XGMAC_GET_BITS(mac_isr, MAC_ISR, TSIS)) { ++ mac_tssr = XGMAC_IOREAD(pdata, MAC_TSSR); ++ ++ if (XGMAC_GET_BITS(mac_tssr, MAC_TSSR, TXTSC)) { ++ /* Read Tx Timestamp to clear interrupt */ ++ pdata->tx_tstamp = ++ hw_if->get_tx_tstamp(pdata); ++ schedule_work(&pdata->tx_tstamp_work); ++ } ++ } ++ } ++ ++ DBGPR(" DMA_ISR = %08x\n", XGMAC_IOREAD(pdata, DMA_ISR)); ++ ++ DBGPR("<--xgbe_isr\n"); ++ ++isr_done: ++ return IRQ_HANDLED; ++} ++ ++static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer) ++{ ++ struct xgbe_channel *channel = container_of(timer, ++ struct xgbe_channel, ++ tx_timer); ++ struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_prv_data *pdata = channel->pdata; ++ unsigned long flags; ++ ++ DBGPR("-->xgbe_tx_timer\n"); ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ++ if (napi_schedule_prep(&pdata->napi)) { ++ /* Disable Tx and Rx interrupts */ ++ xgbe_disable_rx_tx_ints(pdata); ++ ++ /* Turn on polling */ ++ __napi_schedule(&pdata->napi); ++ } ++ ++ channel->tx_timer_active = 0; ++ ++ spin_unlock_irqrestore(&ring->lock, flags); ++ ++ DBGPR("<--xgbe_tx_timer\n"); ++ ++ return HRTIMER_NORESTART; ++} ++ ++static void xgbe_init_tx_timers(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ DBGPR("-->xgbe_init_tx_timers\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ DBGPR(" %s adding tx timer\n", channel->name); ++ hrtimer_init(&channel->tx_timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ channel->tx_timer.function = xgbe_tx_timer; ++ } ++ ++ DBGPR("<--xgbe_init_tx_timers\n"); ++} ++ ++static void xgbe_stop_tx_timers(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel; ++ unsigned int i; ++ ++ DBGPR("-->xgbe_stop_tx_timers\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ if (!channel->tx_ring) ++ break; ++ ++ DBGPR(" %s deleting tx timer\n", channel->name); ++ channel->tx_timer_active = 0; ++ hrtimer_cancel(&channel->tx_timer); ++ } ++ ++ DBGPR("<--xgbe_stop_tx_timers\n"); ++} ++ ++void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata) ++{ ++ unsigned int mac_hfr0, mac_hfr1, mac_hfr2; ++ struct xgbe_hw_features *hw_feat = &pdata->hw_feat; ++ ++ DBGPR("-->xgbe_get_all_hw_features\n"); ++ ++ mac_hfr0 = XGMAC_IOREAD(pdata, MAC_HWF0R); ++ mac_hfr1 = XGMAC_IOREAD(pdata, MAC_HWF1R); ++ mac_hfr2 = XGMAC_IOREAD(pdata, MAC_HWF2R); ++ ++ memset(hw_feat, 0, sizeof(*hw_feat)); ++ ++ /* Hardware feature register 0 */ ++ hw_feat->gmii = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, GMIISEL); ++ hw_feat->vlhash = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VLHASH); ++ hw_feat->sma = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SMASEL); ++ hw_feat->rwk = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RWKSEL); ++ hw_feat->mgk = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MGKSEL); ++ hw_feat->mmc = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, MMCSEL); ++ hw_feat->aoe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, ARPOFFSEL); ++ hw_feat->ts = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSEL); ++ hw_feat->eee = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, EEESEL); ++ hw_feat->tx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TXCOESEL); ++ hw_feat->rx_coe = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, RXCOESEL); ++ hw_feat->addn_mac = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, ++ ADDMACADRSEL); ++ hw_feat->ts_src = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, TSSTSSEL); ++ hw_feat->sa_vlan_ins = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, SAVLANINS); ++ ++ /* Hardware feature register 1 */ ++ hw_feat->rx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ++ RXFIFOSIZE); ++ hw_feat->tx_fifo_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ++ TXFIFOSIZE); ++ hw_feat->dcb = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DCBEN); ++ hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN); ++ hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN); ++ hw_feat->dma_debug = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA); ++ hw_feat->tc_cnt = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC); ++ hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ++ HASHTBLSZ); ++ hw_feat->l3l4_filter_num = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, ++ L3L4FNUM); ++ ++ /* Hardware feature register 2 */ ++ hw_feat->rx_q_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXQCNT); ++ hw_feat->tx_q_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXQCNT); ++ hw_feat->rx_ch_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, RXCHCNT); ++ hw_feat->tx_ch_cnt = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, TXCHCNT); ++ hw_feat->pps_out_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, PPSOUTNUM); ++ hw_feat->aux_snap_num = XGMAC_GET_BITS(mac_hfr2, MAC_HWF2R, AUXSNAPNUM); ++ ++ /* Translate the Hash Table size into actual number */ ++ switch (hw_feat->hash_table_size) { ++ case 0: ++ break; ++ case 1: ++ hw_feat->hash_table_size = 64; ++ break; ++ case 2: ++ hw_feat->hash_table_size = 128; ++ break; ++ case 3: ++ hw_feat->hash_table_size = 256; ++ break; ++ } ++ ++ /* The Queue and Channel counts are zero based so increment them ++ * to get the actual number ++ */ ++ hw_feat->rx_q_cnt++; ++ hw_feat->tx_q_cnt++; ++ hw_feat->rx_ch_cnt++; ++ hw_feat->tx_ch_cnt++; ++ ++ /* A0 does not support NUMTC, hardcode it for now */ ++ hw_feat->tc_cnt = XGBE_TC_CNT; ++ ++ DBGPR("<--xgbe_get_all_hw_features\n"); ++} ++ ++static void xgbe_napi_enable(struct xgbe_prv_data *pdata, unsigned int add) ++{ ++ if (add) ++ netif_napi_add(pdata->netdev, &pdata->napi, xgbe_poll, ++ NAPI_POLL_WEIGHT); ++ napi_enable(&pdata->napi); ++} ++ ++static void xgbe_napi_disable(struct xgbe_prv_data *pdata, unsigned int del) ++{ ++ napi_disable(&pdata->napi); ++ ++ if (del) ++ netif_napi_del(&pdata->napi); ++} ++ ++void xgbe_init_tx_coalesce(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ ++ DBGPR("-->xgbe_init_tx_coalesce\n"); ++ ++ pdata->tx_usecs = XGMAC_INIT_DMA_TX_USECS; ++ pdata->tx_frames = XGMAC_INIT_DMA_TX_FRAMES; ++ ++ hw_if->config_tx_coalesce(pdata); ++ ++ DBGPR("<--xgbe_init_tx_coalesce\n"); ++} ++ ++void xgbe_init_rx_coalesce(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ ++ DBGPR("-->xgbe_init_rx_coalesce\n"); ++ ++ pdata->rx_riwt = hw_if->usec_to_riwt(pdata, XGMAC_INIT_DMA_RX_USECS); ++ pdata->rx_frames = XGMAC_INIT_DMA_RX_FRAMES; ++ ++ hw_if->config_rx_coalesce(pdata); ++ ++ DBGPR("<--xgbe_init_rx_coalesce\n"); ++} ++ ++static void xgbe_free_tx_skbuff(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ struct xgbe_channel *channel; ++ struct xgbe_ring *ring; ++ struct xgbe_ring_data *rdata; ++ unsigned int i, j; ++ ++ DBGPR("-->xgbe_free_tx_skbuff\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ ring = channel->tx_ring; ++ if (!ring) ++ break; ++ ++ for (j = 0; j < ring->rdesc_count; j++) { ++ rdata = XGBE_GET_DESC_DATA(ring, j); ++ desc_if->unmap_skb(pdata, rdata); ++ } ++ } ++ ++ DBGPR("<--xgbe_free_tx_skbuff\n"); ++} ++ ++static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ struct xgbe_channel *channel; ++ struct xgbe_ring *ring; ++ struct xgbe_ring_data *rdata; ++ unsigned int i, j; ++ ++ DBGPR("-->xgbe_free_rx_skbuff\n"); ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ ring = channel->rx_ring; ++ if (!ring) ++ break; ++ ++ for (j = 0; j < ring->rdesc_count; j++) { ++ rdata = XGBE_GET_DESC_DATA(ring, j); ++ desc_if->unmap_skb(pdata, rdata); ++ } ++ } ++ ++ DBGPR("<--xgbe_free_rx_skbuff\n"); ++} ++ ++static void xgbe_adjust_link(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct phy_device *phydev = pdata->phydev; ++ int new_state = 0; ++ ++ if (phydev == NULL) ++ return; ++ ++ if (phydev->link) { ++ /* Flow control support */ ++ if (pdata->pause_autoneg) { ++ if (phydev->pause || phydev->asym_pause) { ++ pdata->tx_pause = 1; ++ pdata->rx_pause = 1; ++ } else { ++ pdata->tx_pause = 0; ++ pdata->rx_pause = 0; ++ } ++ } ++ ++ if (pdata->tx_pause != pdata->phy_tx_pause) { ++ hw_if->config_tx_flow_control(pdata); ++ pdata->phy_tx_pause = pdata->tx_pause; ++ } ++ ++ if (pdata->rx_pause != pdata->phy_rx_pause) { ++ hw_if->config_rx_flow_control(pdata); ++ pdata->phy_rx_pause = pdata->rx_pause; ++ } ++ ++ /* Speed support */ ++ if (phydev->speed != pdata->phy_speed) { ++ new_state = 1; ++ ++ switch (phydev->speed) { ++ case SPEED_10000: ++ hw_if->set_xgmii_speed(pdata); ++ break; ++ ++ case SPEED_2500: ++ hw_if->set_gmii_2500_speed(pdata); ++ break; ++ ++ case SPEED_1000: ++ hw_if->set_gmii_speed(pdata); ++ break; ++ } ++ pdata->phy_speed = phydev->speed; ++ } ++ ++ if (phydev->link != pdata->phy_link) { ++ new_state = 1; ++ pdata->phy_link = 1; ++ } ++ } else if (pdata->phy_link) { ++ new_state = 1; ++ pdata->phy_link = 0; ++ pdata->phy_speed = SPEED_UNKNOWN; ++ } ++ ++ if (new_state) ++ phy_print_status(phydev); ++} ++ ++static int xgbe_phy_init(struct xgbe_prv_data *pdata) ++{ ++ struct net_device *netdev = pdata->netdev; ++ struct phy_device *phydev = pdata->phydev; ++ int ret; ++ ++ pdata->phy_link = -1; ++ pdata->phy_speed = SPEED_UNKNOWN; ++ pdata->phy_tx_pause = pdata->tx_pause; ++ pdata->phy_rx_pause = pdata->rx_pause; ++ ++ ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link, ++ pdata->phy_mode); ++ if (ret) { ++ netdev_err(netdev, "phy_connect_direct failed\n"); ++ return ret; ++ } ++ ++ if (!phydev->drv || (phydev->drv->phy_id == 0)) { ++ netdev_err(netdev, "phy_id not valid\n"); ++ ret = -ENODEV; ++ goto err_phy_connect; ++ } ++ DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n", ++ dev_name(&phydev->dev), phydev->link); ++ ++ return 0; ++ ++err_phy_connect: ++ phy_disconnect(phydev); ++ ++ return ret; ++} ++ ++static void xgbe_phy_exit(struct xgbe_prv_data *pdata) ++{ ++ if (!pdata->phydev) ++ return; ++ ++ phy_disconnect(pdata->phydev); ++} ++ ++int xgbe_powerdown(struct net_device *netdev, unsigned int caller) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned long flags; ++ ++ DBGPR("-->xgbe_powerdown\n"); ++ ++ if (!netif_running(netdev) || ++ (caller == XGMAC_IOCTL_CONTEXT && pdata->power_down)) { ++ netdev_alert(netdev, "Device is already powered down\n"); ++ DBGPR("<--xgbe_powerdown\n"); ++ return -EINVAL; ++ } ++ ++ phy_stop(pdata->phydev); ++ ++ spin_lock_irqsave(&pdata->lock, flags); ++ ++ if (caller == XGMAC_DRIVER_CONTEXT) ++ netif_device_detach(netdev); ++ ++ netif_tx_stop_all_queues(netdev); ++ xgbe_napi_disable(pdata, 0); ++ ++ /* Powerdown Tx/Rx */ ++ hw_if->powerdown_tx(pdata); ++ hw_if->powerdown_rx(pdata); ++ ++ pdata->power_down = 1; ++ ++ spin_unlock_irqrestore(&pdata->lock, flags); ++ ++ DBGPR("<--xgbe_powerdown\n"); ++ ++ return 0; ++} ++ ++int xgbe_powerup(struct net_device *netdev, unsigned int caller) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned long flags; ++ ++ DBGPR("-->xgbe_powerup\n"); ++ ++ if (!netif_running(netdev) || ++ (caller == XGMAC_IOCTL_CONTEXT && !pdata->power_down)) { ++ netdev_alert(netdev, "Device is already powered up\n"); ++ DBGPR("<--xgbe_powerup\n"); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&pdata->lock, flags); ++ ++ pdata->power_down = 0; ++ ++ phy_start(pdata->phydev); ++ ++ /* Enable Tx/Rx */ ++ hw_if->powerup_tx(pdata); ++ hw_if->powerup_rx(pdata); ++ ++ if (caller == XGMAC_DRIVER_CONTEXT) ++ netif_device_attach(netdev); ++ ++ xgbe_napi_enable(pdata, 0); ++ netif_tx_start_all_queues(netdev); ++ ++ spin_unlock_irqrestore(&pdata->lock, flags); ++ ++ DBGPR("<--xgbe_powerup\n"); ++ ++ return 0; ++} ++ ++static int xgbe_start(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct net_device *netdev = pdata->netdev; ++ ++ DBGPR("-->xgbe_start\n"); ++ ++ xgbe_set_rx_mode(netdev); ++ ++ hw_if->init(pdata); ++ ++ phy_start(pdata->phydev); ++ ++ hw_if->enable_tx(pdata); ++ hw_if->enable_rx(pdata); ++ ++ xgbe_init_tx_timers(pdata); ++ ++ xgbe_napi_enable(pdata, 1); ++ netif_tx_start_all_queues(netdev); ++ ++ DBGPR("<--xgbe_start\n"); ++ ++ return 0; ++} ++ ++static void xgbe_stop(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct net_device *netdev = pdata->netdev; ++ ++ DBGPR("-->xgbe_stop\n"); ++ ++ phy_stop(pdata->phydev); ++ ++ netif_tx_stop_all_queues(netdev); ++ xgbe_napi_disable(pdata, 1); ++ ++ xgbe_stop_tx_timers(pdata); ++ ++ hw_if->disable_tx(pdata); ++ hw_if->disable_rx(pdata); ++ ++ DBGPR("<--xgbe_stop\n"); ++} ++ ++static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset) ++{ ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ ++ DBGPR("-->xgbe_restart_dev\n"); ++ ++ /* If not running, "restart" will happen on open */ ++ if (!netif_running(pdata->netdev)) ++ return; ++ ++ xgbe_stop(pdata); ++ synchronize_irq(pdata->irq_number); ++ ++ xgbe_free_tx_skbuff(pdata); ++ xgbe_free_rx_skbuff(pdata); ++ ++ /* Issue software reset to device if requested */ ++ if (reset) ++ hw_if->exit(pdata); ++ ++ xgbe_start(pdata); ++ ++ DBGPR("<--xgbe_restart_dev\n"); ++} ++ ++static void xgbe_restart(struct work_struct *work) ++{ ++ struct xgbe_prv_data *pdata = container_of(work, ++ struct xgbe_prv_data, ++ restart_work); ++ ++ rtnl_lock(); ++ ++ xgbe_restart_dev(pdata, 1); ++ ++ rtnl_unlock(); ++} ++ ++static void xgbe_tx_tstamp(struct work_struct *work) ++{ ++ struct xgbe_prv_data *pdata = container_of(work, ++ struct xgbe_prv_data, ++ tx_tstamp_work); ++ struct skb_shared_hwtstamps hwtstamps; ++ u64 nsec; ++ unsigned long flags; ++ ++ if (pdata->tx_tstamp) { ++ nsec = timecounter_cyc2time(&pdata->tstamp_tc, ++ pdata->tx_tstamp); ++ ++ memset(&hwtstamps, 0, sizeof(hwtstamps)); ++ hwtstamps.hwtstamp = ns_to_ktime(nsec); ++ skb_tstamp_tx(pdata->tx_tstamp_skb, &hwtstamps); ++ } ++ ++ dev_kfree_skb_any(pdata->tx_tstamp_skb); ++ ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ pdata->tx_tstamp_skb = NULL; ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++} ++ ++static int xgbe_get_hwtstamp_settings(struct xgbe_prv_data *pdata, ++ struct ifreq *ifreq) ++{ ++ if (copy_to_user(ifreq->ifr_data, &pdata->tstamp_config, ++ sizeof(pdata->tstamp_config))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static int xgbe_set_hwtstamp_settings(struct xgbe_prv_data *pdata, ++ struct ifreq *ifreq) ++{ ++ struct hwtstamp_config config; ++ unsigned int mac_tscr; ++ ++ if (copy_from_user(&config, ifreq->ifr_data, sizeof(config))) ++ return -EFAULT; ++ ++ if (config.flags) ++ return -EINVAL; ++ ++ mac_tscr = 0; ++ ++ switch (config.tx_type) { ++ case HWTSTAMP_TX_OFF: ++ break; ++ ++ case HWTSTAMP_TX_ON: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ default: ++ return -ERANGE; ++ } ++ ++ switch (config.rx_filter) { ++ case HWTSTAMP_FILTER_NONE: ++ break; ++ ++ case HWTSTAMP_FILTER_ALL: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENALL, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2, UDP, any kind of event packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ /* PTP v1, UDP, any kind of event packet */ ++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2, UDP, Sync packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ /* PTP v1, UDP, Sync packet */ ++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2, UDP, Delay_req packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ /* PTP v1, UDP, Delay_req packet */ ++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* 802.AS1, Ethernet, any kind of event packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* 802.AS1, Ethernet, Sync packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* 802.AS1, Ethernet, Delay_req packet */ ++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, AV8021ASMEN, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2/802.AS1, any layer, any kind of event packet */ ++ case HWTSTAMP_FILTER_PTP_V2_EVENT: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, SNAPTYPSEL, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2/802.AS1, any layer, Sync packet */ ++ case HWTSTAMP_FILTER_PTP_V2_SYNC: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ /* PTP v2/802.AS1, any layer, Delay_req packet */ ++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSVER2ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV4ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSIPV6ENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSMSTRENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSEVNTENA, 1); ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ break; ++ ++ default: ++ return -ERANGE; ++ } ++ ++ pdata->hw_if.config_tstamp(pdata, mac_tscr); ++ ++ memcpy(&pdata->tstamp_config, &config, sizeof(config)); ++ ++ return 0; ++} ++ ++static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata, ++ struct sk_buff *skb, ++ struct xgbe_packet_data *packet) ++{ ++ unsigned long flags; ++ ++ if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) { ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ if (pdata->tx_tstamp_skb) { ++ /* Another timestamp in progress, ignore this one */ ++ XGMAC_SET_BITS(packet->attributes, ++ TX_PACKET_ATTRIBUTES, PTP, 0); ++ } else { ++ pdata->tx_tstamp_skb = skb_get(skb); ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++ } ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++ } ++ ++ if (!XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, PTP)) ++ skb_tx_timestamp(skb); ++} ++ ++static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet) ++{ ++ if (vlan_tx_tag_present(skb)) ++ packet->vlan_ctag = vlan_tx_tag_get(skb); ++} ++ ++static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet) ++{ ++ int ret; ++ ++ if (!XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ TSO_ENABLE)) ++ return 0; ++ ++ ret = skb_cow_head(skb, 0); ++ if (ret) ++ return ret; ++ ++ packet->header_len = skb_transport_offset(skb) + tcp_hdrlen(skb); ++ packet->tcp_header_len = tcp_hdrlen(skb); ++ packet->tcp_payload_len = skb->len - packet->header_len; ++ packet->mss = skb_shinfo(skb)->gso_size; ++ DBGPR(" packet->header_len=%u\n", packet->header_len); ++ DBGPR(" packet->tcp_header_len=%u, packet->tcp_payload_len=%u\n", ++ packet->tcp_header_len, packet->tcp_payload_len); ++ DBGPR(" packet->mss=%u\n", packet->mss); ++ ++ return 0; ++} ++ ++static int xgbe_is_tso(struct sk_buff *skb) ++{ ++ if (skb->ip_summed != CHECKSUM_PARTIAL) ++ return 0; ++ ++ if (!skb_is_gso(skb)) ++ return 0; ++ ++ DBGPR(" TSO packet to be processed\n"); ++ ++ return 1; ++} ++ ++static void xgbe_packet_info(struct xgbe_prv_data *pdata, ++ struct xgbe_ring *ring, struct sk_buff *skb, ++ struct xgbe_packet_data *packet) ++{ ++ struct skb_frag_struct *frag; ++ unsigned int context_desc; ++ unsigned int len; ++ unsigned int i; ++ ++ context_desc = 0; ++ packet->rdesc_count = 0; ++ ++ if (xgbe_is_tso(skb)) { ++ /* TSO requires an extra desriptor if mss is different */ ++ if (skb_shinfo(skb)->gso_size != ring->tx.cur_mss) { ++ context_desc = 1; ++ packet->rdesc_count++; ++ } ++ ++ /* TSO requires an extra desriptor for TSO header */ ++ packet->rdesc_count++; ++ ++ XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ TSO_ENABLE, 1); ++ XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ CSUM_ENABLE, 1); ++ } else if (skb->ip_summed == CHECKSUM_PARTIAL) ++ XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ CSUM_ENABLE, 1); ++ ++ if (vlan_tx_tag_present(skb)) { ++ /* VLAN requires an extra descriptor if tag is different */ ++ if (vlan_tx_tag_get(skb) != ring->tx.cur_vlan_ctag) ++ /* We can share with the TSO context descriptor */ ++ if (!context_desc) { ++ context_desc = 1; ++ packet->rdesc_count++; ++ } ++ ++ XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ VLAN_CTAG, 1); ++ } ++ ++ if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && ++ (pdata->tstamp_config.tx_type == HWTSTAMP_TX_ON)) ++ XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, ++ PTP, 1); ++ ++ for (len = skb_headlen(skb); len;) { ++ packet->rdesc_count++; ++ len -= min_t(unsigned int, len, XGBE_TX_MAX_BUF_SIZE); ++ } ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ frag = &skb_shinfo(skb)->frags[i]; ++ for (len = skb_frag_size(frag); len; ) { ++ packet->rdesc_count++; ++ len -= min_t(unsigned int, len, XGBE_TX_MAX_BUF_SIZE); ++ } ++ } ++} ++ ++static int xgbe_open(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ int ret; ++ ++ DBGPR("-->xgbe_open\n"); ++ ++ /* Initialize the phy */ ++ ret = xgbe_phy_init(pdata); ++ if (ret) ++ return ret; ++ ++ /* Enable the clocks */ ++ ret = clk_prepare_enable(pdata->sysclk); ++ if (ret) { ++ netdev_alert(netdev, "dma clk_prepare_enable failed\n"); ++ goto err_phy_init; ++ } ++ ++ ret = clk_prepare_enable(pdata->ptpclk); ++ if (ret) { ++ netdev_alert(netdev, "ptp clk_prepare_enable failed\n"); ++ goto err_sysclk; ++ } ++ ++ /* Calculate the Rx buffer size before allocating rings */ ++ ret = xgbe_calc_rx_buf_size(netdev, netdev->mtu); ++ if (ret < 0) ++ goto err_ptpclk; ++ pdata->rx_buf_size = ret; ++ ++ /* Allocate the ring descriptors and buffers */ ++ ret = desc_if->alloc_ring_resources(pdata); ++ if (ret) ++ goto err_ptpclk; ++ ++ /* Initialize the device restart and Tx timestamp work struct */ ++ INIT_WORK(&pdata->restart_work, xgbe_restart); ++ INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); ++ ++ /* Request interrupts */ ++ ret = devm_request_irq(pdata->dev, netdev->irq, xgbe_isr, 0, ++ netdev->name, pdata); ++ if (ret) { ++ netdev_alert(netdev, "error requesting irq %d\n", ++ pdata->irq_number); ++ goto err_irq; ++ } ++ pdata->irq_number = netdev->irq; ++ ++ ret = xgbe_start(pdata); ++ if (ret) ++ goto err_start; ++ ++ DBGPR("<--xgbe_open\n"); ++ ++ return 0; ++ ++err_start: ++ hw_if->exit(pdata); ++ ++ devm_free_irq(pdata->dev, pdata->irq_number, pdata); ++ pdata->irq_number = 0; ++ ++err_irq: ++ desc_if->free_ring_resources(pdata); ++ ++err_ptpclk: ++ clk_disable_unprepare(pdata->ptpclk); ++ ++err_sysclk: ++ clk_disable_unprepare(pdata->sysclk); ++ ++err_phy_init: ++ xgbe_phy_exit(pdata); ++ ++ return ret; ++} ++ ++static int xgbe_close(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ ++ DBGPR("-->xgbe_close\n"); ++ ++ /* Stop the device */ ++ xgbe_stop(pdata); ++ ++ /* Issue software reset to device */ ++ hw_if->exit(pdata); ++ ++ /* Free all the ring data */ ++ desc_if->free_ring_resources(pdata); ++ ++ /* Release the interrupt */ ++ if (pdata->irq_number != 0) { ++ devm_free_irq(pdata->dev, pdata->irq_number, pdata); ++ pdata->irq_number = 0; ++ } ++ ++ /* Disable the clocks */ ++ clk_disable_unprepare(pdata->ptpclk); ++ clk_disable_unprepare(pdata->sysclk); ++ ++ /* Release the phy */ ++ xgbe_phy_exit(pdata); ++ ++ DBGPR("<--xgbe_close\n"); ++ ++ return 0; ++} ++ ++static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ struct xgbe_channel *channel; ++ struct xgbe_ring *ring; ++ struct xgbe_packet_data *packet; ++ unsigned long flags; ++ int ret; ++ ++ DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len); ++ ++ channel = pdata->channel + skb->queue_mapping; ++ ring = channel->tx_ring; ++ packet = &ring->packet_data; ++ ++ ret = NETDEV_TX_OK; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ++ if (skb->len == 0) { ++ netdev_err(netdev, "empty skb received from stack\n"); ++ dev_kfree_skb_any(skb); ++ goto tx_netdev_return; ++ } ++ ++ /* Calculate preliminary packet info */ ++ memset(packet, 0, sizeof(*packet)); ++ xgbe_packet_info(pdata, ring, skb, packet); ++ ++ /* Check that there are enough descriptors available */ ++ if (packet->rdesc_count > xgbe_tx_avail_desc(ring)) { ++ DBGPR(" Tx queue stopped, not enough descriptors available\n"); ++ netif_stop_subqueue(netdev, channel->queue_index); ++ ring->tx.queue_stopped = 1; ++ ret = NETDEV_TX_BUSY; ++ goto tx_netdev_return; ++ } ++ ++ ret = xgbe_prep_tso(skb, packet); ++ if (ret) { ++ netdev_err(netdev, "error processing TSO packet\n"); ++ dev_kfree_skb_any(skb); ++ goto tx_netdev_return; ++ } ++ xgbe_prep_vlan(skb, packet); ++ ++ if (!desc_if->map_tx_skb(channel, skb)) { ++ dev_kfree_skb_any(skb); ++ goto tx_netdev_return; ++ } ++ ++ xgbe_prep_tx_tstamp(pdata, skb, packet); ++ ++ /* Configure required descriptor fields for transmission */ ++ hw_if->pre_xmit(channel); ++ ++#ifdef XGMAC_ENABLE_TX_PKT_DUMP ++ xgbe_print_pkt(netdev, skb, true); ++#endif ++ ++tx_netdev_return: ++ spin_unlock_irqrestore(&ring->lock, flags); ++ ++ DBGPR("<--xgbe_xmit\n"); ++ ++ return ret; ++} ++ ++static void xgbe_set_rx_mode(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned int pr_mode, am_mode; ++ ++ DBGPR("-->xgbe_set_rx_mode\n"); ++ ++ pr_mode = ((netdev->flags & IFF_PROMISC) != 0); ++ am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); ++ ++ hw_if->set_promiscuous_mode(pdata, pr_mode); ++ hw_if->set_all_multicast_mode(pdata, am_mode); ++ ++ hw_if->add_mac_addresses(pdata); ++ ++ DBGPR("<--xgbe_set_rx_mode\n"); ++} ++ ++static int xgbe_set_mac_address(struct net_device *netdev, void *addr) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct sockaddr *saddr = addr; ++ ++ DBGPR("-->xgbe_set_mac_address\n"); ++ ++ if (!is_valid_ether_addr(saddr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ memcpy(netdev->dev_addr, saddr->sa_data, netdev->addr_len); ++ ++ hw_if->set_mac_address(pdata, netdev->dev_addr); ++ ++ DBGPR("<--xgbe_set_mac_address\n"); ++ ++ return 0; ++} ++ ++static int xgbe_ioctl(struct net_device *netdev, struct ifreq *ifreq, int cmd) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ int ret; ++ ++ switch (cmd) { ++ case SIOCGHWTSTAMP: ++ ret = xgbe_get_hwtstamp_settings(pdata, ifreq); ++ break; ++ ++ case SIOCSHWTSTAMP: ++ ret = xgbe_set_hwtstamp_settings(pdata, ifreq); ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int xgbe_change_mtu(struct net_device *netdev, int mtu) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ int ret; ++ ++ DBGPR("-->xgbe_change_mtu\n"); ++ ++ ret = xgbe_calc_rx_buf_size(netdev, mtu); ++ if (ret < 0) ++ return ret; ++ ++ pdata->rx_buf_size = ret; ++ netdev->mtu = mtu; ++ ++ xgbe_restart_dev(pdata, 0); ++ ++ DBGPR("<--xgbe_change_mtu\n"); ++ ++ return 0; ++} ++ ++static struct rtnl_link_stats64 *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; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ pdata->hw_if.read_mmc_stats(pdata); ++ ++ s->rx_packets = pstats->rxframecount_gb; ++ s->rx_bytes = pstats->rxoctetcount_gb; ++ s->rx_errors = pstats->rxframecount_gb - ++ pstats->rxbroadcastframes_g - ++ pstats->rxmulticastframes_g - ++ pstats->rxunicastframes_g; ++ s->multicast = pstats->rxmulticastframes_g; ++ s->rx_length_errors = pstats->rxlengtherror; ++ s->rx_crc_errors = pstats->rxcrcerror; ++ s->rx_fifo_errors = pstats->rxfifooverflow; ++ ++ s->tx_packets = pstats->txframecount_gb; ++ s->tx_bytes = pstats->txoctetcount_gb; ++ s->tx_errors = pstats->txframecount_gb - pstats->txframecount_g; ++ 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, ++ u16 vid) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ set_bit(vid, pdata->active_vlans); ++ hw_if->update_vlan_hash_table(pdata); ++ ++ DBGPR("<--%s\n", __func__); ++ ++ return 0; ++} ++ ++static int xgbe_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, ++ u16 vid) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ clear_bit(vid, pdata->active_vlans); ++ hw_if->update_vlan_hash_table(pdata); ++ ++ DBGPR("<--%s\n", __func__); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void xgbe_poll_controller(struct net_device *netdev) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ DBGPR("-->xgbe_poll_controller\n"); ++ ++ disable_irq(pdata->irq_number); ++ ++ xgbe_isr(pdata->irq_number, pdata); ++ ++ enable_irq(pdata->irq_number); ++ ++ DBGPR("<--xgbe_poll_controller\n"); ++} ++#endif /* End CONFIG_NET_POLL_CONTROLLER */ ++ ++static int xgbe_setup_tc(struct net_device *netdev, u8 tc) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ unsigned int offset, queue; ++ u8 i; ++ ++ if (tc && (tc != pdata->hw_feat.tc_cnt)) ++ return -EINVAL; ++ ++ if (tc) { ++ netdev_set_num_tc(netdev, tc); ++ for (i = 0, queue = 0, offset = 0; i < tc; i++) { ++ while ((queue < pdata->tx_q_count) && ++ (pdata->q2tc_map[queue] == i)) ++ queue++; ++ ++ DBGPR(" TC%u using TXq%u-%u\n", i, offset, queue - 1); ++ netdev_set_tc_queue(netdev, i, queue - offset, offset); ++ offset = queue; ++ } ++ } else { ++ netdev_reset_tc(netdev); ++ } ++ ++ return 0; ++} ++ ++static int xgbe_set_features(struct net_device *netdev, ++ netdev_features_t features) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned int rxcsum, rxvlan, rxvlan_filter; ++ ++ rxcsum = pdata->netdev_features & NETIF_F_RXCSUM; ++ rxvlan = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_RX; ++ rxvlan_filter = pdata->netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER; ++ ++ if ((features & NETIF_F_RXCSUM) && !rxcsum) ++ hw_if->enable_rx_csum(pdata); ++ else if (!(features & NETIF_F_RXCSUM) && rxcsum) ++ hw_if->disable_rx_csum(pdata); ++ ++ if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) ++ hw_if->enable_rx_vlan_stripping(pdata); ++ else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan) ++ hw_if->disable_rx_vlan_stripping(pdata); ++ ++ if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && !rxvlan_filter) ++ hw_if->enable_rx_vlan_filtering(pdata); ++ else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter) ++ hw_if->disable_rx_vlan_filtering(pdata); ++ ++ pdata->netdev_features = features; ++ ++ DBGPR("<--xgbe_set_features\n"); ++ ++ return 0; ++} ++ ++static const struct net_device_ops xgbe_netdev_ops = { ++ .ndo_open = xgbe_open, ++ .ndo_stop = xgbe_close, ++ .ndo_start_xmit = xgbe_xmit, ++ .ndo_set_rx_mode = xgbe_set_rx_mode, ++ .ndo_set_mac_address = xgbe_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_do_ioctl = xgbe_ioctl, ++ .ndo_change_mtu = xgbe_change_mtu, ++ .ndo_get_stats64 = xgbe_get_stats64, ++ .ndo_vlan_rx_add_vid = xgbe_vlan_rx_add_vid, ++ .ndo_vlan_rx_kill_vid = xgbe_vlan_rx_kill_vid, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = xgbe_poll_controller, ++#endif ++ .ndo_setup_tc = xgbe_setup_tc, ++ .ndo_set_features = xgbe_set_features, ++}; ++ ++struct net_device_ops *xgbe_get_netdev_ops(void) ++{ ++ return (struct net_device_ops *)&xgbe_netdev_ops; ++} ++ ++static void xgbe_rx_refresh(struct xgbe_channel *channel) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ struct xgbe_ring *ring = channel->rx_ring; ++ struct xgbe_ring_data *rdata; ++ ++ desc_if->realloc_skb(channel); ++ ++ /* Update the Rx Tail Pointer Register with address of ++ * the last cleaned entry */ ++ rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1); ++ XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, ++ lower_32_bits(rdata->rdesc_dma)); ++} ++ ++static int xgbe_tx_poll(struct xgbe_channel *channel) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_desc_if *desc_if = &pdata->desc_if; ++ struct xgbe_ring *ring = channel->tx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ struct net_device *netdev = pdata->netdev; ++ unsigned long flags; ++ int processed = 0; ++ ++ DBGPR("-->xgbe_tx_poll\n"); ++ ++ /* Nothing to do if there isn't a Tx ring for this channel */ ++ if (!ring) ++ return 0; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ ++ while ((processed < XGBE_TX_DESC_MAX_PROC) && ++ (ring->dirty < ring->cur)) { ++ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty); ++ rdesc = rdata->rdesc; ++ ++ if (!hw_if->tx_complete(rdesc)) ++ break; ++ ++#ifdef XGMAC_ENABLE_TX_DESC_DUMP ++ xgbe_dump_tx_desc(ring, ring->dirty, 1, 0); ++#endif ++ ++ /* Free the SKB and reset the descriptor for re-use */ ++ desc_if->unmap_skb(pdata, rdata); ++ hw_if->tx_desc_reset(rdata); ++ ++ processed++; ++ ring->dirty++; ++ } ++ ++ if ((ring->tx.queue_stopped == 1) && ++ (xgbe_tx_avail_desc(ring) > XGBE_TX_DESC_MIN_FREE)) { ++ ring->tx.queue_stopped = 0; ++ netif_wake_subqueue(netdev, channel->queue_index); ++ } ++ ++ DBGPR("<--xgbe_tx_poll: processed=%d\n", processed); ++ ++ spin_unlock_irqrestore(&ring->lock, flags); ++ ++ return processed; ++} ++ ++static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) ++{ ++ struct xgbe_prv_data *pdata = channel->pdata; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ struct xgbe_ring *ring = channel->rx_ring; ++ struct xgbe_ring_data *rdata; ++ struct xgbe_packet_data *packet; ++ struct net_device *netdev = pdata->netdev; ++ struct sk_buff *skb; ++ struct skb_shared_hwtstamps *hwtstamps; ++ unsigned int incomplete, error, context_next, context; ++ unsigned int len, put_len, max_len; ++ int received = 0; ++ ++ DBGPR("-->xgbe_rx_poll: budget=%d\n", budget); ++ ++ /* Nothing to do if there isn't a Rx ring for this channel */ ++ if (!ring) ++ return 0; ++ ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ packet = &ring->packet_data; ++ while (received < budget) { ++ DBGPR(" cur = %d\n", ring->cur); ++ ++ /* First time in loop see if we need to restore state */ ++ if (!received && rdata->state_saved) { ++ incomplete = rdata->state.incomplete; ++ context_next = rdata->state.context_next; ++ skb = rdata->state.skb; ++ error = rdata->state.error; ++ len = rdata->state.len; ++ } else { ++ memset(packet, 0, sizeof(*packet)); ++ incomplete = 0; ++ context_next = 0; ++ skb = NULL; ++ error = 0; ++ len = 0; ++ } ++ ++read_again: ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ ++ if (ring->dirty > (XGBE_RX_DESC_CNT >> 3)) ++ xgbe_rx_refresh(channel); ++ ++ if (hw_if->dev_read(channel)) ++ break; ++ ++ received++; ++ ring->cur++; ++ ring->dirty++; ++ ++ dma_unmap_single(pdata->dev, rdata->skb_dma, ++ rdata->skb_dma_len, DMA_FROM_DEVICE); ++ rdata->skb_dma = 0; ++ ++ incomplete = XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, ++ INCOMPLETE); ++ context_next = XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, ++ CONTEXT_NEXT); ++ context = XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, ++ CONTEXT); ++ ++ /* Earlier error, just drain the remaining data */ ++ if ((incomplete || context_next) && error) ++ goto read_again; ++ ++ if (error || packet->errors) { ++ if (packet->errors) ++ DBGPR("Error in received packet\n"); ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ if (!context) { ++ put_len = rdata->len - len; ++ if (skb) { ++ if (pskb_expand_head(skb, 0, put_len, ++ GFP_ATOMIC)) { ++ DBGPR("pskb_expand_head error\n"); ++ if (incomplete) { ++ error = 1; ++ goto read_again; ++ } ++ ++ dev_kfree_skb(skb); ++ continue; ++ } ++ memcpy(skb_tail_pointer(skb), rdata->skb->data, ++ put_len); ++ } else { ++ skb = rdata->skb; ++ rdata->skb = NULL; ++ } ++ skb_put(skb, put_len); ++ len += put_len; ++ } ++ ++ if (incomplete || context_next) ++ goto read_again; ++ ++ /* Stray Context Descriptor? */ ++ if (!skb) ++ continue; ++ ++ /* Be sure we don't exceed the configured MTU */ ++ max_len = netdev->mtu + ETH_HLEN; ++ if (!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && ++ (skb->protocol == htons(ETH_P_8021Q))) ++ max_len += VLAN_HLEN; ++ ++ if (skb->len > max_len) { ++ DBGPR("packet length exceeds configured MTU\n"); ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++#ifdef XGMAC_ENABLE_RX_PKT_DUMP ++ xgbe_print_pkt(netdev, skb, false); ++#endif ++ ++ skb_checksum_none_assert(skb); ++ if (XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, CSUM_DONE)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ ++ if (XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, VLAN_CTAG)) ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ++ packet->vlan_ctag); ++ ++ if (XGMAC_GET_BITS(packet->attributes, ++ RX_PACKET_ATTRIBUTES, RX_TSTAMP)) { ++ u64 nsec; ++ ++ nsec = timecounter_cyc2time(&pdata->tstamp_tc, ++ packet->rx_tstamp); ++ hwtstamps = skb_hwtstamps(skb); ++ hwtstamps->hwtstamp = ns_to_ktime(nsec); ++ } ++ ++ skb->dev = netdev; ++ skb->protocol = eth_type_trans(skb, netdev); ++ skb_record_rx_queue(skb, channel->queue_index); ++ skb_mark_napi_id(skb, &pdata->napi); ++ ++ netdev->last_rx = jiffies; ++ napi_gro_receive(&pdata->napi, skb); ++ } ++ ++ /* Check if we need to save state before leaving */ ++ if (received && (incomplete || context_next)) { ++ rdata = XGBE_GET_DESC_DATA(ring, ring->cur); ++ rdata->state_saved = 1; ++ rdata->state.incomplete = incomplete; ++ rdata->state.context_next = context_next; ++ rdata->state.skb = skb; ++ rdata->state.len = len; ++ rdata->state.error = error; ++ } ++ ++ DBGPR("<--xgbe_rx_poll: received = %d\n", received); ++ ++ return received; ++} ++ ++static int xgbe_poll(struct napi_struct *napi, int budget) ++{ ++ struct xgbe_prv_data *pdata = container_of(napi, struct xgbe_prv_data, ++ napi); ++ struct xgbe_channel *channel; ++ int ring_budget; ++ int processed, last_processed; ++ unsigned int i; ++ ++ DBGPR("-->xgbe_poll: budget=%d\n", budget); ++ ++ processed = 0; ++ ring_budget = budget / pdata->rx_ring_count; ++ do { ++ last_processed = processed; ++ ++ channel = pdata->channel; ++ for (i = 0; i < pdata->channel_count; i++, channel++) { ++ /* Cleanup Tx ring first */ ++ xgbe_tx_poll(channel); ++ ++ /* Process Rx ring next */ ++ if (ring_budget > (budget - processed)) ++ ring_budget = budget - processed; ++ processed += xgbe_rx_poll(channel, ring_budget); ++ } ++ } while ((processed < budget) && (processed != last_processed)); ++ ++ /* If we processed everything, we are done */ ++ if (processed < budget) { ++ /* Turn off polling */ ++ napi_complete(napi); ++ ++ /* Enable Tx and Rx interrupts */ ++ xgbe_enable_rx_tx_ints(pdata); ++ } ++ ++ DBGPR("<--xgbe_poll: received = %d\n", processed); ++ ++ return processed; ++} ++ ++void xgbe_dump_tx_desc(struct xgbe_ring *ring, unsigned int idx, ++ unsigned int count, unsigned int flag) ++{ ++ struct xgbe_ring_data *rdata; ++ struct xgbe_ring_desc *rdesc; ++ ++ while (count--) { ++ rdata = XGBE_GET_DESC_DATA(ring, idx); ++ rdesc = rdata->rdesc; ++ DBGPR("TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx, ++ (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE", ++ le32_to_cpu(rdesc->desc0), le32_to_cpu(rdesc->desc1), ++ le32_to_cpu(rdesc->desc2), le32_to_cpu(rdesc->desc3)); ++ idx++; ++ } ++} ++ ++void xgbe_dump_rx_desc(struct xgbe_ring *ring, struct xgbe_ring_desc *desc, ++ unsigned int idx) ++{ ++ DBGPR("RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n", idx, ++ le32_to_cpu(desc->desc0), le32_to_cpu(desc->desc1), ++ le32_to_cpu(desc->desc2), le32_to_cpu(desc->desc3)); ++} ++ ++void xgbe_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx) ++{ ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ unsigned char *buf = skb->data; ++ unsigned char buffer[128]; ++ unsigned int i, j; ++ ++ netdev_alert(netdev, "\n************** SKB dump ****************\n"); ++ ++ netdev_alert(netdev, "%s packet of %d bytes\n", ++ (tx_rx ? "TX" : "RX"), skb->len); ++ ++ netdev_alert(netdev, "Dst MAC addr: %pM\n", eth->h_dest); ++ netdev_alert(netdev, "Src MAC addr: %pM\n", eth->h_source); ++ netdev_alert(netdev, "Protocol: 0x%04hx\n", ntohs(eth->h_proto)); ++ ++ for (i = 0, j = 0; i < skb->len;) { ++ j += snprintf(buffer + j, sizeof(buffer) - j, "%02hhx", ++ buf[i++]); ++ ++ if ((i % 32) == 0) { ++ netdev_alert(netdev, " 0x%04x: %s\n", i - 32, buffer); ++ j = 0; ++ } else if ((i % 16) == 0) { ++ buffer[j++] = ' '; ++ buffer[j++] = ' '; ++ } else if ((i % 4) == 0) { ++ buffer[j++] = ' '; ++ } ++ } ++ if (i % 32) ++ netdev_alert(netdev, " 0x%04x: %s\n", i - (i % 32), buffer); ++ ++ netdev_alert(netdev, "\n************** SKB dump ****************\n"); ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c +new file mode 100644 +index 0000000..be28b1a +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-ethtool.c +@@ -0,0 +1,544 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/spinlock.h> ++#include <linux/phy.h> ++#include <linux/net_tstamp.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++struct xgbe_stats { ++ char stat_string[ETH_GSTRING_LEN]; ++ int stat_size; ++ int stat_offset; ++}; ++ ++#define XGMAC_MMC_STAT(_string, _var) \ ++ { _string, \ ++ FIELD_SIZEOF(struct xgbe_mmc_stats, _var), \ ++ offsetof(struct xgbe_prv_data, mmc_stats._var), \ ++ } ++ ++static const struct xgbe_stats xgbe_gstring_stats[] = { ++ XGMAC_MMC_STAT("tx_bytes", txoctetcount_gb), ++ XGMAC_MMC_STAT("tx_packets", txframecount_gb), ++ XGMAC_MMC_STAT("tx_unicast_packets", txunicastframes_gb), ++ XGMAC_MMC_STAT("tx_broadcast_packets", txbroadcastframes_gb), ++ XGMAC_MMC_STAT("tx_multicast_packets", txmulticastframes_gb), ++ XGMAC_MMC_STAT("tx_vlan_packets", txvlanframes_g), ++ XGMAC_MMC_STAT("tx_64_byte_packets", tx64octets_gb), ++ XGMAC_MMC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb), ++ XGMAC_MMC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb), ++ XGMAC_MMC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb), ++ XGMAC_MMC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb), ++ XGMAC_MMC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb), ++ XGMAC_MMC_STAT("tx_underflow_errors", txunderflowerror), ++ XGMAC_MMC_STAT("tx_pause_frames", txpauseframes), ++ ++ XGMAC_MMC_STAT("rx_bytes", rxoctetcount_gb), ++ XGMAC_MMC_STAT("rx_packets", rxframecount_gb), ++ XGMAC_MMC_STAT("rx_unicast_packets", rxunicastframes_g), ++ XGMAC_MMC_STAT("rx_broadcast_packets", rxbroadcastframes_g), ++ XGMAC_MMC_STAT("rx_multicast_packets", rxmulticastframes_g), ++ XGMAC_MMC_STAT("rx_vlan_packets", rxvlanframes_gb), ++ XGMAC_MMC_STAT("rx_64_byte_packets", rx64octets_gb), ++ XGMAC_MMC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb), ++ XGMAC_MMC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb), ++ XGMAC_MMC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb), ++ XGMAC_MMC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb), ++ XGMAC_MMC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb), ++ XGMAC_MMC_STAT("rx_undersize_packets", rxundersize_g), ++ XGMAC_MMC_STAT("rx_oversize_packets", rxoversize_g), ++ XGMAC_MMC_STAT("rx_crc_errors", rxcrcerror), ++ XGMAC_MMC_STAT("rx_crc_errors_small_packets", rxrunterror), ++ XGMAC_MMC_STAT("rx_crc_errors_giant_packets", rxjabbererror), ++ XGMAC_MMC_STAT("rx_length_errors", rxlengtherror), ++ XGMAC_MMC_STAT("rx_out_of_range_errors", rxoutofrangetype), ++ XGMAC_MMC_STAT("rx_fifo_overflow_errors", rxfifooverflow), ++ XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror), ++ XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes), ++}; ++#define XGBE_STATS_COUNT ARRAY_SIZE(xgbe_gstring_stats) ++ ++static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) ++{ ++ int i; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < XGBE_STATS_COUNT; i++) { ++ memcpy(data, xgbe_gstring_stats[i].stat_string, ++ ETH_GSTRING_LEN); ++ data += ETH_GSTRING_LEN; ++ } ++ break; ++ } ++ ++ DBGPR("<--%s\n", __func__); ++} ++ ++static void xgbe_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ u8 *stat; ++ int i; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ pdata->hw_if.read_mmc_stats(pdata); ++ for (i = 0; i < XGBE_STATS_COUNT; i++) { ++ stat = (u8 *)pdata + xgbe_gstring_stats[i].stat_offset; ++ *data++ = *(u64 *)stat; ++ } ++ ++ DBGPR("<--%s\n", __func__); ++} ++ ++static int xgbe_get_sset_count(struct net_device *netdev, int stringset) ++{ ++ int ret; ++ ++ DBGPR("-->%s\n", __func__); ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ ret = XGBE_STATS_COUNT; ++ break; ++ ++ default: ++ ret = -EOPNOTSUPP; ++ } ++ ++ DBGPR("<--%s\n", __func__); ++ ++ return ret; ++} ++ ++static void xgbe_get_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ DBGPR("-->xgbe_get_pauseparam\n"); ++ ++ pause->autoneg = pdata->pause_autoneg; ++ pause->tx_pause = pdata->tx_pause; ++ pause->rx_pause = pdata->rx_pause; ++ ++ DBGPR("<--xgbe_get_pauseparam\n"); ++} ++ ++static int xgbe_set_pauseparam(struct net_device *netdev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct phy_device *phydev = pdata->phydev; ++ int ret = 0; ++ ++ DBGPR("-->xgbe_set_pauseparam\n"); ++ ++ DBGPR(" autoneg = %d, tx_pause = %d, rx_pause = %d\n", ++ pause->autoneg, pause->tx_pause, pause->rx_pause); ++ ++ pdata->pause_autoneg = pause->autoneg; ++ if (pause->autoneg) { ++ phydev->advertising |= ADVERTISED_Pause; ++ phydev->advertising |= ADVERTISED_Asym_Pause; ++ ++ } else { ++ phydev->advertising &= ~ADVERTISED_Pause; ++ phydev->advertising &= ~ADVERTISED_Asym_Pause; ++ ++ pdata->tx_pause = pause->tx_pause; ++ pdata->rx_pause = pause->rx_pause; ++ } ++ ++ if (netif_running(netdev)) ++ ret = phy_start_aneg(phydev); ++ ++ DBGPR("<--xgbe_set_pauseparam\n"); ++ ++ return ret; ++} ++ ++static int xgbe_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ int ret; ++ ++ DBGPR("-->xgbe_get_settings\n"); ++ ++ if (!pdata->phydev) ++ return -ENODEV; ++ ++ ret = phy_ethtool_gset(pdata->phydev, cmd); ++ cmd->transceiver = XCVR_EXTERNAL; ++ ++ DBGPR("<--xgbe_get_settings\n"); ++ ++ return ret; ++} ++ ++static int xgbe_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct phy_device *phydev = pdata->phydev; ++ u32 speed; ++ int ret; ++ ++ DBGPR("-->xgbe_set_settings\n"); ++ ++ if (!pdata->phydev) ++ return -ENODEV; ++ ++ speed = ethtool_cmd_speed(cmd); ++ ++ if (cmd->phy_address != phydev->addr) ++ return -EINVAL; ++ ++ if ((cmd->autoneg != AUTONEG_ENABLE) && ++ (cmd->autoneg != AUTONEG_DISABLE)) ++ return -EINVAL; ++ ++ if (cmd->autoneg == AUTONEG_DISABLE) { ++ switch (speed) { ++ case SPEED_10000: ++ case SPEED_2500: ++ case SPEED_1000: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (cmd->duplex != DUPLEX_FULL) ++ return -EINVAL; ++ } ++ ++ if (cmd->autoneg == AUTONEG_ENABLE) { ++ /* Clear settings needed to force speeds */ ++ phydev->supported &= ~SUPPORTED_1000baseT_Full; ++ phydev->supported &= ~SUPPORTED_10000baseT_Full; ++ } else { ++ /* Add settings needed to force speed */ ++ phydev->supported |= SUPPORTED_1000baseT_Full; ++ phydev->supported |= SUPPORTED_10000baseT_Full; ++ } ++ ++ cmd->advertising &= phydev->supported; ++ if ((cmd->autoneg == AUTONEG_ENABLE) && !cmd->advertising) ++ return -EINVAL; ++ ++ ret = 0; ++ phydev->autoneg = cmd->autoneg; ++ phydev->speed = speed; ++ phydev->duplex = cmd->duplex; ++ phydev->advertising = cmd->advertising; ++ ++ if (cmd->autoneg == AUTONEG_ENABLE) ++ phydev->advertising |= ADVERTISED_Autoneg; ++ else ++ phydev->advertising &= ~ADVERTISED_Autoneg; ++ ++ if (netif_running(netdev)) ++ ret = phy_start_aneg(phydev); ++ ++ DBGPR("<--xgbe_set_settings\n"); ++ ++ return ret; ++} ++ ++static void xgbe_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ strlcpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, XGBE_DRV_VERSION, sizeof(drvinfo->version)); ++ strlcpy(drvinfo->bus_info, dev_name(pdata->dev), ++ sizeof(drvinfo->bus_info)); ++ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d", ++ XGMAC_IOREAD_BITS(pdata, MAC_VR, USERVER), ++ XGMAC_IOREAD_BITS(pdata, MAC_VR, DEVID), ++ XGMAC_IOREAD_BITS(pdata, MAC_VR, SNPSVER)); ++ drvinfo->n_stats = XGBE_STATS_COUNT; ++} ++ ++static int xgbe_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned int riwt; ++ ++ DBGPR("-->xgbe_get_coalesce\n"); ++ ++ memset(ec, 0, sizeof(struct ethtool_coalesce)); ++ ++ riwt = pdata->rx_riwt; ++ ec->rx_coalesce_usecs = hw_if->riwt_to_usec(pdata, riwt); ++ ec->rx_max_coalesced_frames = pdata->rx_frames; ++ ++ ec->tx_coalesce_usecs = pdata->tx_usecs; ++ ec->tx_max_coalesced_frames = pdata->tx_frames; ++ ++ DBGPR("<--xgbe_get_coalesce\n"); ++ ++ return 0; ++} ++ ++static int xgbe_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *ec) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ unsigned int rx_frames, rx_riwt, rx_usecs; ++ unsigned int tx_frames, tx_usecs; ++ ++ DBGPR("-->xgbe_set_coalesce\n"); ++ ++ /* Check for not supported parameters */ ++ if ((ec->rx_coalesce_usecs_irq) || ++ (ec->rx_max_coalesced_frames_irq) || ++ (ec->tx_coalesce_usecs_irq) || ++ (ec->tx_max_coalesced_frames_irq) || ++ (ec->stats_block_coalesce_usecs) || ++ (ec->use_adaptive_rx_coalesce) || ++ (ec->use_adaptive_tx_coalesce) || ++ (ec->pkt_rate_low) || ++ (ec->rx_coalesce_usecs_low) || ++ (ec->rx_max_coalesced_frames_low) || ++ (ec->tx_coalesce_usecs_low) || ++ (ec->tx_max_coalesced_frames_low) || ++ (ec->pkt_rate_high) || ++ (ec->rx_coalesce_usecs_high) || ++ (ec->rx_max_coalesced_frames_high) || ++ (ec->tx_coalesce_usecs_high) || ++ (ec->tx_max_coalesced_frames_high) || ++ (ec->rate_sample_interval)) ++ return -EOPNOTSUPP; ++ ++ /* Can only change rx-frames when interface is down (see ++ * rx_descriptor_init in xgbe-dev.c) ++ */ ++ rx_frames = pdata->rx_frames; ++ if (rx_frames != ec->rx_max_coalesced_frames && netif_running(netdev)) { ++ netdev_alert(netdev, ++ "interface must be down to change rx-frames\n"); ++ return -EINVAL; ++ } ++ ++ rx_riwt = hw_if->usec_to_riwt(pdata, ec->rx_coalesce_usecs); ++ rx_frames = ec->rx_max_coalesced_frames; ++ ++ /* Use smallest possible value if conversion resulted in zero */ ++ if (ec->rx_coalesce_usecs && !rx_riwt) ++ rx_riwt = 1; ++ ++ /* Check the bounds of values for Rx */ ++ if (rx_riwt > XGMAC_MAX_DMA_RIWT) { ++ rx_usecs = hw_if->riwt_to_usec(pdata, XGMAC_MAX_DMA_RIWT); ++ netdev_alert(netdev, "rx-usec is limited to %d usecs\n", ++ rx_usecs); ++ return -EINVAL; ++ } ++ if (rx_frames > pdata->channel->rx_ring->rdesc_count) { ++ netdev_alert(netdev, "rx-frames is limited to %d frames\n", ++ pdata->channel->rx_ring->rdesc_count); ++ return -EINVAL; ++ } ++ ++ tx_usecs = ec->tx_coalesce_usecs; ++ tx_frames = ec->tx_max_coalesced_frames; ++ ++ /* Check the bounds of values for Tx */ ++ if (tx_frames > pdata->channel->tx_ring->rdesc_count) { ++ netdev_alert(netdev, "tx-frames is limited to %d frames\n", ++ pdata->channel->tx_ring->rdesc_count); ++ return -EINVAL; ++ } ++ ++ pdata->rx_riwt = rx_riwt; ++ pdata->rx_frames = rx_frames; ++ hw_if->config_rx_coalesce(pdata); ++ ++ pdata->tx_usecs = tx_usecs; ++ pdata->tx_frames = tx_frames; ++ hw_if->config_tx_coalesce(pdata); ++ ++ DBGPR("<--xgbe_set_coalesce\n"); ++ ++ return 0; ++} ++ ++static int xgbe_get_ts_info(struct net_device *netdev, ++ struct ethtool_ts_info *ts_info) ++{ ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | ++ SOF_TIMESTAMPING_RX_SOFTWARE | ++ SOF_TIMESTAMPING_SOFTWARE | ++ SOF_TIMESTAMPING_TX_HARDWARE | ++ SOF_TIMESTAMPING_RX_HARDWARE | ++ SOF_TIMESTAMPING_RAW_HARDWARE; ++ ++ if (pdata->ptp_clock) ++ ts_info->phc_index = ptp_clock_index(pdata->ptp_clock); ++ else ++ ts_info->phc_index = -1; ++ ++ ts_info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); ++ ts_info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | ++ (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | ++ (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | ++ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | ++ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | ++ (1 << HWTSTAMP_FILTER_ALL); ++ ++ return 0; ++} ++ ++static const struct ethtool_ops xgbe_ethtool_ops = { ++ .get_settings = xgbe_get_settings, ++ .set_settings = xgbe_set_settings, ++ .get_drvinfo = xgbe_get_drvinfo, ++ .get_link = ethtool_op_get_link, ++ .get_coalesce = xgbe_get_coalesce, ++ .set_coalesce = xgbe_set_coalesce, ++ .get_pauseparam = xgbe_get_pauseparam, ++ .set_pauseparam = xgbe_set_pauseparam, ++ .get_strings = xgbe_get_strings, ++ .get_ethtool_stats = xgbe_get_ethtool_stats, ++ .get_sset_count = xgbe_get_sset_count, ++ .get_ts_info = xgbe_get_ts_info, ++}; ++ ++struct ethtool_ops *xgbe_get_ethtool_ops(void) ++{ ++ return (struct ethtool_ops *)&xgbe_ethtool_ops; ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c +new file mode 100644 +index 0000000..81f8b48 +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-main.c +@@ -0,0 +1,566 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/module.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/spinlock.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_net.h> ++#include <linux/clk.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION(XGBE_DRV_VERSION); ++MODULE_DESCRIPTION(XGBE_DRV_DESC); ++ ++unsigned int speed = 0; ++module_param(speed, uint, 0444); ++MODULE_PARM_DESC(speed, " Select operating speed (1=1GbE, 2=2.5GbE, 10=10GbE, any other value implies auto-negotiation"); ++ ++static struct xgbe_channel *xgbe_alloc_rings(struct xgbe_prv_data *pdata) ++{ ++ struct xgbe_channel *channel_mem, *channel; ++ struct xgbe_ring *tx_ring, *rx_ring; ++ unsigned int count, i; ++ ++ DBGPR("-->xgbe_alloc_rings\n"); ++ ++ count = max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); ++ ++ channel_mem = devm_kcalloc(pdata->dev, count, ++ sizeof(struct xgbe_channel), GFP_KERNEL); ++ if (!channel_mem) ++ return NULL; ++ ++ tx_ring = devm_kcalloc(pdata->dev, pdata->tx_ring_count, ++ sizeof(struct xgbe_ring), GFP_KERNEL); ++ if (!tx_ring) ++ return NULL; ++ ++ rx_ring = devm_kcalloc(pdata->dev, pdata->rx_ring_count, ++ sizeof(struct xgbe_ring), GFP_KERNEL); ++ if (!rx_ring) ++ return NULL; ++ ++ for (i = 0, channel = channel_mem; i < count; i++, channel++) { ++ snprintf(channel->name, sizeof(channel->name), "channel-%d", i); ++ channel->pdata = pdata; ++ channel->queue_index = i; ++ channel->dma_regs = pdata->xgmac_regs + DMA_CH_BASE + ++ (DMA_CH_INC * i); ++ ++ if (i < pdata->tx_ring_count) { ++ spin_lock_init(&tx_ring->lock); ++ channel->tx_ring = tx_ring++; ++ } ++ ++ if (i < pdata->rx_ring_count) { ++ spin_lock_init(&tx_ring->lock); ++ channel->rx_ring = rx_ring++; ++ } ++ ++ DBGPR(" %s - queue_index=%u, dma_regs=%p, tx=%p, rx=%p\n", ++ channel->name, channel->queue_index, channel->dma_regs, ++ channel->tx_ring, channel->rx_ring); ++ } ++ ++ pdata->channel_count = count; ++ ++ DBGPR("<--xgbe_alloc_rings\n"); ++ ++ return channel_mem; ++} ++ ++static void xgbe_default_config(struct xgbe_prv_data *pdata) ++{ ++ DBGPR("-->xgbe_default_config\n"); ++ ++ pdata->pblx8 = DMA_PBL_X8_ENABLE; ++ pdata->tx_sf_mode = MTL_TSF_ENABLE; ++ pdata->tx_threshold = MTL_TX_THRESHOLD_64; ++ pdata->tx_pbl = DMA_PBL_16; ++ pdata->tx_osp_mode = DMA_OSP_ENABLE; ++ pdata->rx_sf_mode = MTL_RSF_DISABLE; ++ pdata->rx_threshold = MTL_RX_THRESHOLD_64; ++ pdata->rx_pbl = DMA_PBL_16; ++ pdata->pause_autoneg = 1; ++ pdata->tx_pause = 1; ++ pdata->rx_pause = 1; ++ pdata->power_down = 0; ++ ++ if (speed == 10) { ++ pdata->default_autoneg = AUTONEG_DISABLE; ++ pdata->default_speed = SPEED_10000; ++ } else if (speed == 2) { ++ pdata->default_autoneg = AUTONEG_DISABLE; ++ pdata->default_speed = SPEED_2500; ++ } else if (speed == 1) { ++ pdata->default_autoneg = AUTONEG_DISABLE; ++ pdata->default_speed = SPEED_1000; ++ } else { ++ pdata->default_autoneg = AUTONEG_ENABLE; ++ pdata->default_speed = SPEED_10000; ++ } ++ ++ DBGPR("<--xgbe_default_config\n"); ++} ++ ++static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata) ++{ ++ xgbe_init_function_ptrs_dev(&pdata->hw_if); ++ xgbe_init_function_ptrs_desc(&pdata->desc_if); ++} ++ ++static int xgbe_probe(struct platform_device *pdev) ++{ ++ struct xgbe_prv_data *pdata; ++ struct xgbe_hw_if *hw_if; ++ struct xgbe_desc_if *desc_if; ++ struct net_device *netdev; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ const u8 *mac_addr; ++ int ret; ++ ++ DBGPR("--> xgbe_probe\n"); ++ ++ netdev = alloc_etherdev_mq(sizeof(struct xgbe_prv_data), ++ XGBE_MAX_DMA_CHANNELS); ++ if (!netdev) { ++ dev_err(dev, "alloc_etherdev failed\n"); ++ ret = -ENOMEM; ++ goto err_alloc; ++ } ++ SET_NETDEV_DEV(netdev, dev); ++ pdata = netdev_priv(netdev); ++ pdata->netdev = netdev; ++ pdata->pdev = pdev; ++ pdata->dev = dev; ++ platform_set_drvdata(pdev, netdev); ++ ++ spin_lock_init(&pdata->lock); ++ mutex_init(&pdata->xpcs_mutex); ++ spin_lock_init(&pdata->tstamp_lock); ++ ++ /* Set and validate the number of descriptors for a ring */ ++ BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT); ++ pdata->tx_desc_count = XGBE_TX_DESC_CNT; ++ if (pdata->tx_desc_count & (pdata->tx_desc_count - 1)) { ++ dev_err(dev, "tx descriptor count (%d) is not valid\n", ++ pdata->tx_desc_count); ++ ret = -EINVAL; ++ goto err_io; ++ } ++ BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_RX_DESC_CNT); ++ pdata->rx_desc_count = XGBE_RX_DESC_CNT; ++ if (pdata->rx_desc_count & (pdata->rx_desc_count - 1)) { ++ dev_err(dev, "rx descriptor count (%d) is not valid\n", ++ pdata->rx_desc_count); ++ ret = -EINVAL; ++ goto err_io; ++ } ++ ++ /* Obtain the system clock setting */ ++ pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK); ++ if (IS_ERR(pdata->sysclk)) { ++ dev_err(dev, "dma devm_clk_get failed\n"); ++ ret = PTR_ERR(pdata->sysclk); ++ goto err_io; ++ } ++ ++ /* Obtain the PTP clock setting */ ++ pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK); ++ if (IS_ERR(pdata->ptpclk)) { ++ dev_err(dev, "ptp devm_clk_get failed\n"); ++ ret = PTR_ERR(pdata->ptpclk); ++ goto err_io; ++ } ++ ++ /* Obtain the mmio areas for the device */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pdata->xgmac_regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->xgmac_regs)) { ++ dev_err(dev, "xgmac ioremap failed\n"); ++ ret = PTR_ERR(pdata->xgmac_regs); ++ goto err_io; ++ } ++ DBGPR(" xgmac_regs = %p\n", pdata->xgmac_regs); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ pdata->xpcs_regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->xpcs_regs)) { ++ dev_err(dev, "xpcs ioremap failed\n"); ++ ret = PTR_ERR(pdata->xpcs_regs); ++ goto err_io; ++ } ++ DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs); ++ ++ /* Set the DMA mask */ ++ if (!dev->dma_mask) ++ dev->dma_mask = &dev->coherent_dma_mask; ++ *(dev->dma_mask) = DMA_BIT_MASK(40); ++ dev->coherent_dma_mask = DMA_BIT_MASK(40); ++ ++ if (of_property_read_bool(dev->of_node, "dma-coherent")) { ++ pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_OS_ARCACHE; ++ pdata->awcache = XGBE_DMA_OS_AWCACHE; ++ } else { ++ pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN; ++ pdata->arcache = XGBE_DMA_SYS_ARCACHE; ++ pdata->awcache = XGBE_DMA_SYS_AWCACHE; ++ } ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret < 0) { ++ dev_err(dev, "platform_get_irq failed\n"); ++ goto err_io; ++ } ++ netdev->irq = ret; ++ netdev->base_addr = (unsigned long)pdata->xgmac_regs; ++ ++ /* Set all the function pointers */ ++ xgbe_init_all_fptrs(pdata); ++ hw_if = &pdata->hw_if; ++ desc_if = &pdata->desc_if; ++ ++ /* Issue software reset to device */ ++ hw_if->exit(pdata); ++ ++ /* Populate the hardware features */ ++ xgbe_get_all_hw_features(pdata); ++ ++ /* Retrieve the MAC address */ ++ mac_addr = of_get_mac_address(dev->of_node); ++ if (!mac_addr) { ++ dev_err(dev, "invalid mac address for this device\n"); ++ ret = -EINVAL; ++ goto err_io; ++ } ++ memcpy(netdev->dev_addr, mac_addr, netdev->addr_len); ++ ++ /* Retrieve the PHY mode - it must be "xgmii" */ ++ pdata->phy_mode = of_get_phy_mode(dev->of_node); ++ if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { ++ dev_err(dev, "invalid phy-mode specified for this device\n"); ++ ret = -EINVAL; ++ goto err_io; ++ } ++ ++ /* Set default configuration data */ ++ xgbe_default_config(pdata); ++ ++ /* Calculate the number of Tx and Rx rings to be created ++ * -Tx (DMA) Channels map 1-to-1 to Tx Queues so set ++ * the number of Tx queues to the number of Tx channels ++ * enabled ++ * -Rx (DMA) Channels do not map 1-to-1 so use the actual ++ * number of Rx queues ++ */ ++ pdata->tx_ring_count = min_t(unsigned int, num_online_cpus(), ++ pdata->hw_feat.tx_ch_cnt); ++ pdata->tx_q_count = pdata->tx_ring_count; ++ ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count); ++ if (ret) { ++ dev_err(dev, "error setting real tx queue count\n"); ++ goto err_io; ++ } ++ ++ pdata->rx_ring_count = min_t(unsigned int, ++ netif_get_num_default_rss_queues(), ++ pdata->hw_feat.rx_ch_cnt); ++ pdata->rx_q_count = pdata->hw_feat.rx_q_cnt; ++ ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count); ++ if (ret) { ++ dev_err(dev, "error setting real rx queue count\n"); ++ goto err_io; ++ } ++ ++ /* Allocate the rings for the DMA channels */ ++ pdata->channel = xgbe_alloc_rings(pdata); ++ if (!pdata->channel) { ++ dev_err(dev, "ring allocation failed\n"); ++ ret = -ENOMEM; ++ goto err_io; ++ } ++ ++ /* Prepare to regsiter with MDIO */ ++ pdata->mii_bus_id = kasprintf(GFP_KERNEL, "%s", pdev->name); ++ if (!pdata->mii_bus_id) { ++ dev_err(dev, "failed to allocate mii bus id\n"); ++ ret = -ENOMEM; ++ goto err_io; ++ } ++ ret = xgbe_mdio_register(pdata); ++ if (ret) ++ goto err_bus_id; ++ ++ /* Set device operations */ ++ netdev->netdev_ops = xgbe_get_netdev_ops(); ++ netdev->ethtool_ops = xgbe_get_ethtool_ops(); ++#ifdef CONFIG_AMD_XGBE_DCB ++ netdev->dcbnl_ops = xgbe_get_dcbnl_ops(); ++#endif ++ ++ /* Set device features */ ++ netdev->hw_features = NETIF_F_SG | ++ NETIF_F_IP_CSUM | ++ NETIF_F_IPV6_CSUM | ++ NETIF_F_RXCSUM | ++ NETIF_F_TSO | ++ NETIF_F_TSO6 | ++ NETIF_F_GRO | ++ NETIF_F_HW_VLAN_CTAG_RX | ++ NETIF_F_HW_VLAN_CTAG_TX | ++ NETIF_F_HW_VLAN_CTAG_FILTER; ++ ++ netdev->vlan_features |= NETIF_F_SG | ++ NETIF_F_IP_CSUM | ++ NETIF_F_IPV6_CSUM | ++ NETIF_F_TSO | ++ NETIF_F_TSO6; ++ ++ netdev->features |= netdev->hw_features; ++ pdata->netdev_features = netdev->features; ++ ++ netdev->priv_flags |= IFF_UNICAST_FLT; ++ ++ xgbe_init_rx_coalesce(pdata); ++ xgbe_init_tx_coalesce(pdata); ++ ++ netif_carrier_off(netdev); ++ ret = register_netdev(netdev); ++ if (ret) { ++ dev_err(dev, "net device registration failed\n"); ++ goto err_reg_netdev; ++ } ++ ++ xgbe_ptp_register(pdata); ++ ++ xgbe_debugfs_init(pdata); ++ ++ netdev_notice(netdev, "net device enabled\n"); ++ ++ DBGPR("<-- xgbe_probe\n"); ++ ++ return 0; ++ ++err_reg_netdev: ++ xgbe_mdio_unregister(pdata); ++ ++err_bus_id: ++ kfree(pdata->mii_bus_id); ++ ++err_io: ++ free_netdev(netdev); ++ ++err_alloc: ++ dev_notice(dev, "net device not enabled\n"); ++ ++ return ret; ++} ++ ++static int xgbe_remove(struct platform_device *pdev) ++{ ++ struct net_device *netdev = platform_get_drvdata(pdev); ++ struct xgbe_prv_data *pdata = netdev_priv(netdev); ++ ++ DBGPR("-->xgbe_remove\n"); ++ ++ xgbe_debugfs_exit(pdata); ++ ++ xgbe_ptp_unregister(pdata); ++ ++ unregister_netdev(netdev); ++ ++ xgbe_mdio_unregister(pdata); ++ ++ kfree(pdata->mii_bus_id); ++ ++ free_netdev(netdev); ++ ++ DBGPR("<--xgbe_remove\n"); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int xgbe_suspend(struct device *dev) ++{ ++ struct net_device *netdev = dev_get_drvdata(dev); ++ int ret; ++ ++ DBGPR("-->xgbe_suspend\n"); ++ ++ if (!netif_running(netdev)) { ++ DBGPR("<--xgbe_dev_suspend\n"); ++ return -EINVAL; ++ } ++ ++ ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT); ++ ++ DBGPR("<--xgbe_suspend\n"); ++ ++ return ret; ++} ++ ++static int xgbe_resume(struct device *dev) ++{ ++ struct net_device *netdev = dev_get_drvdata(dev); ++ int ret; ++ ++ DBGPR("-->xgbe_resume\n"); ++ ++ if (!netif_running(netdev)) { ++ DBGPR("<--xgbe_dev_resume\n"); ++ return -EINVAL; ++ } ++ ++ ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT); ++ ++ DBGPR("<--xgbe_resume\n"); ++ ++ return ret; ++} ++#endif /* CONFIG_PM */ ++ ++static const struct of_device_id xgbe_of_match[] = { ++ { .compatible = "amd,xgbe-seattle-v0a", }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, xgbe_of_match); ++static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume); ++ ++static struct platform_driver xgbe_driver = { ++ .driver = { ++ .name = "amd-xgbe", ++ .of_match_table = xgbe_of_match, ++ .pm = &xgbe_pm_ops, ++ }, ++ .probe = xgbe_probe, ++ .remove = xgbe_remove, ++}; ++ ++module_platform_driver(xgbe_driver); +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c +new file mode 100644 +index 0000000..70c3346 +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-mdio.c +@@ -0,0 +1,330 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/module.h> ++#include <linux/kmod.h> ++#include <linux/mdio.h> ++#include <linux/phy.h> ++#include <linux/of.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static int xgbe_mdio_read(struct mii_bus *mii, int prtad, int mmd_reg) ++{ ++ struct xgbe_prv_data *pdata = mii->priv; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ int mmd_data; ++ ++ DBGPR_MDIO("-->xgbe_mdio_read: prtad=%#x mmd_reg=%#x\n", ++ prtad, mmd_reg); ++ ++ mmd_data = hw_if->read_mmd_regs(pdata, prtad, mmd_reg); ++ ++ DBGPR_MDIO("<--xgbe_mdio_read: mmd_data=%#x\n", mmd_data); ++ ++ return mmd_data; ++} ++ ++static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg, ++ u16 mmd_val) ++{ ++ struct xgbe_prv_data *pdata = mii->priv; ++ struct xgbe_hw_if *hw_if = &pdata->hw_if; ++ int mmd_data = mmd_val; ++ ++ DBGPR_MDIO("-->xgbe_mdio_write: prtad=%#x mmd_reg=%#x mmd_data=%#x\n", ++ prtad, mmd_reg, mmd_data); ++ ++ hw_if->write_mmd_regs(pdata, prtad, mmd_reg, mmd_data); ++ ++ DBGPR_MDIO("<--xgbe_mdio_write\n"); ++ ++ return 0; ++} ++ ++void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) ++{ ++ struct device *dev = pdata->dev; ++ struct phy_device *phydev = pdata->mii->phy_map[XGBE_PRTAD]; ++ int i; ++ ++ dev_alert(dev, "\n************* PHY Reg dump **********************\n"); ++ ++ dev_alert(dev, "PCS Control Reg (%#04x) = %#04x\n", MDIO_CTRL1, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1)); ++ dev_alert(dev, "PCS Status Reg (%#04x) = %#04x\n", MDIO_STAT1, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1)); ++ dev_alert(dev, "Phy Id (PHYS ID 1 %#04x)= %#04x\n", MDIO_DEVID1, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1)); ++ dev_alert(dev, "Phy Id (PHYS ID 2 %#04x)= %#04x\n", MDIO_DEVID2, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2)); ++ dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS1, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1)); ++ dev_alert(dev, "Devices in Package (%#04x)= %#04x\n", MDIO_DEVS2, ++ XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2)); ++ ++ dev_alert(dev, "Auto-Neg Control Reg (%#04x) = %#04x\n", MDIO_CTRL1, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1)); ++ dev_alert(dev, "Auto-Neg Status Reg (%#04x) = %#04x\n", MDIO_STAT1, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1)); ++ dev_alert(dev, "Auto-Neg Ad Reg 1 (%#04x) = %#04x\n", ++ MDIO_AN_ADVERTISE, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE)); ++ dev_alert(dev, "Auto-Neg Ad Reg 2 (%#04x) = %#04x\n", ++ MDIO_AN_ADVERTISE + 1, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1)); ++ dev_alert(dev, "Auto-Neg Ad Reg 3 (%#04x) = %#04x\n", ++ MDIO_AN_ADVERTISE + 2, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2)); ++ dev_alert(dev, "Auto-Neg Completion Reg (%#04x) = %#04x\n", ++ MDIO_AN_COMP_STAT, ++ XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT)); ++ ++ dev_alert(dev, "MMD Device Mask = %#x\n", ++ phydev->c45_ids.devices_in_package); ++ for (i = 0; i < ARRAY_SIZE(phydev->c45_ids.device_ids); i++) ++ dev_alert(dev, " MMD %d: ID = %#08x\n", i, ++ phydev->c45_ids.device_ids[i]); ++ ++ dev_alert(dev, "\n*************************************************\n"); ++} ++ ++int xgbe_mdio_register(struct xgbe_prv_data *pdata) ++{ ++ struct device_node *phy_node; ++ struct mii_bus *mii; ++ struct phy_device *phydev; ++ int ret = 0; ++ ++ DBGPR("-->xgbe_mdio_register\n"); ++ ++ /* Retrieve the phy-handle */ ++ phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0); ++ if (!phy_node) { ++ dev_err(pdata->dev, "unable to parse phy-handle\n"); ++ return -EINVAL; ++ } ++ ++ mii = mdiobus_alloc(); ++ if (mii == NULL) { ++ dev_err(pdata->dev, "mdiobus_alloc failed\n"); ++ ret = -ENOMEM; ++ goto err_node_get; ++ } ++ ++ /* Register on the MDIO bus (don't probe any PHYs) */ ++ mii->name = XGBE_PHY_NAME; ++ mii->read = xgbe_mdio_read; ++ mii->write = xgbe_mdio_write; ++ snprintf(mii->id, sizeof(mii->id), "%s", pdata->mii_bus_id); ++ mii->priv = pdata; ++ mii->phy_mask = ~0; ++ mii->parent = pdata->dev; ++ ret = mdiobus_register(mii); ++ if (ret) { ++ dev_err(pdata->dev, "mdiobus_register failed\n"); ++ goto err_mdiobus_alloc; ++ } ++ DBGPR(" mdiobus_register succeeded for %s\n", pdata->mii_bus_id); ++ ++ /* Probe the PCS using Clause 45 */ ++ phydev = get_phy_device(mii, XGBE_PRTAD, true); ++ if (IS_ERR(phydev) || !phydev || ++ !phydev->c45_ids.device_ids[MDIO_MMD_PCS]) { ++ dev_err(pdata->dev, "get_phy_device failed\n"); ++ ret = phydev ? PTR_ERR(phydev) : -ENOLINK; ++ goto err_mdiobus_register; ++ } ++ request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, ++ MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS])); ++ ++ of_node_get(phy_node); ++ phydev->dev.of_node = phy_node; ++ ret = phy_device_register(phydev); ++ if (ret) { ++ dev_err(pdata->dev, "phy_device_register failed\n"); ++ of_node_put(phy_node); ++ goto err_phy_device; ++ } ++ ++ /* Add a reference to the PHY driver so it can't be unloaded */ ++ pdata->phy_module = phydev->dev.driver ? ++ phydev->dev.driver->owner : NULL; ++ if (!try_module_get(pdata->phy_module)) { ++ dev_err(pdata->dev, "try_module_get failed\n"); ++ ret = -EIO; ++ goto err_phy_device; ++ } ++ ++ pdata->mii = mii; ++ pdata->mdio_mmd = MDIO_MMD_PCS; ++ ++ phydev->autoneg = pdata->default_autoneg; ++ if (phydev->autoneg == AUTONEG_DISABLE) { ++ /* Add settings needed to force speed */ ++ phydev->supported |= SUPPORTED_1000baseT_Full; ++ phydev->supported |= SUPPORTED_10000baseT_Full; ++ ++ phydev->speed = pdata->default_speed; ++ phydev->duplex = DUPLEX_FULL; ++ ++ phydev->advertising &= ~ADVERTISED_Autoneg; ++ } ++ ++ pdata->phydev = phydev; ++ ++ of_node_put(phy_node); ++ ++ DBGPHY_REGS(pdata); ++ ++ DBGPR("<--xgbe_mdio_register\n"); ++ ++ return 0; ++ ++err_phy_device: ++ phy_device_free(phydev); ++ ++err_mdiobus_register: ++ mdiobus_unregister(mii); ++ ++err_mdiobus_alloc: ++ mdiobus_free(mii); ++ ++err_node_get: ++ of_node_put(phy_node); ++ ++ return ret; ++} ++ ++void xgbe_mdio_unregister(struct xgbe_prv_data *pdata) ++{ ++ DBGPR("-->xgbe_mdio_unregister\n"); ++ ++ pdata->phydev = NULL; ++ ++ module_put(pdata->phy_module); ++ pdata->phy_module = NULL; ++ ++ mdiobus_unregister(pdata->mii); ++ pdata->mii->priv = NULL; ++ ++ mdiobus_free(pdata->mii); ++ pdata->mii = NULL; ++ ++ DBGPR("<--xgbe_mdio_unregister\n"); ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c +new file mode 100644 +index 0000000..37e64cf +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe-ptp.c +@@ -0,0 +1,285 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 <linux/clk.h> ++#include <linux/clocksource.h> ++#include <linux/ptp_clock_kernel.h> ++#include <linux/net_tstamp.h> ++ ++#include "xgbe.h" ++#include "xgbe-common.h" ++ ++ ++static cycle_t xgbe_cc_read(const struct cyclecounter *cc) ++{ ++ struct xgbe_prv_data *pdata = container_of(cc, ++ struct xgbe_prv_data, ++ tstamp_cc); ++ u64 nsec; ++ ++ nsec = pdata->hw_if.get_tstamp_time(pdata); ++ ++ return nsec; ++} ++ ++static int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta) ++{ ++ struct xgbe_prv_data *pdata = container_of(info, ++ struct xgbe_prv_data, ++ ptp_clock_info); ++ unsigned long flags; ++ u64 adjust; ++ u32 addend, diff; ++ unsigned int neg_adjust = 0; ++ ++ if (delta < 0) { ++ neg_adjust = 1; ++ delta = -delta; ++ } ++ ++ adjust = pdata->tstamp_addend; ++ adjust *= delta; ++ diff = div_u64(adjust, 1000000000UL); ++ ++ addend = (neg_adjust) ? pdata->tstamp_addend - diff : ++ pdata->tstamp_addend + diff; ++ ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ ++ pdata->hw_if.update_tstamp_addend(pdata, addend); ++ ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++ ++ return 0; ++} ++ ++static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) ++{ ++ struct xgbe_prv_data *pdata = container_of(info, ++ struct xgbe_prv_data, ++ ptp_clock_info); ++ unsigned long flags; ++ u64 nsec; ++ ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ ++ nsec = timecounter_read(&pdata->tstamp_tc); ++ ++ nsec += delta; ++ timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); ++ ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++ ++ return 0; ++} ++ ++static int xgbe_gettime(struct ptp_clock_info *info, struct timespec *ts) ++{ ++ struct xgbe_prv_data *pdata = container_of(info, ++ struct xgbe_prv_data, ++ ptp_clock_info); ++ unsigned long flags; ++ u64 nsec; ++ ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ ++ nsec = timecounter_read(&pdata->tstamp_tc); ++ ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++ ++ *ts = ns_to_timespec(nsec); ++ ++ return 0; ++} ++ ++static int xgbe_settime(struct ptp_clock_info *info, const struct timespec *ts) ++{ ++ struct xgbe_prv_data *pdata = container_of(info, ++ struct xgbe_prv_data, ++ ptp_clock_info); ++ unsigned long flags; ++ u64 nsec; ++ ++ nsec = timespec_to_ns(ts); ++ ++ spin_lock_irqsave(&pdata->tstamp_lock, flags); ++ ++ timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); ++ ++ spin_unlock_irqrestore(&pdata->tstamp_lock, flags); ++ ++ return 0; ++} ++ ++static int xgbe_enable(struct ptp_clock_info *info, ++ struct ptp_clock_request *request, int on) ++{ ++ return -EOPNOTSUPP; ++} ++ ++void xgbe_ptp_register(struct xgbe_prv_data *pdata) ++{ ++ struct ptp_clock_info *info = &pdata->ptp_clock_info; ++ struct ptp_clock *clock; ++ struct cyclecounter *cc = &pdata->tstamp_cc; ++ u64 dividend; ++ ++ snprintf(info->name, sizeof(info->name), "%s", ++ netdev_name(pdata->netdev)); ++ info->owner = THIS_MODULE; ++ info->max_adj = clk_get_rate(pdata->ptpclk); ++ info->adjfreq = xgbe_adjfreq; ++ info->adjtime = xgbe_adjtime; ++ info->gettime = xgbe_gettime; ++ info->settime = xgbe_settime; ++ info->enable = xgbe_enable; ++ ++ clock = ptp_clock_register(info, pdata->dev); ++ if (IS_ERR(clock)) { ++ dev_err(pdata->dev, "ptp_clock_register failed\n"); ++ return; ++ } ++ ++ pdata->ptp_clock = clock; ++ ++ /* Calculate the addend: ++ * addend = 2^32 / (PTP ref clock / 50Mhz) ++ * = (2^32 * 50Mhz) / PTP ref clock ++ */ ++ dividend = 50000000; ++ dividend <<= 32; ++ pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk)); ++ ++ /* Setup the timecounter */ ++ cc->read = xgbe_cc_read; ++ cc->mask = CLOCKSOURCE_MASK(64); ++ cc->mult = 1; ++ cc->shift = 0; ++ ++ timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, ++ ktime_to_ns(ktime_get_real())); ++ ++ /* Disable all timestamping to start */ ++ XGMAC_IOWRITE(pdata, MAC_TCR, 0); ++ pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF; ++ pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; ++} ++ ++void xgbe_ptp_unregister(struct xgbe_prv_data *pdata) ++{ ++ if (pdata->ptp_clock) ++ ptp_clock_unregister(pdata->ptp_clock); ++} +diff --git a/drivers/net/ethernet/amd/xgbe-a0/xgbe.h b/drivers/net/ethernet/amd/xgbe-a0/xgbe.h +new file mode 100644 +index 0000000..7b5ed5d +--- /dev/null ++++ b/drivers/net/ethernet/amd/xgbe-a0/xgbe.h +@@ -0,0 +1,769 @@ ++/* ++ * AMD 10Gb Ethernet driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ++ * THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * This file incorporates work covered by the following copyright and ++ * permission notice: ++ * The Synopsys DWC ETHER XGMAC Software Driver and documentation ++ * (hereinafter "Software") is an unsupported proprietary work of Synopsys, ++ * Inc. unless otherwise expressly agreed to in writing between Synopsys ++ * and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product ++ * under any End User Software License Agreement or Agreement for Licensed ++ * Product with Synopsys or any supplement thereto. Permission is hereby ++ * granted, free of charge, to any person obtaining a copy of this software ++ * annotated with this license and 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. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" ++ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A ++ * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS ++ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (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 __XGBE_H__ ++#define __XGBE_H__ ++ ++#include <linux/dma-mapping.h> ++#include <linux/netdevice.h> ++#include <linux/workqueue.h> ++#include <linux/phy.h> ++#include <linux/if_vlan.h> ++#include <linux/bitops.h> ++#include <linux/ptp_clock_kernel.h> ++#include <linux/clocksource.h> ++#include <linux/net_tstamp.h> ++#include <net/dcbnl.h> ++ ++ ++#define XGBE_DRV_NAME "amd-xgbe" ++#define XGBE_DRV_VERSION "0.0.0-a" ++#define XGBE_DRV_DESC "AMD 10 Gigabit Ethernet Driver" ++ ++/* Descriptor related defines */ ++#define XGBE_TX_DESC_CNT 512 ++#define XGBE_TX_DESC_MIN_FREE (XGBE_TX_DESC_CNT >> 3) ++#define XGBE_TX_DESC_MAX_PROC (XGBE_TX_DESC_CNT >> 1) ++#define XGBE_RX_DESC_CNT 512 ++ ++#define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) ++ ++#define XGBE_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) ++#define XGBE_RX_BUF_ALIGN 64 ++ ++#define XGBE_MAX_DMA_CHANNELS 16 ++#define XGBE_MAX_QUEUES 16 ++ ++/* DMA cache settings - Outer sharable, write-back, write-allocate */ ++#define XGBE_DMA_OS_AXDOMAIN 0x2 ++#define XGBE_DMA_OS_ARCACHE 0xb ++#define XGBE_DMA_OS_AWCACHE 0xf ++ ++/* DMA cache settings - System, no caches used */ ++#define XGBE_DMA_SYS_AXDOMAIN 0x3 ++#define XGBE_DMA_SYS_ARCACHE 0x0 ++#define XGBE_DMA_SYS_AWCACHE 0x0 ++ ++#define XGBE_DMA_INTERRUPT_MASK 0x31c7 ++ ++#define XGMAC_MIN_PACKET 60 ++#define XGMAC_STD_PACKET_MTU 1500 ++#define XGMAC_MAX_STD_PACKET 1518 ++#define XGMAC_JUMBO_PACKET_MTU 9000 ++#define XGMAC_MAX_JUMBO_PACKET 9018 ++ ++/* MDIO bus phy name */ ++#define XGBE_PHY_NAME "amd_xgbe_phy" ++#define XGBE_PRTAD 0 ++ ++/* Device-tree clock names */ ++#define XGBE_DMA_CLOCK "dma_clk" ++#define XGBE_PTP_CLOCK "ptp_clk" ++ ++/* Timestamp support - values based on 50MHz PTP clock ++ * 50MHz => 20 nsec ++ */ ++#define XGBE_TSTAMP_SSINC 20 ++#define XGBE_TSTAMP_SNSINC 0 ++ ++/* Driver PMT macros */ ++#define XGMAC_DRIVER_CONTEXT 1 ++#define XGMAC_IOCTL_CONTEXT 2 ++ ++#define XGBE_FIFO_MAX 81920 ++#define XGBE_FIFO_SIZE_B(x) (x) ++#define XGBE_FIFO_SIZE_KB(x) (x * 1024) ++ ++#define XGBE_TC_CNT 2 ++#define XGBE_TC_MIN_QUANTUM 10 ++ ++#define XGBE_SEATTLE_A0 ((read_cpuid_id() & 0x00f0000f) == 0) ++ ++/* Helper macro for descriptor handling ++ * Always use XGBE_GET_DESC_DATA to access the descriptor data ++ * since the index is free-running and needs to be and-ed ++ * with the descriptor count value of the ring to index to ++ * the proper descriptor data. ++ */ ++#define XGBE_GET_DESC_DATA(_ring, _idx) \ ++ ((_ring)->rdata + \ ++ ((_idx) & ((_ring)->rdesc_count - 1))) ++ ++ ++/* Default coalescing parameters */ ++#define XGMAC_INIT_DMA_TX_USECS 50 ++#define XGMAC_INIT_DMA_TX_FRAMES 25 ++ ++#define XGMAC_MAX_DMA_RIWT 0xff ++#define XGMAC_INIT_DMA_RX_USECS 30 ++#define XGMAC_INIT_DMA_RX_FRAMES 25 ++ ++/* Flow control queue count */ ++#define XGMAC_MAX_FLOW_CONTROL_QUEUES 8 ++ ++/* Maximum MAC address hash table size (256 bits = 8 bytes) */ ++#define XGBE_MAC_HASH_TABLE_SIZE 8 ++ ++struct xgbe_prv_data; ++ ++struct xgbe_packet_data { ++ unsigned int attributes; ++ ++ unsigned int errors; ++ ++ unsigned int rdesc_count; ++ unsigned int length; ++ ++ unsigned int header_len; ++ unsigned int tcp_header_len; ++ unsigned int tcp_payload_len; ++ unsigned short mss; ++ ++ unsigned short vlan_ctag; ++ ++ u64 rx_tstamp; ++}; ++ ++/* Common Rx and Tx descriptor mapping */ ++struct xgbe_ring_desc { ++ unsigned int desc0; ++ unsigned int desc1; ++ unsigned int desc2; ++ unsigned int desc3; ++}; ++ ++/* Structure used to hold information related to the descriptor ++ * and the packet associated with the descriptor (always use ++ * use the XGBE_GET_DESC_DATA macro to access this data from the ring) ++ */ ++struct xgbe_ring_data { ++ struct xgbe_ring_desc *rdesc; /* Virtual address of descriptor */ ++ dma_addr_t rdesc_dma; /* DMA address of descriptor */ ++ ++ struct sk_buff *skb; /* Virtual address of SKB */ ++ dma_addr_t skb_dma; /* DMA address of SKB data */ ++ unsigned int skb_dma_len; /* Length of SKB DMA area */ ++ unsigned int tso_header; /* TSO header indicator */ ++ ++ unsigned short len; /* Length of received Rx packet */ ++ ++ unsigned int interrupt; /* Interrupt indicator */ ++ ++ unsigned int mapped_as_page; ++ ++ /* Incomplete receive save location. If the budget is exhausted ++ * or the last descriptor (last normal descriptor or a following ++ * context descriptor) has not been DMA'd yet the current state ++ * of the receive processing needs to be saved. ++ */ ++ unsigned int state_saved; ++ struct { ++ unsigned int incomplete; ++ unsigned int context_next; ++ struct sk_buff *skb; ++ unsigned int len; ++ unsigned int error; ++ } state; ++}; ++ ++struct xgbe_ring { ++ /* Ring lock - used just for TX rings at the moment */ ++ spinlock_t lock; ++ ++ /* Per packet related information */ ++ struct xgbe_packet_data packet_data; ++ ++ /* Virtual/DMA addresses and count of allocated descriptor memory */ ++ struct xgbe_ring_desc *rdesc; ++ dma_addr_t rdesc_dma; ++ unsigned int rdesc_count; ++ ++ /* Array of descriptor data corresponding the descriptor memory ++ * (always use the XGBE_GET_DESC_DATA macro to access this data) ++ */ ++ struct xgbe_ring_data *rdata; ++ ++ /* Ring index values ++ * cur - Tx: index of descriptor to be used for current transfer ++ * Rx: index of descriptor to check for packet availability ++ * dirty - Tx: index of descriptor to check for transfer complete ++ * Rx: count of descriptors in which a packet has been received ++ * (used with skb_realloc_index to refresh the ring) ++ */ ++ unsigned int cur; ++ unsigned int dirty; ++ ++ /* Coalesce frame count used for interrupt bit setting */ ++ unsigned int coalesce_count; ++ ++ union { ++ struct { ++ unsigned int queue_stopped; ++ unsigned short cur_mss; ++ unsigned short cur_vlan_ctag; ++ } tx; ++ ++ struct { ++ unsigned int realloc_index; ++ unsigned int realloc_threshold; ++ } rx; ++ }; ++} ____cacheline_aligned; ++ ++/* Structure used to describe the descriptor rings associated with ++ * a DMA channel. ++ */ ++struct xgbe_channel { ++ char name[16]; ++ ++ /* Address of private data area for device */ ++ struct xgbe_prv_data *pdata; ++ ++ /* Queue index and base address of queue's DMA registers */ ++ unsigned int queue_index; ++ void __iomem *dma_regs; ++ ++ unsigned int saved_ier; ++ ++ unsigned int tx_timer_active; ++ struct hrtimer tx_timer; ++ ++ struct xgbe_ring *tx_ring; ++ struct xgbe_ring *rx_ring; ++} ____cacheline_aligned; ++ ++enum xgbe_int { ++ XGMAC_INT_DMA_CH_SR_TI, ++ XGMAC_INT_DMA_CH_SR_TPS, ++ XGMAC_INT_DMA_CH_SR_TBU, ++ XGMAC_INT_DMA_CH_SR_RI, ++ XGMAC_INT_DMA_CH_SR_RBU, ++ XGMAC_INT_DMA_CH_SR_RPS, ++ XGMAC_INT_DMA_CH_SR_TI_RI, ++ XGMAC_INT_DMA_CH_SR_FBE, ++ XGMAC_INT_DMA_ALL, ++}; ++ ++enum xgbe_int_state { ++ XGMAC_INT_STATE_SAVE, ++ XGMAC_INT_STATE_RESTORE, ++}; ++ ++enum xgbe_mtl_fifo_size { ++ XGMAC_MTL_FIFO_SIZE_256 = 0x00, ++ XGMAC_MTL_FIFO_SIZE_512 = 0x01, ++ XGMAC_MTL_FIFO_SIZE_1K = 0x03, ++ XGMAC_MTL_FIFO_SIZE_2K = 0x07, ++ XGMAC_MTL_FIFO_SIZE_4K = 0x0f, ++ XGMAC_MTL_FIFO_SIZE_8K = 0x1f, ++ XGMAC_MTL_FIFO_SIZE_16K = 0x3f, ++ XGMAC_MTL_FIFO_SIZE_32K = 0x7f, ++ XGMAC_MTL_FIFO_SIZE_64K = 0xff, ++ XGMAC_MTL_FIFO_SIZE_128K = 0x1ff, ++ XGMAC_MTL_FIFO_SIZE_256K = 0x3ff, ++}; ++ ++struct xgbe_mmc_stats { ++ /* Tx Stats */ ++ u64 txoctetcount_gb; ++ u64 txframecount_gb; ++ u64 txbroadcastframes_g; ++ u64 txmulticastframes_g; ++ u64 tx64octets_gb; ++ u64 tx65to127octets_gb; ++ u64 tx128to255octets_gb; ++ u64 tx256to511octets_gb; ++ u64 tx512to1023octets_gb; ++ u64 tx1024tomaxoctets_gb; ++ u64 txunicastframes_gb; ++ u64 txmulticastframes_gb; ++ u64 txbroadcastframes_gb; ++ u64 txunderflowerror; ++ u64 txoctetcount_g; ++ u64 txframecount_g; ++ u64 txpauseframes; ++ u64 txvlanframes_g; ++ ++ /* Rx Stats */ ++ u64 rxframecount_gb; ++ u64 rxoctetcount_gb; ++ u64 rxoctetcount_g; ++ u64 rxbroadcastframes_g; ++ u64 rxmulticastframes_g; ++ u64 rxcrcerror; ++ u64 rxrunterror; ++ u64 rxjabbererror; ++ u64 rxundersize_g; ++ u64 rxoversize_g; ++ u64 rx64octets_gb; ++ u64 rx65to127octets_gb; ++ u64 rx128to255octets_gb; ++ u64 rx256to511octets_gb; ++ u64 rx512to1023octets_gb; ++ u64 rx1024tomaxoctets_gb; ++ u64 rxunicastframes_g; ++ u64 rxlengtherror; ++ u64 rxoutofrangetype; ++ u64 rxpauseframes; ++ u64 rxfifooverflow; ++ u64 rxvlanframes_gb; ++ u64 rxwatchdogerror; ++}; ++ ++struct xgbe_hw_if { ++ int (*tx_complete)(struct xgbe_ring_desc *); ++ ++ int (*set_promiscuous_mode)(struct xgbe_prv_data *, unsigned int); ++ int (*set_all_multicast_mode)(struct xgbe_prv_data *, unsigned int); ++ int (*add_mac_addresses)(struct xgbe_prv_data *); ++ int (*set_mac_address)(struct xgbe_prv_data *, u8 *addr); ++ ++ int (*enable_rx_csum)(struct xgbe_prv_data *); ++ int (*disable_rx_csum)(struct xgbe_prv_data *); ++ ++ int (*enable_rx_vlan_stripping)(struct xgbe_prv_data *); ++ int (*disable_rx_vlan_stripping)(struct xgbe_prv_data *); ++ int (*enable_rx_vlan_filtering)(struct xgbe_prv_data *); ++ int (*disable_rx_vlan_filtering)(struct xgbe_prv_data *); ++ int (*update_vlan_hash_table)(struct xgbe_prv_data *); ++ ++ int (*read_mmd_regs)(struct xgbe_prv_data *, int, int); ++ void (*write_mmd_regs)(struct xgbe_prv_data *, int, int, int); ++ int (*set_gmii_speed)(struct xgbe_prv_data *); ++ int (*set_gmii_2500_speed)(struct xgbe_prv_data *); ++ int (*set_xgmii_speed)(struct xgbe_prv_data *); ++ ++ void (*enable_tx)(struct xgbe_prv_data *); ++ void (*disable_tx)(struct xgbe_prv_data *); ++ void (*enable_rx)(struct xgbe_prv_data *); ++ void (*disable_rx)(struct xgbe_prv_data *); ++ ++ void (*powerup_tx)(struct xgbe_prv_data *); ++ void (*powerdown_tx)(struct xgbe_prv_data *); ++ void (*powerup_rx)(struct xgbe_prv_data *); ++ void (*powerdown_rx)(struct xgbe_prv_data *); ++ ++ int (*init)(struct xgbe_prv_data *); ++ int (*exit)(struct xgbe_prv_data *); ++ ++ int (*enable_int)(struct xgbe_channel *, enum xgbe_int); ++ int (*disable_int)(struct xgbe_channel *, enum xgbe_int); ++ void (*pre_xmit)(struct xgbe_channel *); ++ int (*dev_read)(struct xgbe_channel *); ++ void (*tx_desc_init)(struct xgbe_channel *); ++ void (*rx_desc_init)(struct xgbe_channel *); ++ void (*rx_desc_reset)(struct xgbe_ring_data *); ++ void (*tx_desc_reset)(struct xgbe_ring_data *); ++ int (*is_last_desc)(struct xgbe_ring_desc *); ++ int (*is_context_desc)(struct xgbe_ring_desc *); ++ ++ /* For FLOW ctrl */ ++ int (*config_tx_flow_control)(struct xgbe_prv_data *); ++ int (*config_rx_flow_control)(struct xgbe_prv_data *); ++ ++ /* For RX coalescing */ ++ int (*config_rx_coalesce)(struct xgbe_prv_data *); ++ int (*config_tx_coalesce)(struct xgbe_prv_data *); ++ unsigned int (*usec_to_riwt)(struct xgbe_prv_data *, unsigned int); ++ unsigned int (*riwt_to_usec)(struct xgbe_prv_data *, unsigned int); ++ ++ /* For RX and TX threshold config */ ++ int (*config_rx_threshold)(struct xgbe_prv_data *, unsigned int); ++ int (*config_tx_threshold)(struct xgbe_prv_data *, unsigned int); ++ ++ /* For RX and TX Store and Forward Mode config */ ++ int (*config_rsf_mode)(struct xgbe_prv_data *, unsigned int); ++ int (*config_tsf_mode)(struct xgbe_prv_data *, unsigned int); ++ ++ /* For TX DMA Operate on Second Frame config */ ++ int (*config_osp_mode)(struct xgbe_prv_data *); ++ ++ /* For RX and TX PBL config */ ++ int (*config_rx_pbl_val)(struct xgbe_prv_data *); ++ int (*get_rx_pbl_val)(struct xgbe_prv_data *); ++ int (*config_tx_pbl_val)(struct xgbe_prv_data *); ++ int (*get_tx_pbl_val)(struct xgbe_prv_data *); ++ int (*config_pblx8)(struct xgbe_prv_data *); ++ ++ /* For MMC statistics */ ++ void (*rx_mmc_int)(struct xgbe_prv_data *); ++ void (*tx_mmc_int)(struct xgbe_prv_data *); ++ void (*read_mmc_stats)(struct xgbe_prv_data *); ++ ++ /* For Timestamp config */ ++ int (*config_tstamp)(struct xgbe_prv_data *, unsigned int); ++ void (*update_tstamp_addend)(struct xgbe_prv_data *, unsigned int); ++ void (*set_tstamp_time)(struct xgbe_prv_data *, unsigned int sec, ++ unsigned int nsec); ++ u64 (*get_tstamp_time)(struct xgbe_prv_data *); ++ u64 (*get_tx_tstamp)(struct xgbe_prv_data *); ++ ++ /* For Data Center Bridging config */ ++ void (*config_dcb_tc)(struct xgbe_prv_data *); ++ void (*config_dcb_pfc)(struct xgbe_prv_data *); ++}; ++ ++struct xgbe_desc_if { ++ int (*alloc_ring_resources)(struct xgbe_prv_data *); ++ void (*free_ring_resources)(struct xgbe_prv_data *); ++ int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *); ++ void (*realloc_skb)(struct xgbe_channel *); ++ void (*unmap_skb)(struct xgbe_prv_data *, struct xgbe_ring_data *); ++ void (*wrapper_tx_desc_init)(struct xgbe_prv_data *); ++ void (*wrapper_rx_desc_init)(struct xgbe_prv_data *); ++}; ++ ++/* This structure contains flags that indicate what hardware features ++ * or configurations are present in the device. ++ */ ++struct xgbe_hw_features { ++ /* HW Feature Register0 */ ++ unsigned int gmii; /* 1000 Mbps support */ ++ unsigned int vlhash; /* VLAN Hash Filter */ ++ unsigned int sma; /* SMA(MDIO) Interface */ ++ unsigned int rwk; /* PMT remote wake-up packet */ ++ unsigned int mgk; /* PMT magic packet */ ++ unsigned int mmc; /* RMON module */ ++ unsigned int aoe; /* ARP Offload */ ++ unsigned int ts; /* IEEE 1588-2008 Adavanced Timestamp */ ++ unsigned int eee; /* Energy Efficient Ethernet */ ++ unsigned int tx_coe; /* Tx Checksum Offload */ ++ unsigned int rx_coe; /* Rx Checksum Offload */ ++ unsigned int addn_mac; /* Additional MAC Addresses */ ++ unsigned int ts_src; /* Timestamp Source */ ++ unsigned int sa_vlan_ins; /* Source Address or VLAN Insertion */ ++ ++ /* HW Feature Register1 */ ++ unsigned int rx_fifo_size; /* MTL Receive FIFO Size */ ++ unsigned int tx_fifo_size; /* MTL Transmit FIFO Size */ ++ unsigned int adv_ts_hi; /* Advance Timestamping High Word */ ++ unsigned int dcb; /* DCB Feature */ ++ unsigned int sph; /* Split Header Feature */ ++ unsigned int tso; /* TCP Segmentation Offload */ ++ unsigned int dma_debug; /* DMA Debug Registers */ ++ unsigned int rss; /* Receive Side Scaling */ ++ unsigned int tc_cnt; /* Number of Traffic Classes */ ++ unsigned int hash_table_size; /* Hash Table Size */ ++ unsigned int l3l4_filter_num; /* Number of L3-L4 Filters */ ++ ++ /* HW Feature Register2 */ ++ unsigned int rx_q_cnt; /* Number of MTL Receive Queues */ ++ unsigned int tx_q_cnt; /* Number of MTL Transmit Queues */ ++ unsigned int rx_ch_cnt; /* Number of DMA Receive Channels */ ++ unsigned int tx_ch_cnt; /* Number of DMA Transmit Channels */ ++ unsigned int pps_out_num; /* Number of PPS outputs */ ++ unsigned int aux_snap_num; /* Number of Aux snapshot inputs */ ++}; ++ ++struct xgbe_prv_data { ++ struct net_device *netdev; ++ struct platform_device *pdev; ++ struct device *dev; ++ ++ /* XGMAC/XPCS related mmio registers */ ++ void __iomem *xgmac_regs; /* XGMAC CSRs */ ++ void __iomem *xpcs_regs; /* XPCS MMD registers */ ++ ++ /* Overall device lock */ ++ spinlock_t lock; ++ ++ /* XPCS indirect addressing mutex */ ++ struct mutex xpcs_mutex; ++ ++ int irq_number; ++ ++ struct xgbe_hw_if hw_if; ++ struct xgbe_desc_if desc_if; ++ ++ /* AXI DMA settings */ ++ unsigned int axdomain; ++ unsigned int arcache; ++ unsigned int awcache; ++ ++ /* Rings for Tx/Rx on a DMA channel */ ++ struct xgbe_channel *channel; ++ unsigned int channel_count; ++ unsigned int tx_ring_count; ++ unsigned int tx_desc_count; ++ unsigned int rx_ring_count; ++ unsigned int rx_desc_count; ++ ++ unsigned int tx_q_count; ++ unsigned int rx_q_count; ++ ++ /* Tx/Rx common settings */ ++ unsigned int pblx8; ++ ++ /* Tx settings */ ++ unsigned int tx_sf_mode; ++ unsigned int tx_threshold; ++ unsigned int tx_pbl; ++ unsigned int tx_osp_mode; ++ ++ /* Rx settings */ ++ unsigned int rx_sf_mode; ++ unsigned int rx_threshold; ++ unsigned int rx_pbl; ++ ++ /* Tx coalescing settings */ ++ unsigned int tx_usecs; ++ unsigned int tx_frames; ++ ++ /* Rx coalescing settings */ ++ unsigned int rx_riwt; ++ unsigned int rx_frames; ++ ++ /* Current MTU */ ++ unsigned int rx_buf_size; ++ ++ /* Flow control settings */ ++ unsigned int pause_autoneg; ++ unsigned int tx_pause; ++ unsigned int rx_pause; ++ ++ /* MDIO settings */ ++ struct module *phy_module; ++ char *mii_bus_id; ++ struct mii_bus *mii; ++ int mdio_mmd; ++ struct phy_device *phydev; ++ int default_autoneg; ++ int default_speed; ++ ++ /* Current PHY settings */ ++ phy_interface_t phy_mode; ++ int phy_link; ++ int phy_speed; ++ unsigned int phy_tx_pause; ++ unsigned int phy_rx_pause; ++ ++ /* Netdev related settings */ ++ netdev_features_t netdev_features; ++ struct napi_struct napi; ++ struct xgbe_mmc_stats mmc_stats; ++ ++ /* Filtering support */ ++ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; ++ ++ /* Device clocks */ ++ struct clk *sysclk; ++ struct clk *ptpclk; ++ ++ /* Timestamp support */ ++ spinlock_t tstamp_lock; ++ struct ptp_clock_info ptp_clock_info; ++ struct ptp_clock *ptp_clock; ++ struct hwtstamp_config tstamp_config; ++ struct cyclecounter tstamp_cc; ++ struct timecounter tstamp_tc; ++ unsigned int tstamp_addend; ++ struct work_struct tx_tstamp_work; ++ struct sk_buff *tx_tstamp_skb; ++ u64 tx_tstamp; ++ ++ /* DCB support */ ++ struct ieee_ets *ets; ++ struct ieee_pfc *pfc; ++ unsigned int q2tc_map[XGBE_MAX_QUEUES]; ++ unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS]; ++ ++ /* Hardware features of the device */ ++ struct xgbe_hw_features hw_feat; ++ ++ /* Device restart work structure */ ++ struct work_struct restart_work; ++ ++ /* Keeps track of power mode */ ++ unsigned int power_down; ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *xgbe_debugfs; ++ ++ unsigned int debugfs_xgmac_reg; ++ ++ unsigned int debugfs_xpcs_mmd; ++ unsigned int debugfs_xpcs_reg; ++#endif ++}; ++ ++/* Function prototypes*/ ++ ++void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *); ++void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *); ++struct net_device_ops *xgbe_get_netdev_ops(void); ++struct ethtool_ops *xgbe_get_ethtool_ops(void); ++#ifdef CONFIG_AMD_XGBE_DCB ++const struct dcbnl_rtnl_ops *xgbe_get_dcbnl_ops(void); ++#endif ++ ++int xgbe_mdio_register(struct xgbe_prv_data *); ++void xgbe_mdio_unregister(struct xgbe_prv_data *); ++void xgbe_dump_phy_registers(struct xgbe_prv_data *); ++void xgbe_ptp_register(struct xgbe_prv_data *); ++void xgbe_ptp_unregister(struct xgbe_prv_data *); ++void xgbe_dump_tx_desc(struct xgbe_ring *, unsigned int, unsigned int, ++ unsigned int); ++void xgbe_dump_rx_desc(struct xgbe_ring *, struct xgbe_ring_desc *, ++ unsigned int); ++void xgbe_print_pkt(struct net_device *, struct sk_buff *, bool); ++void xgbe_get_all_hw_features(struct xgbe_prv_data *); ++int xgbe_powerup(struct net_device *, unsigned int); ++int xgbe_powerdown(struct net_device *, unsigned int); ++void xgbe_init_rx_coalesce(struct xgbe_prv_data *); ++void xgbe_init_tx_coalesce(struct xgbe_prv_data *); ++ ++#ifdef CONFIG_DEBUG_FS ++void xgbe_debugfs_init(struct xgbe_prv_data *); ++void xgbe_debugfs_exit(struct xgbe_prv_data *); ++#else ++static inline void xgbe_debugfs_init(struct xgbe_prv_data *pdata) {} ++static inline void xgbe_debugfs_exit(struct xgbe_prv_data *pdata) {} ++#endif /* CONFIG_DEBUG_FS */ ++ ++/* NOTE: Uncomment for TX and RX DESCRIPTOR DUMP in KERNEL LOG */ ++#if 0 ++#define XGMAC_ENABLE_TX_DESC_DUMP ++#define XGMAC_ENABLE_RX_DESC_DUMP ++#endif ++ ++/* NOTE: Uncomment for TX and RX PACKET DUMP in KERNEL LOG */ ++#if 0 ++#define XGMAC_ENABLE_TX_PKT_DUMP ++#define XGMAC_ENABLE_RX_PKT_DUMP ++#endif ++ ++/* NOTE: Uncomment for function trace log messages in KERNEL LOG */ ++#if 0 ++#define YDEBUG ++#define YDEBUG_MDIO ++#endif ++ ++/* For debug prints */ ++#ifdef YDEBUG ++#define DBGPR(x...) pr_alert(x) ++#define DBGPHY_REGS(x...) xgbe_dump_phy_registers(x) ++#else ++#define DBGPR(x...) do { } while (0) ++#define DBGPHY_REGS(x...) do { } while (0) ++#endif ++ ++#ifdef YDEBUG_MDIO ++#define DBGPR_MDIO(x...) pr_alert(x) ++#else ++#define DBGPR_MDIO(x...) do { } while (0) ++#endif ++ ++#endif +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 7dc3d5b..9418925 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -34,3 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o + obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o + obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-phy.o ++obj-$(CONFIG_AMD_XGBE_PHY) += amd-xgbe-a0-phy.o +diff --git a/drivers/net/phy/amd-xgbe-a0-phy.c b/drivers/net/phy/amd-xgbe-a0-phy.c +new file mode 100644 +index 0000000..90145d9 +--- /dev/null ++++ b/drivers/net/phy/amd-xgbe-a0-phy.c +@@ -0,0 +1,1445 @@ ++/* ++ * AMD 10Gb Ethernet PHY driver ++ * ++ * This file is available to you under your choice of the following two ++ * licenses: ++ * ++ * License 1: GPLv2 ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, Inc. ++ * ++ * This file is free software; you may copy, redistribute 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 file is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ * ++ * ++ * License 2: Modified BSD ++ * ++ * Copyright (c) 2014 Advanced Micro Devices, 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 Advanced Micro Devices, Inc. nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (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 <linux/kernel.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/unistd.h> ++#include <linux/slab.h> ++#include <linux/interrupt.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/mm.h> ++#include <linux/module.h> ++#include <linux/mii.h> ++#include <linux/ethtool.h> ++#include <linux/phy.h> ++#include <linux/mdio.h> ++#include <linux/io.h> ++#include <linux/of.h> ++#include <linux/of_platform.h> ++#include <linux/of_device.h> ++#include <linux/uaccess.h> ++ ++ ++MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_VERSION("0.0.0-a"); ++MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver"); ++ ++#define XGBE_PHY_ID 0x7996ced0 ++#define XGBE_PHY_MASK 0xfffffff0 ++ ++#define XGBE_PHY_SERDES_RETRY 32 ++#define XGBE_PHY_CHANNEL_PROPERTY "amd,serdes-channel" ++#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set" ++ ++#define XGBE_AN_INT_CMPLT 0x01 ++#define XGBE_AN_INC_LINK 0x02 ++#define XGBE_AN_PG_RCV 0x04 ++ ++#define XNP_MCF_NULL_MESSAGE 0x001 ++#define XNP_ACK_PROCESSED (1 << 12) ++#define XNP_MP_FORMATTED (1 << 13) ++#define XNP_NP_EXCHANGE (1 << 15) ++ ++#define XGBE_PHY_RATECHANGE_COUNT 500 ++ ++#ifndef MDIO_PMA_10GBR_PMD_CTRL ++#define MDIO_PMA_10GBR_PMD_CTRL 0x0096 ++#endif ++#ifndef MDIO_PMA_10GBR_FEC_CTRL ++#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab ++#endif ++#ifndef MDIO_AN_XNP ++#define MDIO_AN_XNP 0x0016 ++#endif ++ ++#ifndef MDIO_AN_INTMASK ++#define MDIO_AN_INTMASK 0x8001 ++#endif ++#ifndef MDIO_AN_INT ++#define MDIO_AN_INT 0x8002 ++#endif ++ ++#ifndef MDIO_CTRL1_SPEED1G ++#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100) ++#endif ++ ++#define GET_BITS(_var, _index, _width) \ ++ (((_var) >> (_index)) & ((0x1 << (_width)) - 1)) ++ ++#define SET_BITS(_var, _index, _width, _val) \ ++do { \ ++ (_var) &= ~(((0x1 << (_width)) - 1) << (_index)); \ ++ (_var) |= (((_val) & ((0x1 << (_width)) - 1)) << (_index)); \ ++} while (0) ++ ++#define XCMU_IOREAD(_priv, _reg) \ ++ ioread16((_priv)->cmu_regs + _reg) ++ ++#define XCMU_IOWRITE(_priv, _reg, _val) \ ++ iowrite16((_val), (_priv)->cmu_regs + _reg) ++ ++#define XRXTX_IOREAD(_priv, _reg) \ ++ ioread16((_priv)->rxtx_regs + _reg) ++ ++#define XRXTX_IOREAD_BITS(_priv, _reg, _field) \ ++ GET_BITS(XRXTX_IOREAD((_priv), _reg), \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH) ++ ++#define XRXTX_IOWRITE(_priv, _reg, _val) \ ++ iowrite16((_val), (_priv)->rxtx_regs + _reg) ++ ++#define XRXTX_IOWRITE_BITS(_priv, _reg, _field, _val) \ ++do { \ ++ u16 reg_val = XRXTX_IOREAD((_priv), _reg); \ ++ SET_BITS(reg_val, \ ++ _reg##_##_field##_INDEX, \ ++ _reg##_##_field##_WIDTH, (_val)); \ ++ XRXTX_IOWRITE((_priv), _reg, reg_val); \ ++} while (0) ++ ++/* SerDes CMU register offsets */ ++#define CMU_REG15 0x003c ++#define CMU_REG16 0x0040 ++ ++/* SerDes CMU register entry bit positions and sizes */ ++#define CMU_REG16_TX_RATE_CHANGE_BASE 15 ++#define CMU_REG16_RX_RATE_CHANGE_BASE 14 ++#define CMU_REG16_RATE_CHANGE_DECR 2 ++ ++ ++/* SerDes RxTx register offsets */ ++#define RXTX_REG2 0x0008 ++#define RXTX_REG3 0x000c ++#define RXTX_REG5 0x0014 ++#define RXTX_REG6 0x0018 ++#define RXTX_REG20 0x0050 ++#define RXTX_REG53 0x00d4 ++#define RXTX_REG114 0x01c8 ++#define RXTX_REG115 0x01cc ++#define RXTX_REG142 0x0238 ++ ++/* SerDes RxTx register entry bit positions and sizes */ ++#define RXTX_REG2_RESETB_INDEX 15 ++#define RXTX_REG2_RESETB_WIDTH 1 ++#define RXTX_REG3_TX_DATA_RATE_INDEX 14 ++#define RXTX_REG3_TX_DATA_RATE_WIDTH 2 ++#define RXTX_REG3_TX_WORD_MODE_INDEX 11 ++#define RXTX_REG3_TX_WORD_MODE_WIDTH 3 ++#define RXTX_REG5_TXAMP_CNTL_INDEX 7 ++#define RXTX_REG5_TXAMP_CNTL_WIDTH 4 ++#define RXTX_REG6_RX_DATA_RATE_INDEX 9 ++#define RXTX_REG6_RX_DATA_RATE_WIDTH 2 ++#define RXTX_REG6_RX_WORD_MODE_INDEX 11 ++#define RXTX_REG6_RX_WORD_MODE_WIDTH 3 ++#define RXTX_REG20_BLWC_ENA_INDEX 2 ++#define RXTX_REG20_BLWC_ENA_WIDTH 1 ++#define RXTX_REG53_RX_PLLSELECT_INDEX 15 ++#define RXTX_REG53_RX_PLLSELECT_WIDTH 1 ++#define RXTX_REG53_TX_PLLSELECT_INDEX 14 ++#define RXTX_REG53_TX_PLLSELECT_WIDTH 1 ++#define RXTX_REG53_PI_SPD_SEL_CDR_INDEX 10 ++#define RXTX_REG53_PI_SPD_SEL_CDR_WIDTH 4 ++#define RXTX_REG114_PQ_REG_INDEX 9 ++#define RXTX_REG114_PQ_REG_WIDTH 7 ++#define RXTX_REG115_FORCE_LAT_CAL_START_INDEX 2 ++#define RXTX_REG115_FORCE_LAT_CAL_START_WIDTH 1 ++#define RXTX_REG115_FORCE_SUM_CAL_START_INDEX 1 ++#define RXTX_REG115_FORCE_SUM_CAL_START_WIDTH 1 ++#define RXTX_REG142_SUM_CALIB_DONE_INDEX 15 ++#define RXTX_REG142_SUM_CALIB_DONE_WIDTH 1 ++#define RXTX_REG142_SUM_CALIB_ERR_INDEX 14 ++#define RXTX_REG142_SUM_CALIB_ERR_WIDTH 1 ++#define RXTX_REG142_LAT_CALIB_DONE_INDEX 11 ++#define RXTX_REG142_LAT_CALIB_DONE_WIDTH 1 ++ ++#define RXTX_FULL_RATE 0x0 ++#define RXTX_HALF_RATE 0x1 ++#define RXTX_FIFTH_RATE 0x3 ++#define RXTX_66BIT_WORD 0x7 ++#define RXTX_10BIT_WORD 0x1 ++#define RXTX_10G_TX_AMP 0xa ++#define RXTX_1G_TX_AMP 0xf ++#define RXTX_10G_CDR 0x7 ++#define RXTX_1G_CDR 0x2 ++#define RXTX_10G_PLL 0x1 ++#define RXTX_1G_PLL 0x0 ++#define RXTX_10G_PQ 0x1e ++#define RXTX_1G_PQ 0xa ++ ++ ++DEFINE_SPINLOCK(cmu_lock); ++ ++enum amd_xgbe_phy_an { ++ AMD_XGBE_AN_READY = 0, ++ AMD_XGBE_AN_START, ++ AMD_XGBE_AN_EVENT, ++ AMD_XGBE_AN_PAGE_RECEIVED, ++ AMD_XGBE_AN_INCOMPAT_LINK, ++ AMD_XGBE_AN_COMPLETE, ++ AMD_XGBE_AN_NO_LINK, ++ AMD_XGBE_AN_EXIT, ++ AMD_XGBE_AN_ERROR, ++}; ++ ++enum amd_xgbe_phy_rx { ++ AMD_XGBE_RX_READY = 0, ++ AMD_XGBE_RX_BPA, ++ AMD_XGBE_RX_XNP, ++ AMD_XGBE_RX_COMPLETE, ++}; ++ ++enum amd_xgbe_phy_mode { ++ AMD_XGBE_MODE_KR, ++ AMD_XGBE_MODE_KX, ++}; ++ ++enum amd_xgbe_phy_speedset { ++ AMD_XGBE_PHY_SPEEDSET_1000_10000, ++ AMD_XGBE_PHY_SPEEDSET_2500_10000, ++}; ++ ++struct amd_xgbe_phy_priv { ++ struct platform_device *pdev; ++ struct device *dev; ++ ++ struct phy_device *phydev; ++ ++ /* SerDes related mmio resources */ ++ struct resource *rxtx_res; ++ struct resource *cmu_res; ++ ++ /* SerDes related mmio registers */ ++ void __iomem *rxtx_regs; /* SerDes Rx/Tx CSRs */ ++ void __iomem *cmu_regs; /* SerDes CMU CSRs */ ++ ++ unsigned int serdes_channel; ++ unsigned int speed_set; ++ ++ /* Maintain link status for re-starting auto-negotiation */ ++ unsigned int link; ++ enum amd_xgbe_phy_mode mode; ++ ++ /* Auto-negotiation state machine support */ ++ struct mutex an_mutex; ++ enum amd_xgbe_phy_an an_result; ++ enum amd_xgbe_phy_an an_state; ++ enum amd_xgbe_phy_rx kr_state; ++ enum amd_xgbe_phy_rx kx_state; ++ struct work_struct an_work; ++ struct workqueue_struct *an_workqueue; ++}; ++ ++static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); ++ if (ret < 0) ++ return ret; ++ ++ ret |= 0x02; ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); ++ ++ return 0; ++} ++ ++static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~0x02; ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_pcs_power_cycle(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret |= MDIO_CTRL1_LPOWER; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ usleep_range(75, 100); ++ ++ ret &= ~MDIO_CTRL1_LPOWER; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ return 0; ++} ++ ++static void amd_xgbe_phy_serdes_start_ratechange(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ u16 val, mask; ++ ++ /* Assert Rx and Tx ratechange in CMU_reg16 */ ++ val = XCMU_IOREAD(priv, CMU_REG16); ++ ++ mask = (1 << (CMU_REG16_TX_RATE_CHANGE_BASE - ++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))) | ++ (1 << (CMU_REG16_RX_RATE_CHANGE_BASE - ++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))); ++ val |= mask; ++ ++ XCMU_IOWRITE(priv, CMU_REG16, val); ++} ++ ++static void amd_xgbe_phy_serdes_complete_ratechange(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ u16 val, mask; ++ unsigned int wait; ++ ++ /* Release Rx and Tx ratechange for proper channel in CMU_reg16 */ ++ val = XCMU_IOREAD(priv, CMU_REG16); ++ ++ mask = (1 << (CMU_REG16_TX_RATE_CHANGE_BASE - ++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))) | ++ (1 << (CMU_REG16_RX_RATE_CHANGE_BASE - ++ (priv->serdes_channel * CMU_REG16_RATE_CHANGE_DECR))); ++ val &= ~mask; ++ ++ XCMU_IOWRITE(priv, CMU_REG16, val); ++ ++ /* Wait for Rx and Tx ready in CMU_reg15 */ ++ mask = (1 << priv->serdes_channel) | ++ (1 << (priv->serdes_channel + 8)); ++ wait = XGBE_PHY_RATECHANGE_COUNT; ++ while (wait--) { ++ udelay(50); ++ ++ val = XCMU_IOREAD(priv, CMU_REG15); ++ if ((val & mask) == mask) ++ return; ++ } ++ ++ netdev_dbg(phydev->attached_dev, "SerDes rx/tx not ready (%#hx)\n", ++ val); ++} ++ ++static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; ++ ++ /* Disable KR training */ ++ ret = amd_xgbe_an_disable_kr_training(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set PCS to KR/10G speed */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_PCS_CTRL2_TYPE; ++ ret |= MDIO_PCS_CTRL2_10GBR; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_CTRL1_SPEEDSEL; ++ ret |= MDIO_CTRL1_SPEED10G; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ ret = amd_xgbe_phy_pcs_power_cycle(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set SerDes to 10G speed */ ++ spin_lock(&cmu_lock); ++ ++ amd_xgbe_phy_serdes_start_ratechange(phydev); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_FULL_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_66BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_10G_TX_AMP); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FULL_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_66BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 0); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_10G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_10G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_10G_CDR); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10G_PQ); ++ ++ amd_xgbe_phy_serdes_complete_ratechange(phydev); ++ ++ spin_unlock(&cmu_lock); ++ ++ priv->mode = AMD_XGBE_MODE_KR; ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; ++ ++ /* Disable KR training */ ++ ret = amd_xgbe_an_disable_kr_training(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set PCS to KX/1G speed */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_PCS_CTRL2_TYPE; ++ ret |= MDIO_PCS_CTRL2_10GBX; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_CTRL1_SPEEDSEL; ++ ret |= MDIO_CTRL1_SPEED1G; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ ret = amd_xgbe_phy_pcs_power_cycle(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set SerDes to 2.5G speed */ ++ spin_lock(&cmu_lock); ++ ++ amd_xgbe_phy_serdes_start_ratechange(phydev); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_HALF_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_10BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_HALF_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 1); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_1G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_1G_CDR); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1G_PQ); ++ ++ amd_xgbe_phy_serdes_complete_ratechange(phydev); ++ ++ spin_unlock(&cmu_lock); ++ ++ priv->mode = AMD_XGBE_MODE_KX; ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; ++ ++ /* Disable KR training */ ++ ret = amd_xgbe_an_disable_kr_training(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set PCS to KX/1G speed */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_PCS_CTRL2_TYPE; ++ ret |= MDIO_PCS_CTRL2_10GBX; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2, ret); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_CTRL1_SPEEDSEL; ++ ret |= MDIO_CTRL1_SPEED1G; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ ret = amd_xgbe_phy_pcs_power_cycle(phydev); ++ if (ret < 0) ++ return ret; ++ ++ /* Set SerDes to 1G speed */ ++ spin_lock(&cmu_lock); ++ ++ amd_xgbe_phy_serdes_start_ratechange(phydev); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_DATA_RATE, RXTX_FIFTH_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG3, TX_WORD_MODE, RXTX_10BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG5, TXAMP_CNTL, RXTX_1G_TX_AMP); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_DATA_RATE, RXTX_FIFTH_RATE); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG6, RX_WORD_MODE, RXTX_10BIT_WORD); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, 1); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, RX_PLLSELECT, RXTX_1G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, TX_PLLSELECT, RXTX_1G_PLL); ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG53, PI_SPD_SEL_CDR, RXTX_1G_CDR); ++ ++ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1G_PQ); ++ ++ amd_xgbe_phy_serdes_complete_ratechange(phydev); ++ ++ spin_unlock(&cmu_lock); ++ ++ priv->mode = AMD_XGBE_MODE_KX; ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_switch_mode(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; ++ ++ /* If we are in KR switch to KX, and vice-versa */ ++ if (priv->mode == AMD_XGBE_MODE_KR) { ++ if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000) ++ ret = amd_xgbe_phy_gmii_mode(phydev); ++ else ++ ret = amd_xgbe_phy_gmii_2500_mode(phydev); ++ } else { ++ ret = amd_xgbe_phy_xgmii_mode(phydev); ++ } ++ ++ return ret; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ret = amd_xgbe_phy_switch_mode(phydev); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ return AMD_XGBE_AN_START; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev, ++ enum amd_xgbe_phy_rx *state) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ad_reg, lp_reg, ret; ++ ++ *state = AMD_XGBE_RX_COMPLETE; ++ ++ /* If we're in KX mode then we're done */ ++ if (priv->mode == AMD_XGBE_MODE_KX) ++ return AMD_XGBE_AN_EVENT; ++ ++ /* Enable/Disable FEC */ ++ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ++ if (ad_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 2); ++ if (lp_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) ++ ret |= 0x01; ++ else ++ ret &= ~0x01; ++ ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret); ++ ++ /* Start KR training */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ ret |= 0x01; ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret); ++ ++ return AMD_XGBE_AN_EVENT; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev, ++ enum amd_xgbe_phy_rx *state) ++{ ++ u16 msg; ++ ++ *state = AMD_XGBE_RX_XNP; ++ ++ msg = XNP_MCF_NULL_MESSAGE; ++ msg |= XNP_MP_FORMATTED; ++ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 2, 0); ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0); ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg); ++ ++ return AMD_XGBE_AN_EVENT; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev, ++ enum amd_xgbe_phy_rx *state) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ unsigned int link_support; ++ int ret, ad_reg, lp_reg; ++ ++ /* Read Base Ability register 2 first */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ /* Check for a supported mode, otherwise restart in a different one */ ++ link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20; ++ if (!(ret & link_support)) ++ return amd_xgbe_an_switch_mode(phydev); ++ ++ /* Check Extended Next Page support */ ++ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ if (ad_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); ++ if (lp_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ? ++ amd_xgbe_an_tx_xnp(phydev, state) : ++ amd_xgbe_an_tx_training(phydev, state); ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev, ++ enum amd_xgbe_phy_rx *state) ++{ ++ int ad_reg, lp_reg; ++ ++ /* Check Extended Next Page support */ ++ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ if (ad_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); ++ if (lp_reg < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ return ((ad_reg & XNP_NP_EXCHANGE) || (lp_reg & XNP_NP_EXCHANGE)) ? ++ amd_xgbe_an_tx_xnp(phydev, state) : ++ amd_xgbe_an_tx_training(phydev, state); ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ int ret; ++ ++ /* Be sure we aren't looping trying to negotiate */ ++ if (priv->mode == AMD_XGBE_MODE_KR) { ++ if (priv->kr_state != AMD_XGBE_RX_READY) ++ return AMD_XGBE_AN_NO_LINK; ++ priv->kr_state = AMD_XGBE_RX_BPA; ++ } else { ++ if (priv->kx_state != AMD_XGBE_RX_READY) ++ return AMD_XGBE_AN_NO_LINK; ++ priv->kx_state = AMD_XGBE_RX_BPA; ++ } ++ ++ /* Set up Advertisement register 3 first */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ if (phydev->supported & SUPPORTED_10000baseR_FEC) ++ ret |= 0xc000; ++ else ++ ret &= ~0xc000; ++ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret); ++ ++ /* Set up Advertisement register 2 next */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ if (phydev->supported & SUPPORTED_10000baseKR_Full) ++ ret |= 0x80; ++ else ++ ret &= ~0x80; ++ ++ if ((phydev->supported & SUPPORTED_1000baseKX_Full) || ++ (phydev->supported & SUPPORTED_2500baseX_Full)) ++ ret |= 0x20; ++ else ++ ret &= ~0x20; ++ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret); ++ ++ /* Set up Advertisement register 1 last */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ if (phydev->supported & SUPPORTED_Pause) ++ ret |= 0x400; ++ else ++ ret &= ~0x400; ++ ++ if (phydev->supported & SUPPORTED_Asym_Pause) ++ ret |= 0x800; ++ else ++ ret &= ~0x800; ++ ++ /* We don't intend to perform XNP */ ++ ret &= ~XNP_NP_EXCHANGE; ++ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret); ++ ++ /* Enable and start auto-negotiation */ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ ret |= MDIO_AN_CTRL1_ENABLE; ++ ret |= MDIO_AN_CTRL1_RESTART; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); ++ ++ return AMD_XGBE_AN_EVENT; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev) ++{ ++ enum amd_xgbe_phy_an new_state; ++ int ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT); ++ if (ret < 0) ++ return AMD_XGBE_AN_ERROR; ++ ++ new_state = AMD_XGBE_AN_EVENT; ++ if (ret & XGBE_AN_PG_RCV) ++ new_state = AMD_XGBE_AN_PAGE_RECEIVED; ++ else if (ret & XGBE_AN_INC_LINK) ++ new_state = AMD_XGBE_AN_INCOMPAT_LINK; ++ else if (ret & XGBE_AN_INT_CMPLT) ++ new_state = AMD_XGBE_AN_COMPLETE; ++ ++ if (new_state != AMD_XGBE_AN_EVENT) ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ ++ return new_state; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ enum amd_xgbe_phy_rx *state; ++ int ret; ++ ++ state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state ++ : &priv->kx_state; ++ ++ switch (*state) { ++ case AMD_XGBE_RX_BPA: ++ ret = amd_xgbe_an_rx_bpa(phydev, state); ++ break; ++ ++ case AMD_XGBE_RX_XNP: ++ ret = amd_xgbe_an_rx_xnp(phydev, state); ++ break; ++ ++ default: ++ ret = AMD_XGBE_AN_ERROR; ++ } ++ ++ return ret; ++} ++ ++static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev) ++{ ++ return amd_xgbe_an_switch_mode(phydev); ++} ++ ++static void amd_xgbe_an_state_machine(struct work_struct *work) ++{ ++ struct amd_xgbe_phy_priv *priv = container_of(work, ++ struct amd_xgbe_phy_priv, ++ an_work); ++ struct phy_device *phydev = priv->phydev; ++ enum amd_xgbe_phy_an cur_state; ++ int sleep; ++ unsigned int an_supported = 0; ++ ++ while (1) { ++ mutex_lock(&priv->an_mutex); ++ ++ cur_state = priv->an_state; ++ ++ switch (priv->an_state) { ++ case AMD_XGBE_AN_START: ++ priv->an_state = amd_xgbe_an_start(phydev); ++ an_supported = 0; ++ break; ++ ++ case AMD_XGBE_AN_EVENT: ++ priv->an_state = amd_xgbe_an_event(phydev); ++ break; ++ ++ case AMD_XGBE_AN_PAGE_RECEIVED: ++ priv->an_state = amd_xgbe_an_page_received(phydev); ++ an_supported++; ++ break; ++ ++ case AMD_XGBE_AN_INCOMPAT_LINK: ++ priv->an_state = amd_xgbe_an_incompat_link(phydev); ++ break; ++ ++ case AMD_XGBE_AN_COMPLETE: ++ netdev_info(phydev->attached_dev, "%s successful\n", ++ an_supported ? "Auto negotiation" ++ : "Parallel detection"); ++ /* fall through */ ++ ++ case AMD_XGBE_AN_NO_LINK: ++ case AMD_XGBE_AN_EXIT: ++ goto exit_unlock; ++ ++ default: ++ priv->an_state = AMD_XGBE_AN_ERROR; ++ } ++ ++ if (priv->an_state == AMD_XGBE_AN_ERROR) { ++ netdev_err(phydev->attached_dev, ++ "error during auto-negotiation, state=%u\n", ++ cur_state); ++ goto exit_unlock; ++ } ++ ++ sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0; ++ ++ mutex_unlock(&priv->an_mutex); ++ ++ if (sleep) ++ usleep_range(20, 50); ++ } ++ ++exit_unlock: ++ priv->an_result = priv->an_state; ++ priv->an_state = AMD_XGBE_AN_READY; ++ ++ mutex_unlock(&priv->an_mutex); ++} ++ ++static int amd_xgbe_phy_soft_reset(struct phy_device *phydev) ++{ ++ int count, ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret |= MDIO_CTRL1_RESET; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ count = 50; ++ do { ++ msleep(20); ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ } while ((ret & MDIO_CTRL1_RESET) && --count); ++ ++ if (ret & MDIO_CTRL1_RESET) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_config_init(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ ++ /* Initialize supported features */ ++ phydev->supported = SUPPORTED_Autoneg; ++ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; ++ phydev->supported |= SUPPORTED_Backplane; ++ phydev->supported |= SUPPORTED_10000baseKR_Full | ++ SUPPORTED_10000baseR_FEC; ++ switch (priv->speed_set) { ++ case AMD_XGBE_PHY_SPEEDSET_1000_10000: ++ phydev->supported |= SUPPORTED_1000baseKX_Full; ++ break; ++ case AMD_XGBE_PHY_SPEEDSET_2500_10000: ++ phydev->supported |= SUPPORTED_2500baseX_Full; ++ break; ++ } ++ phydev->advertising = phydev->supported; ++ ++ /* Turn off and clear interrupts */ ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0); ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_setup_forced(struct phy_device *phydev) ++{ ++ int ret; ++ ++ /* Disable auto-negotiation */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); ++ if (ret < 0) ++ return ret; ++ ++ ret &= ~MDIO_AN_CTRL1_ENABLE; ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret); ++ ++ /* Validate/Set specified speed */ ++ switch (phydev->speed) { ++ case SPEED_10000: ++ ret = amd_xgbe_phy_xgmii_mode(phydev); ++ break; ++ ++ case SPEED_2500: ++ ret = amd_xgbe_phy_gmii_2500_mode(phydev); ++ break; ++ ++ case SPEED_1000: ++ ret = amd_xgbe_phy_gmii_mode(phydev); ++ break; ++ ++ default: ++ ret = -EINVAL; ++ } ++ ++ if (ret < 0) ++ return ret; ++ ++ /* Validate duplex mode */ ++ if (phydev->duplex != DUPLEX_FULL) ++ return -EINVAL; ++ ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_config_aneg(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ u32 mmd_mask = phydev->c45_ids.devices_in_package; ++ int ret; ++ ++ if (phydev->autoneg != AUTONEG_ENABLE) ++ return amd_xgbe_phy_setup_forced(phydev); ++ ++ /* Make sure we have the AN MMD present */ ++ if (!(mmd_mask & MDIO_DEVS_AN)) ++ return -EINVAL; ++ ++ /* Get the current speed mode */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (ret < 0) ++ return ret; ++ ++ /* Start/Restart the auto-negotiation state machine */ ++ mutex_lock(&priv->an_mutex); ++ priv->an_result = AMD_XGBE_AN_READY; ++ priv->an_state = AMD_XGBE_AN_START; ++ priv->kr_state = AMD_XGBE_RX_READY; ++ priv->kx_state = AMD_XGBE_RX_READY; ++ mutex_unlock(&priv->an_mutex); ++ ++ queue_work(priv->an_workqueue, &priv->an_work); ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_aneg_done(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ enum amd_xgbe_phy_an state; ++ ++ mutex_lock(&priv->an_mutex); ++ state = priv->an_result; ++ mutex_unlock(&priv->an_mutex); ++ ++ return (state == AMD_XGBE_AN_COMPLETE); ++} ++ ++static int amd_xgbe_phy_update_link(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ enum amd_xgbe_phy_an state; ++ unsigned int check_again, autoneg; ++ int ret; ++ ++ /* If we're doing auto-negotiation don't report link down */ ++ mutex_lock(&priv->an_mutex); ++ state = priv->an_state; ++ mutex_unlock(&priv->an_mutex); ++ ++ if (state != AMD_XGBE_AN_READY) { ++ phydev->link = 1; ++ return 0; ++ } ++ ++ /* Since the device can be in the wrong mode when a link is ++ * (re-)established (cable connected after the interface is ++ * up, etc.), the link status may report no link. If there ++ * is no link, try switching modes and checking the status ++ * again if auto negotiation is enabled. ++ */ ++ check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0; ++again: ++ /* Link status is latched low, so read once to clear ++ * and then read again to get current state ++ */ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1); ++ if (ret < 0) ++ return ret; ++ ++ phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0; ++ ++ if (!phydev->link) { ++ if (check_again) { ++ ret = amd_xgbe_phy_switch_mode(phydev); ++ if (ret < 0) ++ return ret; ++ check_again = 0; ++ goto again; ++ } ++ } ++ ++ autoneg = (phydev->link && !priv->link) ? 1 : 0; ++ priv->link = phydev->link; ++ if (autoneg) { ++ /* Link is (back) up, re-start auto-negotiation */ ++ ret = amd_xgbe_phy_config_aneg(phydev); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_read_status(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ u32 mmd_mask = phydev->c45_ids.devices_in_package; ++ int ret, mode, ad_ret, lp_ret; ++ ++ ret = amd_xgbe_phy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (mode < 0) ++ return mode; ++ mode &= MDIO_PCS_CTRL2_TYPE; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (!(mmd_mask & MDIO_DEVS_AN)) ++ return -EINVAL; ++ ++ if (!amd_xgbe_phy_aneg_done(phydev)) ++ return 0; ++ ++ /* Compare Advertisement and Link Partner register 1 */ ++ ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE); ++ if (ad_ret < 0) ++ return ad_ret; ++ lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA); ++ if (lp_ret < 0) ++ return lp_ret; ++ ++ ad_ret &= lp_ret; ++ phydev->pause = (ad_ret & 0x400) ? 1 : 0; ++ phydev->asym_pause = (ad_ret & 0x800) ? 1 : 0; ++ ++ /* Compare Advertisement and Link Partner register 2 */ ++ ad_ret = phy_read_mmd(phydev, MDIO_MMD_AN, ++ MDIO_AN_ADVERTISE + 1); ++ if (ad_ret < 0) ++ return ad_ret; ++ lp_ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA + 1); ++ if (lp_ret < 0) ++ return lp_ret; ++ ++ ad_ret &= lp_ret; ++ if (ad_ret & 0x80) { ++ phydev->speed = SPEED_10000; ++ if (mode != MDIO_PCS_CTRL2_10GBR) { ++ ret = amd_xgbe_phy_xgmii_mode(phydev); ++ if (ret < 0) ++ return ret; ++ } ++ } else { ++ int (*mode_fcn)(struct phy_device *); ++ ++ if (priv->speed_set == ++ AMD_XGBE_PHY_SPEEDSET_1000_10000) { ++ phydev->speed = SPEED_1000; ++ mode_fcn = amd_xgbe_phy_gmii_mode; ++ } else { ++ phydev->speed = SPEED_2500; ++ mode_fcn = amd_xgbe_phy_gmii_2500_mode; ++ } ++ ++ if (mode == MDIO_PCS_CTRL2_10GBR) { ++ ret = mode_fcn(phydev); ++ if (ret < 0) ++ return ret; ++ } ++ } ++ ++ phydev->duplex = DUPLEX_FULL; ++ } else { ++ if (mode == MDIO_PCS_CTRL2_10GBR) { ++ phydev->speed = SPEED_10000; ++ } else { ++ if (priv->speed_set == ++ AMD_XGBE_PHY_SPEEDSET_1000_10000) ++ phydev->speed = SPEED_1000; ++ else ++ phydev->speed = SPEED_2500; ++ } ++ phydev->duplex = DUPLEX_FULL; ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ } ++ ++ return 0; ++} ++ ++static int amd_xgbe_phy_suspend(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ goto unlock; ++ ++ ret |= MDIO_CTRL1_LPOWER; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} ++ ++static int amd_xgbe_phy_resume(struct phy_device *phydev) ++{ ++ int ret; ++ ++ mutex_lock(&phydev->lock); ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1); ++ if (ret < 0) ++ goto unlock; ++ ++ ret &= ~MDIO_CTRL1_LPOWER; ++ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret); ++ ++ ret = 0; ++ ++unlock: ++ mutex_unlock(&phydev->lock); ++ ++ return ret; ++} ++ ++static int amd_xgbe_phy_probe(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv; ++ struct platform_device *pdev; ++ struct device *dev; ++ char *wq_name; ++ const __be32 *property; ++ unsigned int speed_set; ++ int ret; ++ ++ if (!phydev->dev.of_node) ++ return -EINVAL; ++ ++ pdev = of_find_device_by_node(phydev->dev.of_node); ++ if (!pdev) ++ return -EINVAL; ++ dev = &pdev->dev; ++ ++ wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name); ++ if (!wq_name) { ++ ret = -ENOMEM; ++ goto err_pdev; ++ } ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ ret = -ENOMEM; ++ goto err_name; ++ } ++ ++ priv->pdev = pdev; ++ priv->dev = dev; ++ priv->phydev = phydev; ++ ++ /* Get the device mmio areas */ ++ priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res); ++ if (IS_ERR(priv->rxtx_regs)) { ++ dev_err(dev, "rxtx ioremap failed\n"); ++ ret = PTR_ERR(priv->rxtx_regs); ++ goto err_priv; ++ } ++ ++ /* All xgbe phy devices share the CMU registers so retrieve ++ * the resource and do the ioremap directly rather than ++ * the devm_ioremap_resource call ++ */ ++ priv->cmu_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ if (!priv->cmu_res) { ++ dev_err(dev, "cmu invalid resource\n"); ++ ret = -EINVAL; ++ goto err_rxtx; ++ } ++ priv->cmu_regs = devm_ioremap_nocache(dev, priv->cmu_res->start, ++ resource_size(priv->cmu_res)); ++ if (!priv->cmu_regs) { ++ dev_err(dev, "cmu ioremap failed\n"); ++ ret = -ENOMEM; ++ goto err_rxtx; ++ } ++ ++ /* Get the device serdes channel property */ ++ property = of_get_property(dev->of_node, XGBE_PHY_CHANNEL_PROPERTY, ++ NULL); ++ if (!property) { ++ dev_err(dev, "unable to obtain serdes_channel property\n"); ++ ret = -EINVAL; ++ goto err_cmu; ++ } ++ priv->serdes_channel = be32_to_cpu(*property); ++ ++ /* Get the device speed set property */ ++ speed_set = 0; ++ property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY, ++ NULL); ++ if (property) ++ speed_set = be32_to_cpu(*property); ++ ++ switch (speed_set) { ++ case 0: ++ priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000; ++ break; ++ case 1: ++ priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000; ++ break; ++ default: ++ dev_err(dev, "invalid amd,speed-set property\n"); ++ ret = -EINVAL; ++ goto err_cmu; ++ } ++ ++ priv->link = 1; ++ ++ ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2); ++ if (ret < 0) ++ goto err_cmu; ++ if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) ++ priv->mode = AMD_XGBE_MODE_KR; ++ else ++ priv->mode = AMD_XGBE_MODE_KX; ++ ++ mutex_init(&priv->an_mutex); ++ INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine); ++ priv->an_workqueue = create_singlethread_workqueue(wq_name); ++ if (!priv->an_workqueue) { ++ ret = -ENOMEM; ++ goto err_cmu; ++ } ++ ++ phydev->priv = priv; ++ ++ kfree(wq_name); ++ of_dev_put(pdev); ++ ++ return 0; ++ ++err_cmu: ++ devm_iounmap(dev, priv->cmu_regs); ++ ++err_rxtx: ++ devm_iounmap(dev, priv->rxtx_regs); ++ devm_release_mem_region(dev, priv->rxtx_res->start, ++ resource_size(priv->rxtx_res)); ++ ++err_priv: ++ devm_kfree(dev, priv); ++ ++err_name: ++ kfree(wq_name); ++ ++err_pdev: ++ of_dev_put(pdev); ++ ++ return ret; ++} ++ ++static void amd_xgbe_phy_remove(struct phy_device *phydev) ++{ ++ struct amd_xgbe_phy_priv *priv = phydev->priv; ++ struct device *dev = priv->dev; ++ ++ /* Stop any in process auto-negotiation */ ++ mutex_lock(&priv->an_mutex); ++ priv->an_state = AMD_XGBE_AN_EXIT; ++ mutex_unlock(&priv->an_mutex); ++ ++ flush_workqueue(priv->an_workqueue); ++ destroy_workqueue(priv->an_workqueue); ++ ++ devm_iounmap(dev, priv->cmu_regs); ++ ++ devm_iounmap(dev, priv->rxtx_regs); ++ devm_release_mem_region(dev, priv->rxtx_res->start, ++ resource_size(priv->rxtx_res)); ++ ++ devm_kfree(dev, priv); ++} ++ ++static int amd_xgbe_match_phy_device(struct phy_device *phydev) ++{ ++ return phydev->c45_ids.device_ids[MDIO_MMD_PCS] == XGBE_PHY_ID; ++} ++ ++static struct phy_driver amd_xgbe_phy_driver[] = { ++ { ++ .phy_id = XGBE_PHY_ID, ++ .phy_id_mask = XGBE_PHY_MASK, ++ .name = "AMD XGBE PHY", ++ .features = 0, ++ .probe = amd_xgbe_phy_probe, ++ .remove = amd_xgbe_phy_remove, ++ .soft_reset = amd_xgbe_phy_soft_reset, ++ .config_init = amd_xgbe_phy_config_init, ++ .suspend = amd_xgbe_phy_suspend, ++ .resume = amd_xgbe_phy_resume, ++ .config_aneg = amd_xgbe_phy_config_aneg, ++ .aneg_done = amd_xgbe_phy_aneg_done, ++ .read_status = amd_xgbe_phy_read_status, ++ .match_phy_device = amd_xgbe_match_phy_device, ++ .driver = { ++ .owner = THIS_MODULE, ++ }, ++ }, ++}; ++ ++static int __init amd_xgbe_phy_init(void) ++{ ++ return phy_drivers_register(amd_xgbe_phy_driver, ++ ARRAY_SIZE(amd_xgbe_phy_driver)); ++} ++ ++static void __exit amd_xgbe_phy_exit(void) ++{ ++ phy_drivers_unregister(amd_xgbe_phy_driver, ++ ARRAY_SIZE(amd_xgbe_phy_driver)); ++} ++ ++module_init(amd_xgbe_phy_init); ++module_exit(amd_xgbe_phy_exit); ++ ++static struct mdio_device_id __maybe_unused amd_xgbe_phy_ids[] = { ++ { XGBE_PHY_ID, XGBE_PHY_MASK }, ++ { } ++}; ++MODULE_DEVICE_TABLE(mdio, amd_xgbe_phy_ids); +-- +2.1.0 + diff --git a/patches.arch/arm64-0010-KVM-ARM-Hack-to-enable-VGIC-mapping-on-64k-PAGE_SIZE.patch b/patches.arch/arm64-0010-KVM-ARM-Hack-to-enable-VGIC-mapping-on-64k-PAGE_SIZE.patch new file mode 100644 index 0000000..e480a90 --- /dev/null +++ b/patches.arch/arm64-0010-KVM-ARM-Hack-to-enable-VGIC-mapping-on-64k-PAGE_SIZE.patch @@ -0,0 +1,103 @@ +From d7c519b3f27348a66d83b8ed047aac0a5a8c4d69 Mon Sep 17 00:00:00 2001 +From: Alexander Graf <agraf@suse.de> +Date: Wed, 22 Oct 2014 13:01:55 +0200 +Subject: [PATCH 10/38] KVM: ARM: Hack to enable VGIC mapping on 64k PAGE_SIZE + kernels +Patch-mainline: No +References: bnc#902633 + +Originally commit 63afbe7a0ac disabled mapping of unaligned VGIC regions +on 64k PAGE_SIZE enabled kernels. However, we want to be able to support +broken hardware, even if it allows guests to crash the hosts. + +Hack things up for now to enable the map again. Also add a sanity check +to make sure that normal user space doesn't blow up hosts unknowingly. + +To allow guests to find out where to map the vgic, expose the offset to +user space via the device api. + +Do not use KVM on broken hosts unless you know what you're doing! + +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm/include/uapi/asm/kvm.h | 1 + + arch/arm64/include/uapi/asm/kvm.h | 1 + + virt/kvm/arm/vgic.c | 16 ++++++++++++++++ + 3 files changed, 18 insertions(+) + +diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h +index e6ebdd3..e10db8e 100644 +--- a/arch/arm/include/uapi/asm/kvm.h ++++ b/arch/arm/include/uapi/asm/kvm.h +@@ -79,6 +79,7 @@ struct kvm_regs { + /* Supported VGIC address types */ + #define KVM_VGIC_V2_ADDR_TYPE_DIST 0 + #define KVM_VGIC_V2_ADDR_TYPE_CPU 1 ++#define KVM_VGIC_V2_PAGE_OFFSET 0xfff2 + + #define KVM_VGIC_V2_DIST_SIZE 0x1000 + #define KVM_VGIC_V2_CPU_SIZE 0x2000 +diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h +index e633ff8..e923288 100644 +--- a/arch/arm64/include/uapi/asm/kvm.h ++++ b/arch/arm64/include/uapi/asm/kvm.h +@@ -73,6 +73,7 @@ struct kvm_regs { + /* Supported VGIC address types */ + #define KVM_VGIC_V2_ADDR_TYPE_DIST 0 + #define KVM_VGIC_V2_ADDR_TYPE_CPU 1 ++#define KVM_VGIC_V2_PAGE_OFFSET 0xfff2 + + #define KVM_VGIC_V2_DIST_SIZE 0x1000 + #define KVM_VGIC_V2_CPU_SIZE 0x2000 +diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c +index 718e8ca..dfbd586 100644 +--- a/virt/kvm/arm/vgic.c ++++ b/virt/kvm/arm/vgic.c +@@ -1534,6 +1534,7 @@ int kvm_vgic_hyp_init(void) + goto out_unmap; + } + ++#if 0 + if (!PAGE_ALIGNED(vcpu_res.start)) { + kvm_err("GICV physical address 0x%llx not page aligned\n", + (unsigned long long)vcpu_res.start); +@@ -1548,6 +1549,7 @@ int kvm_vgic_hyp_init(void) + ret = -ENXIO; + goto out_unmap; + } ++#endif + + vgic_vcpu_base = vcpu_res.start; + +@@ -1594,6 +1596,13 @@ int kvm_vgic_init(struct kvm *kvm) + goto out; + } + ++ if ((kvm->arch.vgic.vgic_cpu_base & ~PAGE_MASK) != ++ (vgic_vcpu_base & ~PAGE_MASK)) { ++ kvm_err("Need to align vgic identically in guest and host\n"); ++ ret = -ENXIO; ++ goto out; ++ } ++ + ret = kvm_phys_addr_ioremap(kvm, kvm->arch.vgic.vgic_cpu_base, + vgic_vcpu_base, KVM_VGIC_V2_CPU_SIZE); + if (ret) { +@@ -1729,6 +1738,13 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) + *addr = vgic->vgic_cpu_base; + } + break; ++ case KVM_VGIC_V2_PAGE_OFFSET: ++ if (write) { ++ r = -ENODEV; ++ } else { ++ *addr = vgic_vcpu_base & ~PAGE_MASK; ++ } ++ break; + default: + r = -ENODEV; + } +-- +2.1.0 + diff --git a/patches.arch/arm64-0011-ARM-Add-APM-Mustang-network-driver.patch b/patches.arch/arm64-0011-ARM-Add-APM-Mustang-network-driver.patch new file mode 100644 index 0000000..1c52f2c --- /dev/null +++ b/patches.arch/arm64-0011-ARM-Add-APM-Mustang-network-driver.patch @@ -0,0 +1,3683 @@ +From e3370b1530dc2f65f05b562f84a86196c4f88718 Mon Sep 17 00:00:00 2001 +From: Alexander Graf <agraf@suse.de> +Date: Wed, 22 Oct 2014 15:14:20 +0200 +Subject: [PATCH 11/38] ARM: Add APM Mustang network driver +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The APM network driver came too late for 3.16, but we need to be able +to support it to make use of Mustang machines. This is a backport of +the 3.18-rc1 state of said driver. + +While at it, also add the respective device tree nodes. + +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/boot/dts/apm-mustang.dts | 20 + + arch/arm64/boot/dts/apm-storm.dtsi | 245 ++++- + drivers/net/ethernet/Kconfig | 1 + + drivers/net/ethernet/Makefile | 1 + + drivers/net/ethernet/apm/Kconfig | 1 + + drivers/net/ethernet/apm/Makefile | 5 + + drivers/net/ethernet/apm/xgene/Kconfig | 10 + + drivers/net/ethernet/apm/xgene/Makefile | 7 + + .../net/ethernet/apm/xgene/xgene_enet_ethtool.c | 150 +++ + drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 743 +++++++++++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 325 +++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 1006 ++++++++++++++++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 163 ++++ + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c | 389 ++++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h | 41 + + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c | 332 +++++++ + drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h | 53 ++ + 17 files changed, 3489 insertions(+), 3 deletions(-) + create mode 100644 drivers/net/ethernet/apm/Kconfig + create mode 100644 drivers/net/ethernet/apm/Makefile + create mode 100644 drivers/net/ethernet/apm/xgene/Kconfig + create mode 100644 drivers/net/ethernet/apm/xgene/Makefile + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_hw.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_hw.h + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_main.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_main.h + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c + create mode 100644 drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h + +diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts +index 6541962..2e25de0 100644 +--- a/arch/arm64/boot/dts/apm-mustang.dts ++++ b/arch/arm64/boot/dts/apm-mustang.dts +@@ -25,6 +25,26 @@ + }; + }; + ++&pcie0clk { ++ status = "ok"; ++}; ++ ++&pcie0 { ++ status = "ok"; ++}; ++ + &serial0 { + status = "ok"; + }; ++ ++&menet { ++ status = "ok"; ++}; ++ ++&sgenet0 { ++ status = "ok"; ++}; ++ ++&xgenet { ++ status = "ok"; ++}; +diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi +index 40aa96c..cea114b 100644 +--- a/arch/arm64/boot/dts/apm-storm.dtsi ++++ b/arch/arm64/boot/dts/apm-storm.dtsi +@@ -167,14 +167,33 @@ + clock-output-names = "ethclk"; + }; + +- eth8clk: eth8clk { ++ menetclk: menetclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <ðclk 0>; +- clock-names = "eth8clk"; + reg = <0x0 0x1702C000 0x0 0x1000>; + reg-names = "csr-reg"; +- clock-output-names = "eth8clk"; ++ clock-output-names = "menetclk"; ++ }; ++ ++ sge0clk: sge0clk@1f21c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f21c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ csr-mask = <0x3>; ++ clock-output-names = "sge0clk"; ++ }; ++ ++ xge0clk: xge0clk@1f61c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f61c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ csr-mask = <0x3>; ++ clock-output-names = "xge0clk"; + }; + + sataphy1clk: sataphy1clk@1f21c000 { +@@ -270,6 +289,171 @@ + enable-mask = <0x2>; + clock-output-names = "rtcclk"; + }; ++ ++ pcie0clk: pcie0clk@1f2bc000 { ++ status = "disabled"; ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f2bc000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "pcie0clk"; ++ }; ++ ++ pcie1clk: pcie1clk@1f2cc000 { ++ status = "disabled"; ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f2cc000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "pcie1clk"; ++ }; ++ ++ pcie2clk: pcie2clk@1f2dc000 { ++ status = "disabled"; ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f2dc000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "pcie2clk"; ++ }; ++ ++ pcie3clk: pcie3clk@1f50c000 { ++ status = "disabled"; ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f50c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "pcie3clk"; ++ }; ++ ++ pcie4clk: pcie4clk@1f51c000 { ++ status = "disabled"; ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f51c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "pcie4clk"; ++ }; ++ }; ++ ++ pcie0: pcie@1f2b0000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ ++ 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */ ++ 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; ++ dma-coherent; ++ clocks = <&pcie0clk 0>; ++ }; ++ ++ pcie1: pcie@1f2c0000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */ ++ 0xd0 0xd0000000 0x0 0x00040000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x0 0x00000000 0xd0 0x10000000 0x00 0x00010000 /* io */ ++ 0x02000000 0x0 0x80000000 0xd1 0x80000000 0x00 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>; ++ dma-coherent; ++ clocks = <&pcie1clk 0>; ++ }; ++ ++ pcie2: pcie@1f2d0000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f2d0000 0x0 0x00010000 /* Controller registers */ ++ 0x90 0xd0000000 0x0 0x00040000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x0 0x00000000 0x90 0x10000000 0x0 0x00010000 /* io */ ++ 0x02000000 0x0 0x80000000 0x91 0x80000000 0x0 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>; ++ dma-coherent; ++ clocks = <&pcie2clk 0>; ++ }; ++ ++ pcie3: pcie@1f500000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f500000 0x0 0x00010000 /* Controller registers */ ++ 0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x0 0x00000000 0xa0 0x10000000 0x0 0x00010000 /* io */ ++ 0x02000000 0x0 0x80000000 0xa1 0x80000000 0x0 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>; ++ dma-coherent; ++ clocks = <&pcie3clk 0>; ++ }; ++ ++ pcie4: pcie@1f510000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f510000 0x0 0x00010000 /* Controller registers */ ++ 0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x0 0x00000000 0xc0 0x10000000 0x0 0x00010000 /* io */ ++ 0x02000000 0x0 0x80000000 0xc1 0x80000000 0x0 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>; ++ dma-coherent; ++ clocks = <&pcie4clk 0>; + }; + + serial0: serial@1c020000 { +@@ -397,5 +581,60 @@ + #clock-cells = <1>; + clocks = <&rtcclk 0>; + }; ++ ++ menet: ethernet@17020000 { ++ compatible = "apm,xgene-enet"; ++ status = "disabled"; ++ reg = <0x0 0x17020000 0x0 0xd100>, ++ <0x0 0X17030000 0x0 0X400>, ++ <0x0 0X10000000 0x0 0X200>; ++ reg-names = "enet_csr", "ring_csr", "ring_cmd"; ++ interrupts = <0x0 0x3c 0x4>; ++ dma-coherent; ++ clocks = <&menetclk 0>; ++ /* mac address will be overwritten by the bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ phy-connection-type = "rgmii"; ++ phy-handle = <&menetphy>; ++ mdio { ++ compatible = "apm,xgene-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ menetphy: menetphy@3 { ++ compatible = "ethernet-phy-id001c.c915"; ++ reg = <0x3>; ++ }; ++ ++ }; ++ }; ++ ++ sgenet0: ethernet@1f210000 { ++ compatible = "apm,xgene-enet"; ++ status = "disabled"; ++ reg = <0x0 0x1f210000 0x0 0x10000>, ++ <0x0 0x1f200000 0x0 0X10000>, ++ <0x0 0x1B000000 0x0 0X20000>; ++ reg-names = "enet_csr", "ring_csr", "ring_cmd"; ++ interrupts = <0x0 0xA0 0x4>; ++ dma-coherent; ++ clocks = <&sge0clk 0>; ++ local-mac-address = [00 00 00 00 00 00]; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ xgenet: ethernet@1f610000 { ++ compatible = "apm,xgene-enet"; ++ status = "disabled"; ++ reg = <0x0 0x1f610000 0x0 0xd100>, ++ <0x0 0x1f600000 0x0 0X400>, ++ <0x0 0x18000000 0x0 0X200>; ++ reg-names = "enet_csr", "ring_csr", "ring_cmd"; ++ interrupts = <0x0 0x60 0x4>; ++ dma-coherent; ++ clocks = <&xge0clk 0>; ++ /* mac address will be overwritten by the bootloader */ ++ local-mac-address = [00 00 00 00 00 00]; ++ phy-connection-type = "xgmii"; ++ }; + }; + }; +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index edb7186..dc7406c 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -24,6 +24,7 @@ source "drivers/net/ethernet/allwinner/Kconfig" + source "drivers/net/ethernet/alteon/Kconfig" + source "drivers/net/ethernet/altera/Kconfig" + source "drivers/net/ethernet/amd/Kconfig" ++source "drivers/net/ethernet/apm/Kconfig" + source "drivers/net/ethernet/apple/Kconfig" + source "drivers/net/ethernet/arc/Kconfig" + source "drivers/net/ethernet/atheros/Kconfig" +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index 58de333..224a018 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/ + obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ + obj-$(CONFIG_ALTERA_TSE) += altera/ + obj-$(CONFIG_NET_VENDOR_AMD) += amd/ ++obj-$(CONFIG_NET_XGENE) += apm/ + obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ + obj-$(CONFIG_NET_VENDOR_ARC) += arc/ + obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ +diff --git a/drivers/net/ethernet/apm/Kconfig b/drivers/net/ethernet/apm/Kconfig +new file mode 100644 +index 0000000..ec63d70 +--- /dev/null ++++ b/drivers/net/ethernet/apm/Kconfig +@@ -0,0 +1 @@ ++source "drivers/net/ethernet/apm/xgene/Kconfig" +diff --git a/drivers/net/ethernet/apm/Makefile b/drivers/net/ethernet/apm/Makefile +new file mode 100644 +index 0000000..65ce32a +--- /dev/null ++++ b/drivers/net/ethernet/apm/Makefile +@@ -0,0 +1,5 @@ ++# ++# Makefile for APM X-GENE Ethernet driver. ++# ++ ++obj-$(CONFIG_NET_XGENE) += xgene/ +diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig +new file mode 100644 +index 0000000..f4054d24 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/Kconfig +@@ -0,0 +1,10 @@ ++config NET_XGENE ++ tristate "APM X-Gene SoC Ethernet Driver" ++ depends on HAS_DMA ++ select PHYLIB ++ help ++ This is the Ethernet driver for the on-chip ethernet interface on the ++ APM X-Gene SoC. ++ ++ To compile this driver as a module, choose M here. This module will ++ be called xgene_enet. +diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile +new file mode 100644 +index 0000000..68be5655 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for APM X-Gene Ethernet Driver. ++# ++ ++xgene-enet-objs := xgene_enet_hw.o xgene_enet_sgmac.o xgene_enet_xgmac.o \ ++ xgene_enet_main.o xgene_enet_ethtool.o ++obj-$(CONFIG_NET_XGENE) += xgene-enet.o +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +new file mode 100644 +index 0000000..416d6eb +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c +@@ -0,0 +1,150 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <linux/ethtool.h> ++#include "xgene_enet_main.h" ++ ++struct xgene_gstrings_stats { ++ char name[ETH_GSTRING_LEN]; ++ int offset; ++}; ++ ++#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } ++ ++static const struct xgene_gstrings_stats gstrings_stats[] = { ++ XGENE_STAT(rx_packets), ++ XGENE_STAT(tx_packets), ++ XGENE_STAT(rx_bytes), ++ XGENE_STAT(tx_bytes), ++ XGENE_STAT(rx_errors), ++ XGENE_STAT(tx_errors), ++ XGENE_STAT(rx_length_errors), ++ XGENE_STAT(rx_crc_errors), ++ XGENE_STAT(rx_frame_errors), ++ XGENE_STAT(rx_fifo_errors) ++}; ++ ++#define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) ++ ++static void xgene_get_drvinfo(struct net_device *ndev, ++ struct ethtool_drvinfo *info) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct platform_device *pdev = pdata->pdev; ++ ++ strcpy(info->driver, "xgene_enet"); ++ strcpy(info->version, XGENE_DRV_VERSION); ++ snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); ++ sprintf(info->bus_info, "%s", pdev->name); ++} ++ ++static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct phy_device *phydev = pdata->phy_dev; ++ ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ if (phydev == NULL) ++ return -ENODEV; ++ ++ return phy_ethtool_gset(phydev, cmd); ++ } else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { ++ cmd->supported = SUPPORTED_1000baseT_Full | ++ SUPPORTED_Autoneg | SUPPORTED_MII; ++ cmd->advertising = cmd->supported; ++ ethtool_cmd_speed_set(cmd, SPEED_1000); ++ cmd->duplex = DUPLEX_FULL; ++ cmd->port = PORT_MII; ++ cmd->transceiver = XCVR_INTERNAL; ++ cmd->autoneg = AUTONEG_ENABLE; ++ } else { ++ cmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE; ++ cmd->advertising = cmd->supported; ++ ethtool_cmd_speed_set(cmd, SPEED_10000); ++ cmd->duplex = DUPLEX_FULL; ++ cmd->port = PORT_FIBRE; ++ cmd->transceiver = XCVR_INTERNAL; ++ cmd->autoneg = AUTONEG_DISABLE; ++ } ++ ++ return 0; ++} ++ ++static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct phy_device *phydev = pdata->phy_dev; ++ ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) { ++ if (phydev == NULL) ++ return -ENODEV; ++ ++ return phy_ethtool_sset(phydev, cmd); ++ } ++ ++ return -EINVAL; ++} ++ ++static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) ++{ ++ int i; ++ u8 *p = data; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ for (i = 0; i < XGENE_STATS_LEN; i++) { ++ memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++} ++ ++static int xgene_get_sset_count(struct net_device *ndev, int sset) ++{ ++ if (sset != ETH_SS_STATS) ++ return -EINVAL; ++ ++ return XGENE_STATS_LEN; ++} ++ ++static void xgene_get_ethtool_stats(struct net_device *ndev, ++ struct ethtool_stats *dummy, ++ u64 *data) ++{ ++ void *pdata = netdev_priv(ndev); ++ int i; ++ ++ for (i = 0; i < XGENE_STATS_LEN; i++) ++ *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); ++} ++ ++static const struct ethtool_ops xgene_ethtool_ops = { ++ .get_drvinfo = xgene_get_drvinfo, ++ .get_settings = xgene_get_settings, ++ .set_settings = xgene_set_settings, ++ .get_link = ethtool_op_get_link, ++ .get_strings = xgene_get_strings, ++ .get_sset_count = xgene_get_sset_count, ++ .get_ethtool_stats = xgene_get_ethtool_stats ++}; ++ ++void xgene_enet_set_ethtool_ops(struct net_device *ndev) ++{ ++ ndev->ethtool_ops = &xgene_ethtool_ops; ++} +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +new file mode 100644 +index 0000000..63ea194 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +@@ -0,0 +1,743 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Ravi Patel <rapatel@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++ ++static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring) ++{ ++ u32 *ring_cfg = ring->state; ++ u64 addr = ring->dma; ++ enum xgene_enet_ring_cfgsize cfgsize = ring->cfgsize; ++ ++ ring_cfg[4] |= (1 << SELTHRSH_POS) & ++ CREATE_MASK(SELTHRSH_POS, SELTHRSH_LEN); ++ ring_cfg[3] |= ACCEPTLERR; ++ ring_cfg[2] |= QCOHERENT; ++ ++ addr >>= 8; ++ ring_cfg[2] |= (addr << RINGADDRL_POS) & ++ CREATE_MASK_ULL(RINGADDRL_POS, RINGADDRL_LEN); ++ addr >>= RINGADDRL_LEN; ++ ring_cfg[3] |= addr & CREATE_MASK_ULL(RINGADDRH_POS, RINGADDRH_LEN); ++ ring_cfg[3] |= ((u32)cfgsize << RINGSIZE_POS) & ++ CREATE_MASK(RINGSIZE_POS, RINGSIZE_LEN); ++} ++ ++static void xgene_enet_ring_set_type(struct xgene_enet_desc_ring *ring) ++{ ++ u32 *ring_cfg = ring->state; ++ bool is_bufpool; ++ u32 val; ++ ++ is_bufpool = xgene_enet_is_bufpool(ring->id); ++ val = (is_bufpool) ? RING_BUFPOOL : RING_REGULAR; ++ ring_cfg[4] |= (val << RINGTYPE_POS) & ++ CREATE_MASK(RINGTYPE_POS, RINGTYPE_LEN); ++ ++ if (is_bufpool) { ++ ring_cfg[3] |= (BUFPOOL_MODE << RINGMODE_POS) & ++ CREATE_MASK(RINGMODE_POS, RINGMODE_LEN); ++ } ++} ++ ++static void xgene_enet_ring_set_recombbuf(struct xgene_enet_desc_ring *ring) ++{ ++ u32 *ring_cfg = ring->state; ++ ++ ring_cfg[3] |= RECOMBBUF; ++ ring_cfg[3] |= (0xf << RECOMTIMEOUTL_POS) & ++ CREATE_MASK(RECOMTIMEOUTL_POS, RECOMTIMEOUTL_LEN); ++ ring_cfg[4] |= 0x7 & CREATE_MASK(RECOMTIMEOUTH_POS, RECOMTIMEOUTH_LEN); ++} ++ ++static void xgene_enet_ring_wr32(struct xgene_enet_desc_ring *ring, ++ u32 offset, u32 data) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); ++ ++ iowrite32(data, pdata->ring_csr_addr + offset); ++} ++ ++static void xgene_enet_ring_rd32(struct xgene_enet_desc_ring *ring, ++ u32 offset, u32 *data) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); ++ ++ *data = ioread32(pdata->ring_csr_addr + offset); ++} ++ ++static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring) ++{ ++ int i; ++ ++ xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num); ++ for (i = 0; i < NUM_RING_CONFIG; i++) { ++ xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4), ++ ring->state[i]); ++ } ++} ++ ++static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring) ++{ ++ memset(ring->state, 0, sizeof(u32) * NUM_RING_CONFIG); ++ xgene_enet_write_ring_state(ring); ++} ++ ++static void xgene_enet_set_ring_state(struct xgene_enet_desc_ring *ring) ++{ ++ xgene_enet_ring_set_type(ring); ++ ++ if (xgene_enet_ring_owner(ring->id) == RING_OWNER_ETH0) ++ xgene_enet_ring_set_recombbuf(ring); ++ ++ xgene_enet_ring_init(ring); ++ xgene_enet_write_ring_state(ring); ++} ++ ++static void xgene_enet_set_ring_id(struct xgene_enet_desc_ring *ring) ++{ ++ u32 ring_id_val, ring_id_buf; ++ bool is_bufpool; ++ ++ is_bufpool = xgene_enet_is_bufpool(ring->id); ++ ++ ring_id_val = ring->id & GENMASK(9, 0); ++ ring_id_val |= OVERWRITE; ++ ++ ring_id_buf = (ring->num << 9) & GENMASK(18, 9); ++ ring_id_buf |= PREFETCH_BUF_EN; ++ if (is_bufpool) ++ ring_id_buf |= IS_BUFFER_POOL; ++ ++ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id_val); ++ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, ring_id_buf); ++} ++ ++static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring) ++{ ++ u32 ring_id; ++ ++ ring_id = ring->id | OVERWRITE; ++ xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id); ++ xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0); ++} ++ ++struct xgene_enet_desc_ring *xgene_enet_setup_ring( ++ struct xgene_enet_desc_ring *ring) ++{ ++ u32 size = ring->size; ++ u32 i, data; ++ bool is_bufpool; ++ ++ xgene_enet_clr_ring_state(ring); ++ xgene_enet_set_ring_state(ring); ++ xgene_enet_set_ring_id(ring); ++ ++ ring->slots = xgene_enet_get_numslots(ring->id, size); ++ ++ is_bufpool = xgene_enet_is_bufpool(ring->id); ++ if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU) ++ return ring; ++ ++ for (i = 0; i < ring->slots; i++) ++ xgene_enet_mark_desc_slot_empty(&ring->raw_desc[i]); ++ ++ xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data); ++ data |= BIT(31 - xgene_enet_ring_bufnum(ring->id)); ++ xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data); ++ ++ return ring; ++} ++ ++void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring) ++{ ++ u32 data; ++ bool is_bufpool; ++ ++ is_bufpool = xgene_enet_is_bufpool(ring->id); ++ if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU) ++ goto out; ++ ++ xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data); ++ data &= ~BIT(31 - xgene_enet_ring_bufnum(ring->id)); ++ xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data); ++ ++out: ++ xgene_enet_clr_desc_ring_id(ring); ++ xgene_enet_clr_ring_state(ring); ++} ++ ++void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, ++ struct xgene_enet_pdata *pdata, ++ enum xgene_enet_err_code status) ++{ ++ struct rtnl_link_stats64 *stats = &pdata->stats; ++ ++ switch (status) { ++ case INGRESS_CRC: ++ stats->rx_crc_errors++; ++ break; ++ case INGRESS_CHECKSUM: ++ case INGRESS_CHECKSUM_COMPUTE: ++ stats->rx_errors++; ++ break; ++ case INGRESS_TRUNC_FRAME: ++ stats->rx_frame_errors++; ++ break; ++ case INGRESS_PKT_LEN: ++ stats->rx_length_errors++; ++ break; ++ case INGRESS_PKT_UNDER: ++ stats->rx_frame_errors++; ++ break; ++ case INGRESS_FIFO_OVERRUN: ++ stats->rx_fifo_errors++; ++ break; ++ default: ++ break; ++ } ++} ++ ++static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_ring_if_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->mcx_mac_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 wr_addr, u32 wr_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(wr_addr, addr); ++ iowrite32(wr_data, wr); ++ iowrite32(XGENE_ENET_WR_CMD, cmd); ++ ++ /* wait for write command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata, ++ u32 wr_addr, u32 wr_data) ++{ ++ void __iomem *addr, *wr, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) ++ netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", ++ wr_addr); ++} ++ ++static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->mcx_mac_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 rd_addr, u32 *rd_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(rd_addr, addr); ++ iowrite32(XGENE_ENET_RD_CMD, cmd); ++ ++ /* wait for read command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ *rd_data = ioread32(rd); ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, ++ u32 rd_addr, u32 *rd_data) ++{ ++ void __iomem *addr, *rd, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) ++ netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", ++ rd_addr); ++} ++ ++static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id, ++ u32 reg, u16 data) ++{ ++ u32 addr = 0, wr_data = 0; ++ u32 done; ++ u8 wait = 10; ++ ++ PHY_ADDR_SET(&addr, phy_id); ++ REG_ADDR_SET(&addr, reg); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); ++ ++ PHY_CONTROL_SET(&wr_data, data); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data); ++ do { ++ usleep_range(5, 10); ++ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); ++ } while ((done & BUSY_MASK) && wait--); ++ ++ if (done & BUSY_MASK) { ++ netdev_err(pdata->ndev, "MII_MGMT write failed\n"); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, ++ u8 phy_id, u32 reg) ++{ ++ u32 addr = 0; ++ u32 data, done; ++ u8 wait = 10; ++ ++ PHY_ADDR_SET(&addr, phy_id); ++ REG_ADDR_SET(&addr, reg); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); ++ do { ++ usleep_range(5, 10); ++ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); ++ } while ((done & BUSY_MASK) && wait--); ++ ++ if (done & BUSY_MASK) { ++ netdev_err(pdata->ndev, "MII_MGMT read failed\n"); ++ return -EBUSY; ++ } ++ ++ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); ++ ++ return data; ++} ++ ++static void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) ++{ ++ u32 addr0, addr1; ++ u8 *dev_addr = pdata->ndev->dev_addr; ++ ++ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | ++ (dev_addr[1] << 8) | dev_addr[0]; ++ addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); ++ ++ xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0); ++ xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1); ++} ++ ++static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) ++{ ++ struct net_device *ndev = pdata->ndev; ++ u32 data; ++ u8 wait = 10; ++ ++ xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); ++ do { ++ usleep_range(100, 110); ++ xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); ++ } while ((data != 0xffffffff) && wait--); ++ ++ if (data != 0xffffffff) { ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void xgene_gmac_reset(struct xgene_enet_pdata *pdata) ++{ ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); ++} ++ ++static void xgene_gmac_init(struct xgene_enet_pdata *pdata) ++{ ++ u32 value, mc2; ++ u32 intf_ctl, rgmii; ++ u32 icm0, icm2; ++ ++ xgene_gmac_reset(pdata); ++ ++ xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); ++ xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); ++ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2); ++ xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); ++ xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); ++ ++ switch (pdata->phy_speed) { ++ case SPEED_10: ++ ENET_INTERFACE_MODE2_SET(&mc2, 1); ++ CFG_MACMODE_SET(&icm0, 0); ++ CFG_WAITASYNCRD_SET(&icm2, 500); ++ rgmii &= ~CFG_SPEED_1250; ++ break; ++ case SPEED_100: ++ ENET_INTERFACE_MODE2_SET(&mc2, 1); ++ intf_ctl |= ENET_LHD_MODE; ++ CFG_MACMODE_SET(&icm0, 1); ++ CFG_WAITASYNCRD_SET(&icm2, 80); ++ rgmii &= ~CFG_SPEED_1250; ++ break; ++ default: ++ ENET_INTERFACE_MODE2_SET(&mc2, 2); ++ intf_ctl |= ENET_GHD_MODE; ++ CFG_TXCLK_MUXSEL0_SET(&rgmii, 4); ++ xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value); ++ value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; ++ xgene_enet_wr_csr(pdata, DEBUG_REG_ADDR, value); ++ break; ++ } ++ ++ mc2 |= FULL_DUPLEX2; ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); ++ xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); ++ ++ xgene_gmac_set_mac_addr(pdata); ++ ++ /* Adjust MDC clock frequency */ ++ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value); ++ MGMT_CLOCK_SEL_SET(&value, 7); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value); ++ ++ /* Enable drop if bufpool not available */ ++ xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value); ++ value |= CFG_RSIF_FPBUFF_TIMEOUT_EN; ++ xgene_enet_wr_csr(pdata, RSIF_CONFIG_REG_ADDR, value); ++ ++ /* Rtype should be copied from FP */ ++ xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); ++ xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); ++ ++ /* Rx-Tx traffic resume */ ++ xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); ++ ++ xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); ++ xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); ++ ++ xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); ++ value &= ~TX_DV_GATE_EN0; ++ value &= ~RX_DV_GATE_EN0; ++ value |= RESUME_RX0; ++ xgene_enet_wr_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, value); ++ ++ xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX); ++} ++ ++static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) ++{ ++ u32 val = 0xffffffff; ++ ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, val); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, val); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, val); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val); ++} ++ ++static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id) ++{ ++ u32 cb; ++ u32 fpsel; ++ ++ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; ++ ++ xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb); ++ cb |= CFG_CLE_BYPASS_EN0; ++ CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); ++ xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb); ++ ++ xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb); ++ CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); ++ CFG_CLE_FPSEL0_SET(&cb, fpsel); ++ xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb); ++} ++ ++static void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); ++} ++ ++static void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); ++} ++ ++static void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); ++} ++ ++static void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); ++ xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); ++} ++ ++static void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++{ ++ u32 val; ++ ++ clk_prepare_enable(pdata->clk); ++ clk_disable_unprepare(pdata->clk); ++ clk_prepare_enable(pdata->clk); ++ xgene_enet_ecc_init(pdata); ++ xgene_enet_config_ring_if_assoc(pdata); ++ ++ /* Enable auto-incr for scanning */ ++ xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); ++ val |= SCAN_AUTO_INCR; ++ MGMT_CLOCK_SEL_SET(&val, 1); ++ xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); ++} ++ ++static void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) ++{ ++ clk_disable_unprepare(pdata->clk); ++} ++ ++static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) ++{ ++ struct xgene_enet_pdata *pdata = bus->priv; ++ u32 val; ++ ++ val = xgene_mii_phy_read(pdata, mii_id, regnum); ++ netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n", ++ mii_id, regnum, val); ++ ++ return val; ++} ++ ++static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, ++ u16 val) ++{ ++ struct xgene_enet_pdata *pdata = bus->priv; ++ ++ netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n", ++ mii_id, regnum, val); ++ return xgene_mii_phy_write(pdata, mii_id, regnum, val); ++} ++ ++static void xgene_enet_adjust_link(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct phy_device *phydev = pdata->phy_dev; ++ ++ if (phydev->link) { ++ if (pdata->phy_speed != phydev->speed) { ++ pdata->phy_speed = phydev->speed; ++ xgene_gmac_init(pdata); ++ xgene_gmac_rx_enable(pdata); ++ xgene_gmac_tx_enable(pdata); ++ phy_print_status(phydev); ++ } ++ } else { ++ xgene_gmac_rx_disable(pdata); ++ xgene_gmac_tx_disable(pdata); ++ pdata->phy_speed = SPEED_UNKNOWN; ++ phy_print_status(phydev); ++ } ++} ++ ++static int xgene_enet_phy_connect(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct device_node *phy_np; ++ struct phy_device *phy_dev; ++ struct device *dev = &pdata->pdev->dev; ++ ++ phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); ++ if (!phy_np) { ++ netdev_dbg(ndev, "No phy-handle found\n"); ++ return -ENODEV; ++ } ++ ++ phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, ++ 0, pdata->phy_mode); ++ if (!phy_dev) { ++ netdev_err(ndev, "Could not connect to PHY\n"); ++ return -ENODEV; ++ } ++ ++ pdata->phy_speed = SPEED_UNKNOWN; ++ phy_dev->supported &= ~SUPPORTED_10baseT_Half & ++ ~SUPPORTED_100baseT_Half & ++ ~SUPPORTED_1000baseT_Half; ++ phy_dev->advertising = phy_dev->supported; ++ pdata->phy_dev = phy_dev; ++ ++ return 0; ++} ++ ++int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) ++{ ++ struct net_device *ndev = pdata->ndev; ++ struct device *dev = &pdata->pdev->dev; ++ struct device_node *child_np; ++ struct device_node *mdio_np = NULL; ++ struct mii_bus *mdio_bus; ++ int ret; ++ ++ for_each_child_of_node(dev->of_node, child_np) { ++ if (of_device_is_compatible(child_np, "apm,xgene-mdio")) { ++ mdio_np = child_np; ++ break; ++ } ++ } ++ ++ if (!mdio_np) { ++ netdev_dbg(ndev, "No mdio node in the dts\n"); ++ return -ENXIO; ++ } ++ ++ mdio_bus = mdiobus_alloc(); ++ if (!mdio_bus) ++ return -ENOMEM; ++ ++ mdio_bus->name = "APM X-Gene MDIO bus"; ++ mdio_bus->read = xgene_enet_mdio_read; ++ mdio_bus->write = xgene_enet_mdio_write; ++ snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii", ++ ndev->name); ++ ++ mdio_bus->priv = pdata; ++ mdio_bus->parent = &ndev->dev; ++ ++ ret = of_mdiobus_register(mdio_bus, mdio_np); ++ if (ret) { ++ netdev_err(ndev, "Failed to register MDIO bus\n"); ++ mdiobus_free(mdio_bus); ++ return ret; ++ } ++ pdata->mdio_bus = mdio_bus; ++ ++ ret = xgene_enet_phy_connect(ndev); ++ if (ret) ++ xgene_enet_mdio_remove(pdata); ++ ++ return ret; ++} ++ ++void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) ++{ ++ mdiobus_unregister(pdata->mdio_bus); ++ mdiobus_free(pdata->mdio_bus); ++ pdata->mdio_bus = NULL; ++} ++ ++struct xgene_mac_ops xgene_gmac_ops = { ++ .init = xgene_gmac_init, ++ .reset = xgene_gmac_reset, ++ .rx_enable = xgene_gmac_rx_enable, ++ .tx_enable = xgene_gmac_tx_enable, ++ .rx_disable = xgene_gmac_rx_disable, ++ .tx_disable = xgene_gmac_tx_disable, ++ .set_mac_addr = xgene_gmac_set_mac_addr, ++}; ++ ++struct xgene_port_ops xgene_gport_ops = { ++ .reset = xgene_enet_reset, ++ .cle_bypass = xgene_enet_cle_bypass, ++ .shutdown = xgene_gport_shutdown, ++}; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +new file mode 100644 +index 0000000..3855858 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +@@ -0,0 +1,325 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Ravi Patel <rapatel@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __XGENE_ENET_HW_H__ ++#define __XGENE_ENET_HW_H__ ++ ++#include "xgene_enet_main.h" ++ ++struct xgene_enet_pdata; ++struct xgene_enet_stats; ++ ++/* clears and then set bits */ ++static inline void xgene_set_bits(u32 *dst, u32 val, u32 start, u32 len) ++{ ++ u32 end = start + len - 1; ++ u32 mask = GENMASK(end, start); ++ ++ *dst &= ~mask; ++ *dst |= (val << start) & mask; ++} ++ ++static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) ++{ ++ return (val & GENMASK(end, start)) >> start; ++} ++ ++enum xgene_enet_rm { ++ RM0, ++ RM1, ++ RM3 = 3 ++}; ++ ++#define CSR_RING_ID 0x0008 ++#define OVERWRITE BIT(31) ++#define IS_BUFFER_POOL BIT(20) ++#define PREFETCH_BUF_EN BIT(21) ++#define CSR_RING_ID_BUF 0x000c ++#define CSR_RING_NE_INT_MODE 0x017c ++#define CSR_RING_CONFIG 0x006c ++#define CSR_RING_WR_BASE 0x0070 ++#define NUM_RING_CONFIG 5 ++#define BUFPOOL_MODE 3 ++#define INC_DEC_CMD_ADDR 0x002c ++#define UDP_HDR_SIZE 2 ++#define BUF_LEN_CODE_2K 0x5000 ++ ++#define CREATE_MASK(pos, len) GENMASK((pos)+(len)-1, (pos)) ++#define CREATE_MASK_ULL(pos, len) GENMASK_ULL((pos)+(len)-1, (pos)) ++ ++/* Empty slot soft signature */ ++#define EMPTY_SLOT_INDEX 1 ++#define EMPTY_SLOT ~0ULL ++ ++#define WORK_DESC_SIZE 32 ++#define BUFPOOL_DESC_SIZE 16 ++ ++#define RING_OWNER_MASK GENMASK(9, 6) ++#define RING_BUFNUM_MASK GENMASK(5, 0) ++ ++#define SELTHRSH_POS 3 ++#define SELTHRSH_LEN 3 ++#define RINGADDRL_POS 5 ++#define RINGADDRL_LEN 27 ++#define RINGADDRH_POS 0 ++#define RINGADDRH_LEN 6 ++#define RINGSIZE_POS 23 ++#define RINGSIZE_LEN 3 ++#define RINGTYPE_POS 19 ++#define RINGTYPE_LEN 2 ++#define RINGMODE_POS 20 ++#define RINGMODE_LEN 3 ++#define RECOMTIMEOUTL_POS 28 ++#define RECOMTIMEOUTL_LEN 3 ++#define RECOMTIMEOUTH_POS 0 ++#define RECOMTIMEOUTH_LEN 2 ++#define NUMMSGSINQ_POS 1 ++#define NUMMSGSINQ_LEN 16 ++#define ACCEPTLERR BIT(19) ++#define QCOHERENT BIT(4) ++#define RECOMBBUF BIT(27) ++ ++#define BLOCK_ETH_CSR_OFFSET 0x2000 ++#define BLOCK_ETH_RING_IF_OFFSET 0x9000 ++#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 ++ ++#define BLOCK_ETH_MAC_OFFSET 0x0000 ++#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 ++ ++#define MAC_ADDR_REG_OFFSET 0x00 ++#define MAC_COMMAND_REG_OFFSET 0x04 ++#define MAC_WRITE_REG_OFFSET 0x08 ++#define MAC_READ_REG_OFFSET 0x0c ++#define MAC_COMMAND_DONE_REG_OFFSET 0x10 ++ ++#define MII_MGMT_CONFIG_ADDR 0x20 ++#define MII_MGMT_COMMAND_ADDR 0x24 ++#define MII_MGMT_ADDRESS_ADDR 0x28 ++#define MII_MGMT_CONTROL_ADDR 0x2c ++#define MII_MGMT_STATUS_ADDR 0x30 ++#define MII_MGMT_INDICATORS_ADDR 0x34 ++ ++#define BUSY_MASK BIT(0) ++#define READ_CYCLE_MASK BIT(0) ++#define PHY_CONTROL_SET(dst, val) xgene_set_bits(dst, val, 0, 16) ++ ++#define ENET_SPARE_CFG_REG_ADDR 0x0750 ++#define RSIF_CONFIG_REG_ADDR 0x0010 ++#define RSIF_RAM_DBG_REG0_ADDR 0x0048 ++#define RGMII_REG_0_ADDR 0x07e0 ++#define CFG_LINK_AGGR_RESUME_0_ADDR 0x07c8 ++#define DEBUG_REG_ADDR 0x0700 ++#define CFG_BYPASS_ADDR 0x0294 ++#define CLE_BYPASS_REG0_0_ADDR 0x0490 ++#define CLE_BYPASS_REG1_0_ADDR 0x0494 ++#define CFG_RSIF_FPBUFF_TIMEOUT_EN BIT(31) ++#define RESUME_TX BIT(0) ++#define CFG_SPEED_1250 BIT(24) ++#define TX_PORT0 BIT(0) ++#define CFG_BYPASS_UNISEC_TX BIT(2) ++#define CFG_BYPASS_UNISEC_RX BIT(1) ++#define CFG_CLE_BYPASS_EN0 BIT(31) ++#define CFG_TXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 29, 3) ++ ++#define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2) ++#define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12) ++#define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4) ++#define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2) ++#define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16) ++#define CFG_CLE_DSTQID0(val) (val & GENMASK(11, 0)) ++#define CFG_CLE_FPSEL0(val) ((val << 16) & GENMASK(19, 16)) ++#define ICM_CONFIG0_REG_0_ADDR 0x0400 ++#define ICM_CONFIG2_REG_0_ADDR 0x0410 ++#define RX_DV_GATE_REG_0_ADDR 0x05fc ++#define TX_DV_GATE_EN0 BIT(2) ++#define RX_DV_GATE_EN0 BIT(1) ++#define RESUME_RX0 BIT(0) ++#define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 ++#define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc ++#define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 ++#define ENET_CFGSSQMIQMLITEWQASSOC_ADDR 0xf4 ++#define ENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 ++#define ENET_BLOCK_MEM_RDY_ADDR 0x74 ++#define MAC_CONFIG_1_ADDR 0x00 ++#define MAC_CONFIG_2_ADDR 0x04 ++#define MAX_FRAME_LEN_ADDR 0x10 ++#define INTERFACE_CONTROL_ADDR 0x38 ++#define STATION_ADDR0_ADDR 0x40 ++#define STATION_ADDR1_ADDR 0x44 ++#define PHY_ADDR_SET(dst, val) xgene_set_bits(dst, val, 8, 5) ++#define REG_ADDR_SET(dst, val) xgene_set_bits(dst, val, 0, 5) ++#define ENET_INTERFACE_MODE2_SET(dst, val) xgene_set_bits(dst, val, 8, 2) ++#define MGMT_CLOCK_SEL_SET(dst, val) xgene_set_bits(dst, val, 0, 3) ++#define SOFT_RESET1 BIT(31) ++#define TX_EN BIT(0) ++#define RX_EN BIT(2) ++#define ENET_LHD_MODE BIT(25) ++#define ENET_GHD_MODE BIT(26) ++#define FULL_DUPLEX2 BIT(0) ++#define SCAN_AUTO_INCR BIT(5) ++#define TBYT_ADDR 0x38 ++#define TPKT_ADDR 0x39 ++#define TDRP_ADDR 0x45 ++#define TFCS_ADDR 0x47 ++#define TUND_ADDR 0x4a ++ ++#define TSO_IPPROTO_TCP 1 ++ ++#define USERINFO_POS 0 ++#define USERINFO_LEN 32 ++#define FPQNUM_POS 32 ++#define FPQNUM_LEN 12 ++#define LERR_POS 60 ++#define LERR_LEN 3 ++#define STASH_POS 52 ++#define STASH_LEN 2 ++#define BUFDATALEN_POS 48 ++#define BUFDATALEN_LEN 12 ++#define DATAADDR_POS 0 ++#define DATAADDR_LEN 42 ++#define COHERENT_POS 63 ++#define HENQNUM_POS 48 ++#define HENQNUM_LEN 12 ++#define TYPESEL_POS 44 ++#define TYPESEL_LEN 4 ++#define ETHHDR_POS 12 ++#define ETHHDR_LEN 8 ++#define IC_POS 35 /* Insert CRC */ ++#define TCPHDR_POS 0 ++#define TCPHDR_LEN 6 ++#define IPHDR_POS 6 ++#define IPHDR_LEN 6 ++#define EC_POS 22 /* Enable checksum */ ++#define EC_LEN 1 ++#define IS_POS 24 /* IP protocol select */ ++#define IS_LEN 1 ++#define TYPE_ETH_WORK_MESSAGE_POS 44 ++ ++struct xgene_enet_raw_desc { ++ __le64 m0; ++ __le64 m1; ++ __le64 m2; ++ __le64 m3; ++}; ++ ++struct xgene_enet_raw_desc16 { ++ __le64 m0; ++ __le64 m1; ++}; ++ ++static inline void xgene_enet_mark_desc_slot_empty(void *desc_slot_ptr) ++{ ++ __le64 *desc_slot = desc_slot_ptr; ++ ++ desc_slot[EMPTY_SLOT_INDEX] = cpu_to_le64(EMPTY_SLOT); ++} ++ ++static inline bool xgene_enet_is_desc_slot_empty(void *desc_slot_ptr) ++{ ++ __le64 *desc_slot = desc_slot_ptr; ++ ++ return (desc_slot[EMPTY_SLOT_INDEX] == cpu_to_le64(EMPTY_SLOT)); ++} ++ ++enum xgene_enet_ring_cfgsize { ++ RING_CFGSIZE_512B, ++ RING_CFGSIZE_2KB, ++ RING_CFGSIZE_16KB, ++ RING_CFGSIZE_64KB, ++ RING_CFGSIZE_512KB, ++ RING_CFGSIZE_INVALID ++}; ++ ++enum xgene_enet_ring_type { ++ RING_DISABLED, ++ RING_REGULAR, ++ RING_BUFPOOL ++}; ++ ++enum xgene_ring_owner { ++ RING_OWNER_ETH0, ++ RING_OWNER_CPU = 15, ++ RING_OWNER_INVALID ++}; ++ ++enum xgene_enet_ring_bufnum { ++ RING_BUFNUM_REGULAR = 0x0, ++ RING_BUFNUM_BUFPOOL = 0x20, ++ RING_BUFNUM_INVALID ++}; ++ ++enum xgene_enet_cmd { ++ XGENE_ENET_WR_CMD = BIT(31), ++ XGENE_ENET_RD_CMD = BIT(30) ++}; ++ ++enum xgene_enet_err_code { ++ HBF_READ_DATA = 3, ++ HBF_LL_READ = 4, ++ BAD_WORK_MSG = 6, ++ BUFPOOL_TIMEOUT = 15, ++ INGRESS_CRC = 16, ++ INGRESS_CHECKSUM = 17, ++ INGRESS_TRUNC_FRAME = 18, ++ INGRESS_PKT_LEN = 19, ++ INGRESS_PKT_UNDER = 20, ++ INGRESS_FIFO_OVERRUN = 21, ++ INGRESS_CHECKSUM_COMPUTE = 26, ++ ERR_CODE_INVALID ++}; ++ ++static inline enum xgene_ring_owner xgene_enet_ring_owner(u16 id) ++{ ++ return (id & RING_OWNER_MASK) >> 6; ++} ++ ++static inline u8 xgene_enet_ring_bufnum(u16 id) ++{ ++ return id & RING_BUFNUM_MASK; ++} ++ ++static inline bool xgene_enet_is_bufpool(u16 id) ++{ ++ return ((id & RING_BUFNUM_MASK) >= 0x20) ? true : false; ++} ++ ++static inline u16 xgene_enet_get_numslots(u16 id, u32 size) ++{ ++ bool is_bufpool = xgene_enet_is_bufpool(id); ++ ++ return (is_bufpool) ? size / BUFPOOL_DESC_SIZE : ++ size / WORK_DESC_SIZE; ++} ++ ++struct xgene_enet_desc_ring *xgene_enet_setup_ring( ++ struct xgene_enet_desc_ring *ring); ++void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring); ++void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, ++ struct xgene_enet_pdata *pdata, ++ enum xgene_enet_err_code status); ++ ++int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); ++void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); ++ ++extern struct xgene_mac_ops xgene_gmac_ops; ++extern struct xgene_port_ops xgene_gport_ops; ++ ++#endif /* __XGENE_ENET_HW_H__ */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +new file mode 100644 +index 0000000..3c208cc +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -0,0 +1,1006 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Ravi Patel <rapatel@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++#include "xgene_enet_sgmac.h" ++#include "xgene_enet_xgmac.h" ++ ++static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) ++{ ++ struct xgene_enet_raw_desc16 *raw_desc; ++ int i; ++ ++ for (i = 0; i < buf_pool->slots; i++) { ++ raw_desc = &buf_pool->raw_desc16[i]; ++ ++ /* Hardware expects descriptor in little endian format */ ++ raw_desc->m0 = cpu_to_le64(i | ++ SET_VAL(FPQNUM, buf_pool->dst_ring_num) | ++ SET_VAL(STASH, 3)); ++ } ++} ++ ++static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool, ++ u32 nbuf) ++{ ++ struct sk_buff *skb; ++ struct xgene_enet_raw_desc16 *raw_desc; ++ struct net_device *ndev; ++ struct device *dev; ++ dma_addr_t dma_addr; ++ u32 tail = buf_pool->tail; ++ u32 slots = buf_pool->slots - 1; ++ u16 bufdatalen, len; ++ int i; ++ ++ ndev = buf_pool->ndev; ++ dev = ndev_to_dev(buf_pool->ndev); ++ bufdatalen = BUF_LEN_CODE_2K | (SKB_BUFFER_SIZE & GENMASK(11, 0)); ++ len = XGENE_ENET_MAX_MTU; ++ ++ for (i = 0; i < nbuf; i++) { ++ raw_desc = &buf_pool->raw_desc16[tail]; ++ ++ skb = netdev_alloc_skb_ip_align(ndev, len); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ buf_pool->rx_skb[tail] = skb; ++ ++ dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, dma_addr)) { ++ netdev_err(ndev, "DMA mapping error\n"); ++ dev_kfree_skb_any(skb); ++ return -EINVAL; ++ } ++ ++ raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | ++ SET_VAL(BUFDATALEN, bufdatalen) | ++ SET_BIT(COHERENT)); ++ tail = (tail + 1) & slots; ++ } ++ ++ iowrite32(nbuf, buf_pool->cmd); ++ buf_pool->tail = tail; ++ ++ return 0; ++} ++ ++static u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); ++ ++ return ((u16)pdata->rm << 10) | ring->num; ++} ++ ++static u8 xgene_enet_hdr_len(const void *data) ++{ ++ const struct ethhdr *eth = data; ++ ++ return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN; ++} ++ ++static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring) ++{ ++ u32 __iomem *cmd_base = ring->cmd_base; ++ u32 ring_state, num_msgs; ++ ++ ring_state = ioread32(&cmd_base[1]); ++ num_msgs = ring_state & CREATE_MASK(NUMMSGSINQ_POS, NUMMSGSINQ_LEN); ++ ++ return num_msgs >> NUMMSGSINQ_POS; ++} ++ ++static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool) ++{ ++ struct xgene_enet_raw_desc16 *raw_desc; ++ u32 slots = buf_pool->slots - 1; ++ u32 tail = buf_pool->tail; ++ u32 userinfo; ++ int i, len; ++ ++ len = xgene_enet_ring_len(buf_pool); ++ for (i = 0; i < len; i++) { ++ tail = (tail - 1) & slots; ++ raw_desc = &buf_pool->raw_desc16[tail]; ++ ++ /* Hardware stores descriptor in little endian format */ ++ userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); ++ dev_kfree_skb_any(buf_pool->rx_skb[userinfo]); ++ } ++ ++ iowrite32(-len, buf_pool->cmd); ++ buf_pool->tail = tail; ++} ++ ++static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) ++{ ++ struct xgene_enet_desc_ring *rx_ring = data; ++ ++ if (napi_schedule_prep(&rx_ring->napi)) { ++ disable_irq_nosync(irq); ++ __napi_schedule(&rx_ring->napi); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, ++ struct xgene_enet_raw_desc *raw_desc) ++{ ++ struct sk_buff *skb; ++ struct device *dev; ++ u16 skb_index; ++ u8 status; ++ int ret = 0; ++ ++ skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); ++ skb = cp_ring->cp_skb[skb_index]; ++ ++ dev = ndev_to_dev(cp_ring->ndev); ++ dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)), ++ GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)), ++ DMA_TO_DEVICE); ++ ++ /* Checking for error */ ++ status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); ++ if (unlikely(status > 2)) { ++ xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev), ++ status); ++ ret = -EIO; ++ } ++ ++ if (likely(skb)) { ++ dev_kfree_skb_any(skb); ++ } else { ++ netdev_err(cp_ring->ndev, "completion skb is NULL\n"); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ ++static u64 xgene_enet_work_msg(struct sk_buff *skb) ++{ ++ struct iphdr *iph; ++ u8 l3hlen, l4hlen = 0; ++ u8 csum_enable = 0; ++ u8 proto = 0; ++ u8 ethhdr; ++ u64 hopinfo; ++ ++ if (unlikely(skb->protocol != htons(ETH_P_IP)) && ++ unlikely(skb->protocol != htons(ETH_P_8021Q))) ++ goto out; ++ ++ if (unlikely(!(skb->dev->features & NETIF_F_IP_CSUM))) ++ goto out; ++ ++ iph = ip_hdr(skb); ++ if (unlikely(ip_is_fragment(iph))) ++ goto out; ++ ++ if (likely(iph->protocol == IPPROTO_TCP)) { ++ l4hlen = tcp_hdrlen(skb) >> 2; ++ csum_enable = 1; ++ proto = TSO_IPPROTO_TCP; ++ } else if (iph->protocol == IPPROTO_UDP) { ++ l4hlen = UDP_HDR_SIZE; ++ csum_enable = 1; ++ } ++out: ++ l3hlen = ip_hdrlen(skb) >> 2; ++ ethhdr = xgene_enet_hdr_len(skb->data); ++ hopinfo = SET_VAL(TCPHDR, l4hlen) | ++ SET_VAL(IPHDR, l3hlen) | ++ SET_VAL(ETHHDR, ethhdr) | ++ SET_VAL(EC, csum_enable) | ++ SET_VAL(IS, proto) | ++ SET_BIT(IC) | ++ SET_BIT(TYPE_ETH_WORK_MESSAGE); ++ ++ return hopinfo; ++} ++ ++static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, ++ struct sk_buff *skb) ++{ ++ struct device *dev = ndev_to_dev(tx_ring->ndev); ++ struct xgene_enet_raw_desc *raw_desc; ++ dma_addr_t dma_addr; ++ u16 tail = tx_ring->tail; ++ u64 hopinfo; ++ ++ raw_desc = &tx_ring->raw_desc[tail]; ++ memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc)); ++ ++ dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, dma_addr)) { ++ netdev_err(tx_ring->ndev, "DMA mapping error\n"); ++ return -EINVAL; ++ } ++ ++ /* Hardware expects descriptor in little endian format */ ++ raw_desc->m0 = cpu_to_le64(tail); ++ raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | ++ SET_VAL(BUFDATALEN, skb->len) | ++ SET_BIT(COHERENT)); ++ hopinfo = xgene_enet_work_msg(skb); ++ raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | ++ hopinfo); ++ tx_ring->cp_ring->cp_skb[tail] = skb; ++ ++ return 0; ++} ++ ++static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, ++ struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring; ++ struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring; ++ u32 tx_level, cq_level; ++ ++ tx_level = xgene_enet_ring_len(tx_ring); ++ cq_level = xgene_enet_ring_len(cp_ring); ++ if (unlikely(tx_level > pdata->tx_qcnt_hi || ++ cq_level > pdata->cp_qcnt_hi)) { ++ netif_stop_queue(ndev); ++ return NETDEV_TX_BUSY; ++ } ++ ++ if (xgene_enet_setup_tx_desc(tx_ring, skb)) { ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++ } ++ ++ iowrite32(1, tx_ring->cmd); ++ skb_tx_timestamp(skb); ++ tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1); ++ ++ pdata->stats.tx_packets++; ++ pdata->stats.tx_bytes += skb->len; ++ ++ return NETDEV_TX_OK; ++} ++ ++static void xgene_enet_skip_csum(struct sk_buff *skb) ++{ ++ struct iphdr *iph = ip_hdr(skb); ++ ++ if (!ip_is_fragment(iph) || ++ (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) { ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } ++} ++ ++static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, ++ struct xgene_enet_raw_desc *raw_desc) ++{ ++ struct net_device *ndev; ++ struct xgene_enet_pdata *pdata; ++ struct device *dev; ++ struct xgene_enet_desc_ring *buf_pool; ++ u32 datalen, skb_index; ++ struct sk_buff *skb; ++ u8 status; ++ int ret = 0; ++ ++ ndev = rx_ring->ndev; ++ pdata = netdev_priv(ndev); ++ dev = ndev_to_dev(rx_ring->ndev); ++ buf_pool = rx_ring->buf_pool; ++ ++ dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)), ++ XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE); ++ skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); ++ skb = buf_pool->rx_skb[skb_index]; ++ ++ /* checking for error */ ++ status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); ++ if (unlikely(status > 2)) { ++ dev_kfree_skb_any(skb); ++ xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev), ++ status); ++ pdata->stats.rx_dropped++; ++ ret = -EIO; ++ goto out; ++ } ++ ++ /* strip off CRC as HW isn't doing this */ ++ datalen = GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)); ++ datalen -= 4; ++ prefetch(skb->data - NET_IP_ALIGN); ++ skb_put(skb, datalen); ++ ++ skb_checksum_none_assert(skb); ++ skb->protocol = eth_type_trans(skb, ndev); ++ if (likely((ndev->features & NETIF_F_IP_CSUM) && ++ skb->protocol == htons(ETH_P_IP))) { ++ xgene_enet_skip_csum(skb); ++ } ++ ++ pdata->stats.rx_packets++; ++ pdata->stats.rx_bytes += datalen; ++ napi_gro_receive(&rx_ring->napi, skb); ++out: ++ if (--rx_ring->nbufpool == 0) { ++ ret = xgene_enet_refill_bufpool(buf_pool, NUM_BUFPOOL); ++ rx_ring->nbufpool = NUM_BUFPOOL; ++ } ++ ++ return ret; ++} ++ ++static bool is_rx_desc(struct xgene_enet_raw_desc *raw_desc) ++{ ++ return GET_VAL(FPQNUM, le64_to_cpu(raw_desc->m0)) ? true : false; ++} ++ ++static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, ++ int budget) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); ++ struct xgene_enet_raw_desc *raw_desc; ++ u16 head = ring->head; ++ u16 slots = ring->slots - 1; ++ int ret, count = 0; ++ ++ do { ++ raw_desc = &ring->raw_desc[head]; ++ if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc))) ++ break; ++ ++ if (is_rx_desc(raw_desc)) ++ ret = xgene_enet_rx_frame(ring, raw_desc); ++ else ++ ret = xgene_enet_tx_completion(ring, raw_desc); ++ xgene_enet_mark_desc_slot_empty(raw_desc); ++ ++ head = (head + 1) & slots; ++ count++; ++ ++ if (ret) ++ break; ++ } while (--budget); ++ ++ if (likely(count)) { ++ iowrite32(-count, ring->cmd); ++ ring->head = head; ++ ++ if (netif_queue_stopped(ring->ndev)) { ++ if (xgene_enet_ring_len(ring) < pdata->cp_qcnt_low) ++ netif_wake_queue(ring->ndev); ++ } ++ } ++ ++ return count; ++} ++ ++static int xgene_enet_napi(struct napi_struct *napi, const int budget) ++{ ++ struct xgene_enet_desc_ring *ring; ++ int processed; ++ ++ ring = container_of(napi, struct xgene_enet_desc_ring, napi); ++ processed = xgene_enet_process_ring(ring, budget); ++ ++ if (processed != budget) { ++ napi_complete(napi); ++ enable_irq(ring->irq); ++ } ++ ++ return processed; ++} ++ ++static void xgene_enet_timeout(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ ++ pdata->mac_ops->reset(pdata); ++} ++ ++static int xgene_enet_register_irq(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct device *dev = ndev_to_dev(ndev); ++ int ret; ++ ++ ret = devm_request_irq(dev, pdata->rx_ring->irq, xgene_enet_rx_irq, ++ IRQF_SHARED, ndev->name, pdata->rx_ring); ++ if (ret) { ++ netdev_err(ndev, "rx%d interrupt request failed\n", ++ pdata->rx_ring->irq); ++ } ++ ++ return ret; ++} ++ ++static void xgene_enet_free_irq(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata; ++ struct device *dev; ++ ++ pdata = netdev_priv(ndev); ++ dev = ndev_to_dev(ndev); ++ devm_free_irq(dev, pdata->rx_ring->irq, pdata->rx_ring); ++} ++ ++static int xgene_enet_open(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct xgene_mac_ops *mac_ops = pdata->mac_ops; ++ int ret; ++ ++ mac_ops->tx_enable(pdata); ++ mac_ops->rx_enable(pdata); ++ ++ ret = xgene_enet_register_irq(ndev); ++ if (ret) ++ return ret; ++ napi_enable(&pdata->rx_ring->napi); ++ ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) ++ phy_start(pdata->phy_dev); ++ else ++ schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF); ++ ++ netif_start_queue(ndev); ++ ++ return ret; ++} ++ ++static int xgene_enet_close(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct xgene_mac_ops *mac_ops = pdata->mac_ops; ++ ++ netif_stop_queue(ndev); ++ ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) ++ phy_stop(pdata->phy_dev); ++ else ++ cancel_delayed_work_sync(&pdata->link_work); ++ ++ napi_disable(&pdata->rx_ring->napi); ++ xgene_enet_free_irq(ndev); ++ xgene_enet_process_ring(pdata->rx_ring, -1); ++ ++ mac_ops->tx_disable(pdata); ++ mac_ops->rx_disable(pdata); ++ ++ return 0; ++} ++ ++static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring) ++{ ++ struct xgene_enet_pdata *pdata; ++ struct device *dev; ++ ++ pdata = netdev_priv(ring->ndev); ++ dev = ndev_to_dev(ring->ndev); ++ ++ xgene_enet_clear_ring(ring); ++ dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); ++} ++ ++static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) ++{ ++ struct xgene_enet_desc_ring *buf_pool; ++ ++ if (pdata->tx_ring) { ++ xgene_enet_delete_ring(pdata->tx_ring); ++ pdata->tx_ring = NULL; ++ } ++ ++ if (pdata->rx_ring) { ++ buf_pool = pdata->rx_ring->buf_pool; ++ xgene_enet_delete_bufpool(buf_pool); ++ xgene_enet_delete_ring(buf_pool); ++ xgene_enet_delete_ring(pdata->rx_ring); ++ pdata->rx_ring = NULL; ++ } ++} ++ ++static int xgene_enet_get_ring_size(struct device *dev, ++ enum xgene_enet_ring_cfgsize cfgsize) ++{ ++ int size = -EINVAL; ++ ++ switch (cfgsize) { ++ case RING_CFGSIZE_512B: ++ size = 0x200; ++ break; ++ case RING_CFGSIZE_2KB: ++ size = 0x800; ++ break; ++ case RING_CFGSIZE_16KB: ++ size = 0x4000; ++ break; ++ case RING_CFGSIZE_64KB: ++ size = 0x10000; ++ break; ++ case RING_CFGSIZE_512KB: ++ size = 0x80000; ++ break; ++ default: ++ dev_err(dev, "Unsupported cfg ring size %d\n", cfgsize); ++ break; ++ } ++ ++ return size; ++} ++ ++static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring) ++{ ++ struct device *dev; ++ ++ if (!ring) ++ return; ++ ++ dev = ndev_to_dev(ring->ndev); ++ ++ if (ring->desc_addr) { ++ xgene_enet_clear_ring(ring); ++ dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); ++ } ++ devm_kfree(dev, ring); ++} ++ ++static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata) ++{ ++ struct device *dev = &pdata->pdev->dev; ++ struct xgene_enet_desc_ring *ring; ++ ++ ring = pdata->tx_ring; ++ if (ring) { ++ if (ring->cp_ring && ring->cp_ring->cp_skb) ++ devm_kfree(dev, ring->cp_ring->cp_skb); ++ xgene_enet_free_desc_ring(ring); ++ } ++ ++ ring = pdata->rx_ring; ++ if (ring) { ++ if (ring->buf_pool) { ++ if (ring->buf_pool->rx_skb) ++ devm_kfree(dev, ring->buf_pool->rx_skb); ++ xgene_enet_free_desc_ring(ring->buf_pool); ++ } ++ xgene_enet_free_desc_ring(ring); ++ } ++} ++ ++static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( ++ struct net_device *ndev, u32 ring_num, ++ enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id) ++{ ++ struct xgene_enet_desc_ring *ring; ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct device *dev = ndev_to_dev(ndev); ++ int size; ++ ++ size = xgene_enet_get_ring_size(dev, cfgsize); ++ if (size < 0) ++ return NULL; ++ ++ ring = devm_kzalloc(dev, sizeof(struct xgene_enet_desc_ring), ++ GFP_KERNEL); ++ if (!ring) ++ return NULL; ++ ++ ring->ndev = ndev; ++ ring->num = ring_num; ++ ring->cfgsize = cfgsize; ++ ring->id = ring_id; ++ ++ ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma, ++ GFP_KERNEL); ++ if (!ring->desc_addr) { ++ devm_kfree(dev, ring); ++ return NULL; ++ } ++ ring->size = size; ++ ++ ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); ++ ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; ++ ring = xgene_enet_setup_ring(ring); ++ netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", ++ ring->num, ring->size, ring->id, ring->slots); ++ ++ return ring; ++} ++ ++static u16 xgene_enet_get_ring_id(enum xgene_ring_owner owner, u8 bufnum) ++{ ++ return (owner << 6) | (bufnum & GENMASK(5, 0)); ++} ++ ++static int xgene_enet_create_desc_rings(struct net_device *ndev) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct device *dev = ndev_to_dev(ndev); ++ struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring; ++ struct xgene_enet_desc_ring *buf_pool = NULL; ++ u8 cpu_bufnum = 0, eth_bufnum = 0; ++ u8 bp_bufnum = 0x20; ++ u16 ring_id, ring_num = 0; ++ int ret; ++ ++ /* allocate rx descriptor ring */ ++ ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++); ++ rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++, ++ RING_CFGSIZE_16KB, ring_id); ++ if (!rx_ring) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ /* allocate buffer pool for receiving packets */ ++ ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, bp_bufnum++); ++ buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++, ++ RING_CFGSIZE_2KB, ring_id); ++ if (!buf_pool) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ rx_ring->nbufpool = NUM_BUFPOOL; ++ rx_ring->buf_pool = buf_pool; ++ rx_ring->irq = pdata->rx_irq; ++ buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots, ++ sizeof(struct sk_buff *), GFP_KERNEL); ++ if (!buf_pool->rx_skb) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool); ++ rx_ring->buf_pool = buf_pool; ++ pdata->rx_ring = rx_ring; ++ ++ /* allocate tx descriptor ring */ ++ ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, eth_bufnum++); ++ tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++, ++ RING_CFGSIZE_16KB, ring_id); ++ if (!tx_ring) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ pdata->tx_ring = tx_ring; ++ ++ cp_ring = pdata->rx_ring; ++ cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots, ++ sizeof(struct sk_buff *), GFP_KERNEL); ++ if (!cp_ring->cp_skb) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ pdata->tx_ring->cp_ring = cp_ring; ++ pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring); ++ ++ pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2; ++ pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2; ++ pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2; ++ ++ return 0; ++ ++err: ++ xgene_enet_free_desc_rings(pdata); ++ return ret; ++} ++ ++static struct rtnl_link_stats64 *xgene_enet_get_stats64( ++ struct net_device *ndev, ++ struct rtnl_link_stats64 *storage) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ struct rtnl_link_stats64 *stats = &pdata->stats; ++ ++ stats->rx_errors += stats->rx_length_errors + ++ stats->rx_crc_errors + ++ stats->rx_frame_errors + ++ stats->rx_fifo_errors; ++ memcpy(storage, &pdata->stats, sizeof(struct rtnl_link_stats64)); ++ ++ return storage; ++} ++ ++static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) ++{ ++ struct xgene_enet_pdata *pdata = netdev_priv(ndev); ++ int ret; ++ ++ ret = eth_mac_addr(ndev, addr); ++ if (ret) ++ return ret; ++ pdata->mac_ops->set_mac_addr(pdata); ++ ++ return ret; ++} ++ ++static const struct net_device_ops xgene_ndev_ops = { ++ .ndo_open = xgene_enet_open, ++ .ndo_stop = xgene_enet_close, ++ .ndo_start_xmit = xgene_enet_start_xmit, ++ .ndo_tx_timeout = xgene_enet_timeout, ++ .ndo_get_stats64 = xgene_enet_get_stats64, ++ .ndo_change_mtu = eth_change_mtu, ++ .ndo_set_mac_address = xgene_enet_set_mac_address, ++}; ++ ++static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) ++{ ++ struct platform_device *pdev; ++ struct net_device *ndev; ++ struct device *dev; ++ struct resource *res; ++ void __iomem *base_addr; ++ const char *mac; ++ int ret; ++ ++ pdev = pdata->pdev; ++ dev = &pdev->dev; ++ ndev = pdata->ndev; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); ++ if (!res) { ++ dev_err(dev, "Resource enet_csr not defined\n"); ++ return -ENODEV; ++ } ++ pdata->base_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->base_addr)) { ++ dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); ++ return PTR_ERR(pdata->base_addr); ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); ++ if (!res) { ++ dev_err(dev, "Resource ring_csr not defined\n"); ++ return -ENODEV; ++ } ++ pdata->ring_csr_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->ring_csr_addr)) { ++ dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); ++ return PTR_ERR(pdata->ring_csr_addr); ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); ++ if (!res) { ++ dev_err(dev, "Resource ring_cmd not defined\n"); ++ return -ENODEV; ++ } ++ pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); ++ if (IS_ERR(pdata->ring_cmd_addr)) { ++ dev_err(dev, "Unable to retrieve ENET Ring command region\n"); ++ return PTR_ERR(pdata->ring_cmd_addr); ++ } ++ ++ ret = platform_get_irq(pdev, 0); ++ if (ret <= 0) { ++ dev_err(dev, "Unable to get ENET Rx IRQ\n"); ++ ret = ret ? : -ENXIO; ++ return ret; ++ } ++ pdata->rx_irq = ret; ++ ++ mac = of_get_mac_address(dev->of_node); ++ if (mac) ++ memcpy(ndev->dev_addr, mac, ndev->addr_len); ++ else ++ eth_hw_addr_random(ndev); ++ memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); ++ ++ pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); ++ if (pdata->phy_mode < 0) { ++ dev_err(dev, "Unable to get phy-connection-type\n"); ++ return pdata->phy_mode; ++ } ++ if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII && ++ pdata->phy_mode != PHY_INTERFACE_MODE_SGMII && ++ pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) { ++ dev_err(dev, "Incorrect phy-connection-type specified\n"); ++ return -ENODEV; ++ } ++ ++ pdata->clk = devm_clk_get(&pdev->dev, NULL); ++ ret = IS_ERR(pdata->clk); ++ if (IS_ERR(pdata->clk)) { ++ dev_err(&pdev->dev, "can't get clock\n"); ++ ret = PTR_ERR(pdata->clk); ++ return ret; ++ } ++ ++ base_addr = pdata->base_addr; ++ pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; ++ pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; ++ pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII || ++ pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) { ++ pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; ++ pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; ++ } else { ++ pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET; ++ pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET; ++ } ++ pdata->rx_buff_cnt = NUM_PKT_BUF; ++ ++ return 0; ++} ++ ++static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) ++{ ++ struct net_device *ndev = pdata->ndev; ++ struct xgene_enet_desc_ring *buf_pool; ++ u16 dst_ring_num; ++ int ret; ++ ++ pdata->port_ops->reset(pdata); ++ ++ ret = xgene_enet_create_desc_rings(ndev); ++ if (ret) { ++ netdev_err(ndev, "Error in ring configuration\n"); ++ return ret; ++ } ++ ++ /* setup buffer pool */ ++ buf_pool = pdata->rx_ring->buf_pool; ++ xgene_enet_init_bufpool(buf_pool); ++ ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt); ++ if (ret) { ++ xgene_enet_delete_desc_rings(pdata); ++ return ret; ++ } ++ ++ dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); ++ pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id); ++ pdata->mac_ops->init(pdata); ++ ++ return ret; ++} ++ ++static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata) ++{ ++ switch (pdata->phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ pdata->mac_ops = &xgene_gmac_ops; ++ pdata->port_ops = &xgene_gport_ops; ++ pdata->rm = RM3; ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ pdata->mac_ops = &xgene_sgmac_ops; ++ pdata->port_ops = &xgene_sgport_ops; ++ pdata->rm = RM1; ++ break; ++ default: ++ pdata->mac_ops = &xgene_xgmac_ops; ++ pdata->port_ops = &xgene_xgport_ops; ++ pdata->rm = RM0; ++ break; ++ } ++} ++ ++static int xgene_enet_probe(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct xgene_enet_pdata *pdata; ++ struct device *dev = &pdev->dev; ++ struct napi_struct *napi; ++ struct xgene_mac_ops *mac_ops; ++ int ret; ++ ++ ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata)); ++ if (!ndev) ++ return -ENOMEM; ++ ++ pdata = netdev_priv(ndev); ++ ++ pdata->pdev = pdev; ++ pdata->ndev = ndev; ++ SET_NETDEV_DEV(ndev, dev); ++ platform_set_drvdata(pdev, pdata); ++ ndev->netdev_ops = &xgene_ndev_ops; ++ xgene_enet_set_ethtool_ops(ndev); ++ ndev->features |= NETIF_F_IP_CSUM | ++ NETIF_F_GSO | ++ NETIF_F_GRO; ++ ++ ret = xgene_enet_get_resources(pdata); ++ if (ret) ++ goto err; ++ ++ xgene_enet_setup_ops(pdata); ++ ++ ret = register_netdev(ndev); ++ if (ret) { ++ netdev_err(ndev, "Failed to register netdev\n"); ++ goto err; ++ } ++ ++ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ netdev_err(ndev, "No usable DMA configuration\n"); ++ goto err; ++ } ++ ++ ret = xgene_enet_init_hw(pdata); ++ if (ret) ++ goto err; ++ ++ napi = &pdata->rx_ring->napi; ++ netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); ++ mac_ops = pdata->mac_ops; ++ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) ++ ret = xgene_enet_mdio_config(pdata); ++ else ++ INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state); ++ ++ return ret; ++err: ++ free_netdev(ndev); ++ return ret; ++} ++ ++static int xgene_enet_remove(struct platform_device *pdev) ++{ ++ struct xgene_enet_pdata *pdata; ++ struct xgene_mac_ops *mac_ops; ++ struct net_device *ndev; ++ ++ pdata = platform_get_drvdata(pdev); ++ mac_ops = pdata->mac_ops; ++ ndev = pdata->ndev; ++ ++ mac_ops->rx_disable(pdata); ++ mac_ops->tx_disable(pdata); ++ ++ netif_napi_del(&pdata->rx_ring->napi); ++ xgene_enet_mdio_remove(pdata); ++ xgene_enet_delete_desc_rings(pdata); ++ unregister_netdev(ndev); ++ pdata->port_ops->shutdown(pdata); ++ free_netdev(ndev); ++ ++ return 0; ++} ++ ++static struct of_device_id xgene_enet_match[] = { ++ {.compatible = "apm,xgene-enet",}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, xgene_enet_match); ++ ++static struct platform_driver xgene_enet_driver = { ++ .driver = { ++ .name = "xgene-enet", ++ .of_match_table = xgene_enet_match, ++ }, ++ .probe = xgene_enet_probe, ++ .remove = xgene_enet_remove, ++}; ++ ++module_platform_driver(xgene_enet_driver); ++ ++MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver"); ++MODULE_VERSION(XGENE_DRV_VERSION); ++MODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); ++MODULE_AUTHOR("Keyur Chudgar <kchudgar@apm.com>"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +new file mode 100644 +index 0000000..874e5a0 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +@@ -0,0 +1,163 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Ravi Patel <rapatel@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __XGENE_ENET_MAIN_H__ ++#define __XGENE_ENET_MAIN_H__ ++ ++#include <linux/clk.h> ++#include <linux/of_platform.h> ++#include <linux/of_net.h> ++#include <linux/of_mdio.h> ++#include <linux/module.h> ++#include <net/ip.h> ++#include <linux/prefetch.h> ++#include <linux/if_vlan.h> ++#include <linux/phy.h> ++#include "xgene_enet_hw.h" ++ ++#define XGENE_DRV_VERSION "v1.0" ++#define XGENE_ENET_MAX_MTU 1536 ++#define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN) ++#define NUM_PKT_BUF 64 ++#define NUM_BUFPOOL 32 ++ ++#define PHY_POLL_LINK_ON (10 * HZ) ++#define PHY_POLL_LINK_OFF (PHY_POLL_LINK_ON / 5) ++ ++/* software context of a descriptor ring */ ++struct xgene_enet_desc_ring { ++ struct net_device *ndev; ++ u16 id; ++ u16 num; ++ u16 head; ++ u16 tail; ++ u16 slots; ++ u16 irq; ++ u32 size; ++ u32 state[NUM_RING_CONFIG]; ++ void __iomem *cmd_base; ++ void __iomem *cmd; ++ dma_addr_t dma; ++ u16 dst_ring_num; ++ u8 nbufpool; ++ struct sk_buff *(*rx_skb); ++ struct sk_buff *(*cp_skb); ++ enum xgene_enet_ring_cfgsize cfgsize; ++ struct xgene_enet_desc_ring *cp_ring; ++ struct xgene_enet_desc_ring *buf_pool; ++ struct napi_struct napi; ++ union { ++ void *desc_addr; ++ struct xgene_enet_raw_desc *raw_desc; ++ struct xgene_enet_raw_desc16 *raw_desc16; ++ }; ++}; ++ ++struct xgene_mac_ops { ++ void (*init)(struct xgene_enet_pdata *pdata); ++ void (*reset)(struct xgene_enet_pdata *pdata); ++ void (*tx_enable)(struct xgene_enet_pdata *pdata); ++ void (*rx_enable)(struct xgene_enet_pdata *pdata); ++ void (*tx_disable)(struct xgene_enet_pdata *pdata); ++ void (*rx_disable)(struct xgene_enet_pdata *pdata); ++ void (*set_mac_addr)(struct xgene_enet_pdata *pdata); ++ void (*link_state)(struct work_struct *work); ++}; ++ ++struct xgene_port_ops { ++ void (*reset)(struct xgene_enet_pdata *pdata); ++ void (*cle_bypass)(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id); ++ void (*shutdown)(struct xgene_enet_pdata *pdata); ++}; ++ ++/* ethernet private data */ ++struct xgene_enet_pdata { ++ struct net_device *ndev; ++ struct mii_bus *mdio_bus; ++ struct phy_device *phy_dev; ++ int phy_speed; ++ struct clk *clk; ++ struct platform_device *pdev; ++ struct xgene_enet_desc_ring *tx_ring; ++ struct xgene_enet_desc_ring *rx_ring; ++ char *dev_name; ++ u32 rx_buff_cnt; ++ u32 tx_qcnt_hi; ++ u32 cp_qcnt_hi; ++ u32 cp_qcnt_low; ++ u32 rx_irq; ++ void __iomem *eth_csr_addr; ++ void __iomem *eth_ring_if_addr; ++ void __iomem *eth_diag_csr_addr; ++ void __iomem *mcx_mac_addr; ++ void __iomem *mcx_mac_csr_addr; ++ void __iomem *base_addr; ++ void __iomem *ring_csr_addr; ++ void __iomem *ring_cmd_addr; ++ int phy_mode; ++ enum xgene_enet_rm rm; ++ struct rtnl_link_stats64 stats; ++ struct xgene_mac_ops *mac_ops; ++ struct xgene_port_ops *port_ops; ++ struct delayed_work link_work; ++}; ++ ++struct xgene_indirect_ctl { ++ void __iomem *addr; ++ void __iomem *ctl; ++ void __iomem *cmd; ++ void __iomem *cmd_done; ++}; ++ ++/* Set the specified value into a bit-field defined by its starting position ++ * and length within a single u64. ++ */ ++static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) ++{ ++ return (val & ((1ULL << len) - 1)) << pos; ++} ++ ++#define SET_VAL(field, val) \ ++ xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) ++ ++#define SET_BIT(field) \ ++ xgene_enet_set_field_value(field ## _POS, 1, 1) ++ ++/* Get the value from a bit-field defined by its starting position ++ * and length within the specified u64. ++ */ ++static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) ++{ ++ return (src >> pos) & ((1ULL << len) - 1); ++} ++ ++#define GET_VAL(field, src) \ ++ xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) ++ ++static inline struct device *ndev_to_dev(struct net_device *ndev) ++{ ++ return ndev->dev.parent; ++} ++ ++void xgene_enet_set_ethtool_ops(struct net_device *netdev); ++ ++#endif /* __XGENE_ENET_MAIN_H__ */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +new file mode 100644 +index 0000000..e6d24c2 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.c +@@ -0,0 +1,389 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++#include "xgene_enet_sgmac.h" ++ ++static void xgene_enet_wr_csr(struct xgene_enet_pdata *p, u32 offset, u32 val) ++{ ++ iowrite32(val, p->eth_csr_addr + offset); ++} ++ ++static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *p, ++ u32 offset, u32 val) ++{ ++ iowrite32(val, p->eth_ring_if_addr + offset); ++} ++ ++static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *p, ++ u32 offset, u32 val) ++{ ++ iowrite32(val, p->eth_diag_csr_addr + offset); ++} ++ ++static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl, ++ u32 wr_addr, u32 wr_data) ++{ ++ int i; ++ ++ iowrite32(wr_addr, ctl->addr); ++ iowrite32(wr_data, ctl->ctl); ++ iowrite32(XGENE_ENET_WR_CMD, ctl->cmd); ++ ++ /* wait for write command to complete */ ++ for (i = 0; i < 10; i++) { ++ if (ioread32(ctl->cmd_done)) { ++ iowrite32(0, ctl->cmd); ++ return true; ++ } ++ udelay(1); ++ } ++ ++ return false; ++} ++ ++static void xgene_enet_wr_mac(struct xgene_enet_pdata *p, ++ u32 wr_addr, u32 wr_data) ++{ ++ struct xgene_indirect_ctl ctl = { ++ .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, ++ .ctl = p->mcx_mac_addr + MAC_WRITE_REG_OFFSET, ++ .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, ++ .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET ++ }; ++ ++ if (!xgene_enet_wr_indirect(&ctl, wr_addr, wr_data)) ++ netdev_err(p->ndev, "mac write failed, addr: %04x\n", wr_addr); ++} ++ ++static u32 xgene_enet_rd_csr(struct xgene_enet_pdata *p, u32 offset) ++{ ++ return ioread32(p->eth_csr_addr + offset); ++} ++ ++static u32 xgene_enet_rd_diag_csr(struct xgene_enet_pdata *p, u32 offset) ++{ ++ return ioread32(p->eth_diag_csr_addr + offset); ++} ++ ++static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr) ++{ ++ u32 rd_data; ++ int i; ++ ++ iowrite32(rd_addr, ctl->addr); ++ iowrite32(XGENE_ENET_RD_CMD, ctl->cmd); ++ ++ /* wait for read command to complete */ ++ for (i = 0; i < 10; i++) { ++ if (ioread32(ctl->cmd_done)) { ++ rd_data = ioread32(ctl->ctl); ++ iowrite32(0, ctl->cmd); ++ ++ return rd_data; ++ } ++ udelay(1); ++ } ++ ++ pr_err("%s: mac read failed, addr: %04x\n", __func__, rd_addr); ++ ++ return 0; ++} ++ ++static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr) ++{ ++ struct xgene_indirect_ctl ctl = { ++ .addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET, ++ .ctl = p->mcx_mac_addr + MAC_READ_REG_OFFSET, ++ .cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET, ++ .cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET ++ }; ++ ++ return xgene_enet_rd_indirect(&ctl, rd_addr); ++} ++ ++static int xgene_enet_ecc_init(struct xgene_enet_pdata *p) ++{ ++ struct net_device *ndev = p->ndev; ++ u32 data; ++ int i; ++ ++ xgene_enet_wr_diag_csr(p, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0); ++ for (i = 0; i < 10 && data != ~0U ; i++) { ++ usleep_range(100, 110); ++ data = xgene_enet_rd_diag_csr(p, ENET_BLOCK_MEM_RDY_ADDR); ++ } ++ ++ if (data != ~0U) { ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p) ++{ ++ u32 val = 0xffffffff; ++ ++ xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQASSOC_ADDR, val); ++ xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPQASSOC_ADDR, val); ++} ++ ++static void xgene_mii_phy_write(struct xgene_enet_pdata *p, u8 phy_id, ++ u32 reg, u16 data) ++{ ++ u32 addr, wr_data, done; ++ int i; ++ ++ addr = PHY_ADDR(phy_id) | REG_ADDR(reg); ++ xgene_enet_wr_mac(p, MII_MGMT_ADDRESS_ADDR, addr); ++ ++ wr_data = PHY_CONTROL(data); ++ xgene_enet_wr_mac(p, MII_MGMT_CONTROL_ADDR, wr_data); ++ ++ for (i = 0; i < 10; i++) { ++ done = xgene_enet_rd_mac(p, MII_MGMT_INDICATORS_ADDR); ++ if (!(done & BUSY_MASK)) ++ return; ++ usleep_range(10, 20); ++ } ++ ++ netdev_err(p->ndev, "MII_MGMT write failed\n"); ++} ++ ++static u32 xgene_mii_phy_read(struct xgene_enet_pdata *p, u8 phy_id, u32 reg) ++{ ++ u32 addr, data, done; ++ int i; ++ ++ addr = PHY_ADDR(phy_id) | REG_ADDR(reg); ++ xgene_enet_wr_mac(p, MII_MGMT_ADDRESS_ADDR, addr); ++ xgene_enet_wr_mac(p, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); ++ ++ for (i = 0; i < 10; i++) { ++ done = xgene_enet_rd_mac(p, MII_MGMT_INDICATORS_ADDR); ++ if (!(done & BUSY_MASK)) { ++ data = xgene_enet_rd_mac(p, MII_MGMT_STATUS_ADDR); ++ xgene_enet_wr_mac(p, MII_MGMT_COMMAND_ADDR, 0); ++ ++ return data; ++ } ++ usleep_range(10, 20); ++ } ++ ++ netdev_err(p->ndev, "MII_MGMT read failed\n"); ++ ++ return 0; ++} ++ ++static void xgene_sgmac_reset(struct xgene_enet_pdata *p) ++{ ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, SOFT_RESET1); ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, 0); ++} ++ ++static void xgene_sgmac_set_mac_addr(struct xgene_enet_pdata *p) ++{ ++ u32 addr0, addr1; ++ u8 *dev_addr = p->ndev->dev_addr; ++ ++ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | ++ (dev_addr[1] << 8) | dev_addr[0]; ++ xgene_enet_wr_mac(p, STATION_ADDR0_ADDR, addr0); ++ ++ addr1 = xgene_enet_rd_mac(p, STATION_ADDR1_ADDR); ++ addr1 |= (dev_addr[5] << 24) | (dev_addr[4] << 16); ++ xgene_enet_wr_mac(p, STATION_ADDR1_ADDR, addr1); ++} ++ ++static u32 xgene_enet_link_status(struct xgene_enet_pdata *p) ++{ ++ u32 data; ++ ++ data = xgene_mii_phy_read(p, INT_PHY_ADDR, ++ SGMII_BASE_PAGE_ABILITY_ADDR >> 2); ++ ++ return data & LINK_UP; ++} ++ ++static void xgene_sgmac_init(struct xgene_enet_pdata *p) ++{ ++ u32 data, loop = 10; ++ ++ xgene_sgmac_reset(p); ++ ++ /* Enable auto-negotiation */ ++ xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_CONTROL_ADDR >> 2, 0x1000); ++ xgene_mii_phy_write(p, INT_PHY_ADDR, SGMII_TBI_CONTROL_ADDR >> 2, 0); ++ ++ while (loop--) { ++ data = xgene_mii_phy_read(p, INT_PHY_ADDR, ++ SGMII_STATUS_ADDR >> 2); ++ if ((data & AUTO_NEG_COMPLETE) && (data & LINK_STATUS)) ++ break; ++ usleep_range(10, 20); ++ } ++ if (!(data & AUTO_NEG_COMPLETE) || !(data & LINK_STATUS)) ++ netdev_err(p->ndev, "Auto-negotiation failed\n"); ++ ++ data = xgene_enet_rd_mac(p, MAC_CONFIG_2_ADDR); ++ ENET_INTERFACE_MODE2_SET(&data, 2); ++ xgene_enet_wr_mac(p, MAC_CONFIG_2_ADDR, data | FULL_DUPLEX2); ++ xgene_enet_wr_mac(p, INTERFACE_CONTROL_ADDR, ENET_GHD_MODE); ++ ++ data = xgene_enet_rd_csr(p, ENET_SPARE_CFG_REG_ADDR); ++ data |= MPA_IDLE_WITH_QMI_EMPTY; ++ xgene_enet_wr_csr(p, ENET_SPARE_CFG_REG_ADDR, data); ++ ++ xgene_sgmac_set_mac_addr(p); ++ ++ data = xgene_enet_rd_csr(p, DEBUG_REG_ADDR); ++ data |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; ++ xgene_enet_wr_csr(p, DEBUG_REG_ADDR, data); ++ ++ /* Adjust MDC clock frequency */ ++ data = xgene_enet_rd_mac(p, MII_MGMT_CONFIG_ADDR); ++ MGMT_CLOCK_SEL_SET(&data, 7); ++ xgene_enet_wr_mac(p, MII_MGMT_CONFIG_ADDR, data); ++ ++ /* Enable drop if bufpool not available */ ++ data = xgene_enet_rd_csr(p, RSIF_CONFIG_REG_ADDR); ++ data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; ++ xgene_enet_wr_csr(p, RSIF_CONFIG_REG_ADDR, data); ++ ++ /* Rtype should be copied from FP */ ++ xgene_enet_wr_csr(p, RSIF_RAM_DBG_REG0_ADDR, 0); ++ ++ /* Bypass traffic gating */ ++ xgene_enet_wr_csr(p, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); ++ xgene_enet_wr_csr(p, CFG_BYPASS_ADDR, RESUME_TX); ++ xgene_enet_wr_csr(p, SG_RX_DV_GATE_REG_0_ADDR, RESUME_RX0); ++} ++ ++static void xgene_sgmac_rxtx(struct xgene_enet_pdata *p, u32 bits, bool set) ++{ ++ u32 data; ++ ++ data = xgene_enet_rd_mac(p, MAC_CONFIG_1_ADDR); ++ ++ if (set) ++ data |= bits; ++ else ++ data &= ~bits; ++ ++ xgene_enet_wr_mac(p, MAC_CONFIG_1_ADDR, data); ++} ++ ++static void xgene_sgmac_rx_enable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, RX_EN, true); ++} ++ ++static void xgene_sgmac_tx_enable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, TX_EN, true); ++} ++ ++static void xgene_sgmac_rx_disable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, RX_EN, false); ++} ++ ++static void xgene_sgmac_tx_disable(struct xgene_enet_pdata *p) ++{ ++ xgene_sgmac_rxtx(p, TX_EN, false); ++} ++ ++static void xgene_enet_reset(struct xgene_enet_pdata *p) ++{ ++ clk_prepare_enable(p->clk); ++ clk_disable_unprepare(p->clk); ++ clk_prepare_enable(p->clk); ++ ++ xgene_enet_ecc_init(p); ++ xgene_enet_config_ring_if_assoc(p); ++} ++ ++static void xgene_enet_cle_bypass(struct xgene_enet_pdata *p, ++ u32 dst_ring_num, u16 bufpool_id) ++{ ++ u32 data, fpsel; ++ ++ data = CFG_CLE_BYPASS_EN0; ++ xgene_enet_wr_csr(p, CLE_BYPASS_REG0_0_ADDR, data); ++ ++ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; ++ data = CFG_CLE_DSTQID0(dst_ring_num) | CFG_CLE_FPSEL0(fpsel); ++ xgene_enet_wr_csr(p, CLE_BYPASS_REG1_0_ADDR, data); ++} ++ ++static void xgene_enet_shutdown(struct xgene_enet_pdata *p) ++{ ++ clk_disable_unprepare(p->clk); ++} ++ ++static void xgene_enet_link_state(struct work_struct *work) ++{ ++ struct xgene_enet_pdata *p = container_of(to_delayed_work(work), ++ struct xgene_enet_pdata, link_work); ++ struct net_device *ndev = p->ndev; ++ u32 link, poll_interval; ++ ++ link = xgene_enet_link_status(p); ++ if (link) { ++ if (!netif_carrier_ok(ndev)) { ++ netif_carrier_on(ndev); ++ xgene_sgmac_init(p); ++ xgene_sgmac_rx_enable(p); ++ xgene_sgmac_tx_enable(p); ++ netdev_info(ndev, "Link is Up - 1Gbps\n"); ++ } ++ poll_interval = PHY_POLL_LINK_ON; ++ } else { ++ if (netif_carrier_ok(ndev)) { ++ xgene_sgmac_rx_disable(p); ++ xgene_sgmac_tx_disable(p); ++ netif_carrier_off(ndev); ++ netdev_info(ndev, "Link is Down\n"); ++ } ++ poll_interval = PHY_POLL_LINK_OFF; ++ } ++ ++ schedule_delayed_work(&p->link_work, poll_interval); ++} ++ ++struct xgene_mac_ops xgene_sgmac_ops = { ++ .init = xgene_sgmac_init, ++ .reset = xgene_sgmac_reset, ++ .rx_enable = xgene_sgmac_rx_enable, ++ .tx_enable = xgene_sgmac_tx_enable, ++ .rx_disable = xgene_sgmac_rx_disable, ++ .tx_disable = xgene_sgmac_tx_disable, ++ .set_mac_addr = xgene_sgmac_set_mac_addr, ++ .link_state = xgene_enet_link_state ++}; ++ ++struct xgene_port_ops xgene_sgport_ops = { ++ .reset = xgene_enet_reset, ++ .cle_bypass = xgene_enet_cle_bypass, ++ .shutdown = xgene_enet_shutdown ++}; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +new file mode 100644 +index 0000000..de43246 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_sgmac.h +@@ -0,0 +1,41 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __XGENE_ENET_SGMAC_H__ ++#define __XGENE_ENET_SGMAC_H__ ++ ++#define PHY_ADDR(src) (((src)<<8) & GENMASK(12, 8)) ++#define REG_ADDR(src) ((src) & GENMASK(4, 0)) ++#define PHY_CONTROL(src) ((src) & GENMASK(15, 0)) ++#define INT_PHY_ADDR 0x1e ++#define SGMII_TBI_CONTROL_ADDR 0x44 ++#define SGMII_CONTROL_ADDR 0x00 ++#define SGMII_STATUS_ADDR 0x04 ++#define SGMII_BASE_PAGE_ABILITY_ADDR 0x14 ++#define AUTO_NEG_COMPLETE BIT(5) ++#define LINK_STATUS BIT(2) ++#define LINK_UP BIT(15) ++#define MPA_IDLE_WITH_QMI_EMPTY BIT(12) ++#define SG_RX_DV_GATE_REG_0_ADDR 0x0dfc ++ ++extern struct xgene_mac_ops xgene_sgmac_ops; ++extern struct xgene_port_ops xgene_sgport_ops; ++ ++#endif /* __XGENE_ENET_SGMAC_H__ */ +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +new file mode 100644 +index 0000000..67d0720 +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +@@ -0,0 +1,332 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include "xgene_enet_main.h" ++#include "xgene_enet_hw.h" ++#include "xgene_enet_xgmac.h" ++ ++static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_ring_if_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ iowrite32(val, addr); ++} ++ ++static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 wr_addr, u32 wr_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(wr_addr, addr); ++ iowrite32(wr_data, wr); ++ iowrite32(XGENE_ENET_WR_CMD, cmd); ++ ++ /* wait for write command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, ++ u32 wr_addr, u32 wr_data) ++{ ++ void __iomem *addr, *wr, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) ++ netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", ++ wr_addr); ++} ++ ++static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, ++ u32 offset, u32 *val) ++{ ++ void __iomem *addr = pdata->eth_diag_csr_addr + offset; ++ ++ *val = ioread32(addr); ++} ++ ++static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, ++ void __iomem *cmd, void __iomem *cmd_done, ++ u32 rd_addr, u32 *rd_data) ++{ ++ u32 done; ++ u8 wait = 10; ++ ++ iowrite32(rd_addr, addr); ++ iowrite32(XGENE_ENET_RD_CMD, cmd); ++ ++ /* wait for read command to complete */ ++ while (!(done = ioread32(cmd_done)) && wait--) ++ udelay(1); ++ ++ if (!done) ++ return false; ++ ++ *rd_data = ioread32(rd); ++ iowrite32(0, cmd); ++ ++ return true; ++} ++ ++static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, ++ u32 rd_addr, u32 *rd_data) ++{ ++ void __iomem *addr, *rd, *cmd, *cmd_done; ++ ++ addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; ++ rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; ++ cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; ++ cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; ++ ++ if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) ++ netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", ++ rd_addr); ++} ++ ++static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) ++{ ++ struct net_device *ndev = pdata->ndev; ++ u32 data; ++ u8 wait = 10; ++ ++ xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); ++ do { ++ usleep_range(100, 110); ++ xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); ++ } while ((data != 0xffffffff) && wait--); ++ ++ if (data != 0xffffffff) { ++ netdev_err(ndev, "Failed to release memory from shutdown\n"); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) ++{ ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, 0); ++ xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, 0); ++} ++ ++static void xgene_xgmac_reset(struct xgene_enet_pdata *pdata) ++{ ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, HSTMACRST); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_0, 0); ++} ++ ++static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) ++{ ++ u32 addr0, addr1; ++ u8 *dev_addr = pdata->ndev->dev_addr; ++ ++ addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | ++ (dev_addr[1] << 8) | dev_addr[0]; ++ addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); ++ ++ xgene_enet_wr_mac(pdata, HSTMACADR_LSW_ADDR, addr0); ++ xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); ++} ++ ++static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_csr(pdata, XG_LINK_STATUS_ADDR, &data); ++ ++ return data; ++} ++ ++static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_xgmac_reset(pdata); ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ data |= HSTPPEN; ++ data &= ~HSTLENCHK; ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); ++ ++ xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600); ++ xgene_xgmac_set_mac_addr(pdata); ++ ++ xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); ++ data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; ++ xgene_enet_wr_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, data); ++ ++ xgene_enet_wr_csr(pdata, XG_CFG_BYPASS_ADDR, RESUME_TX); ++ xgene_enet_wr_csr(pdata, XGENET_RX_DV_GATE_REG_0_ADDR, 0); ++ xgene_enet_rd_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, &data); ++ data |= BIT(12); ++ xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_ADDR, data); ++ xgene_enet_wr_csr(pdata, XG_ENET_SPARE_CFG_REG_1_ADDR, 0x82); ++} ++ ++static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN); ++} ++ ++static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN); ++} ++ ++static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN); ++} ++ ++static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata) ++{ ++ u32 data; ++ ++ xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data); ++ xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN); ++} ++ ++static void xgene_enet_reset(struct xgene_enet_pdata *pdata) ++{ ++ clk_prepare_enable(pdata->clk); ++ clk_disable_unprepare(pdata->clk); ++ clk_prepare_enable(pdata->clk); ++ ++ xgene_enet_ecc_init(pdata); ++ xgene_enet_config_ring_if_assoc(pdata); ++} ++ ++static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata, ++ u32 dst_ring_num, u16 bufpool_id) ++{ ++ u32 cb, fpsel; ++ ++ xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG0_ADDR, &cb); ++ cb |= CFG_CLE_BYPASS_EN0; ++ CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); ++ xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG0_ADDR, cb); ++ ++ fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; ++ xgene_enet_rd_csr(pdata, XCLE_BYPASS_REG1_ADDR, &cb); ++ CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); ++ CFG_CLE_FPSEL0_SET(&cb, fpsel); ++ xgene_enet_wr_csr(pdata, XCLE_BYPASS_REG1_ADDR, cb); ++} ++ ++static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata) ++{ ++ clk_disable_unprepare(pdata->clk); ++} ++ ++static void xgene_enet_link_state(struct work_struct *work) ++{ ++ struct xgene_enet_pdata *pdata = container_of(to_delayed_work(work), ++ struct xgene_enet_pdata, link_work); ++ struct net_device *ndev = pdata->ndev; ++ u32 link_status, poll_interval; ++ ++ link_status = xgene_enet_link_status(pdata); ++ if (link_status) { ++ if (!netif_carrier_ok(ndev)) { ++ netif_carrier_on(ndev); ++ xgene_xgmac_init(pdata); ++ xgene_xgmac_rx_enable(pdata); ++ xgene_xgmac_tx_enable(pdata); ++ netdev_info(ndev, "Link is Up - 10Gbps\n"); ++ } ++ poll_interval = PHY_POLL_LINK_ON; ++ } else { ++ if (netif_carrier_ok(ndev)) { ++ xgene_xgmac_rx_disable(pdata); ++ xgene_xgmac_tx_disable(pdata); ++ netif_carrier_off(ndev); ++ netdev_info(ndev, "Link is Down\n"); ++ } ++ poll_interval = PHY_POLL_LINK_OFF; ++ } ++ ++ schedule_delayed_work(&pdata->link_work, poll_interval); ++} ++ ++struct xgene_mac_ops xgene_xgmac_ops = { ++ .init = xgene_xgmac_init, ++ .reset = xgene_xgmac_reset, ++ .rx_enable = xgene_xgmac_rx_enable, ++ .tx_enable = xgene_xgmac_tx_enable, ++ .rx_disable = xgene_xgmac_rx_disable, ++ .tx_disable = xgene_xgmac_tx_disable, ++ .set_mac_addr = xgene_xgmac_set_mac_addr, ++ .link_state = xgene_enet_link_state ++}; ++ ++struct xgene_port_ops xgene_xgport_ops = { ++ .reset = xgene_enet_reset, ++ .cle_bypass = xgene_enet_xgcle_bypass, ++ .shutdown = xgene_enet_shutdown, ++}; +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +new file mode 100644 +index 0000000..5a5296a +--- /dev/null ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +@@ -0,0 +1,53 @@ ++/* Applied Micro X-Gene SoC Ethernet Driver ++ * ++ * Copyright (c) 2014, Applied Micro Circuits Corporation ++ * Authors: Iyappan Subramanian <isubramanian@apm.com> ++ * Keyur Chudgar <kchudgar@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef __XGENE_ENET_XGMAC_H__ ++#define __XGENE_ENET_XGMAC_H__ ++ ++#define BLOCK_AXG_MAC_OFFSET 0x0800 ++#define BLOCK_AXG_MAC_CSR_OFFSET 0x2000 ++ ++#define AXGMAC_CONFIG_0 0x0000 ++#define AXGMAC_CONFIG_1 0x0004 ++#define HSTMACRST BIT(31) ++#define HSTTCTLEN BIT(31) ++#define HSTTFEN BIT(30) ++#define HSTRCTLEN BIT(29) ++#define HSTRFEN BIT(28) ++#define HSTPPEN BIT(7) ++#define HSTDRPLT64 BIT(5) ++#define HSTLENCHK BIT(3) ++#define HSTMACADR_LSW_ADDR 0x0010 ++#define HSTMACADR_MSW_ADDR 0x0014 ++#define HSTMAXFRAME_LENGTH_ADDR 0x0020 ++ ++#define XG_RSIF_CONFIG_REG_ADDR 0x00a0 ++#define XCLE_BYPASS_REG0_ADDR 0x0160 ++#define XCLE_BYPASS_REG1_ADDR 0x0164 ++#define XG_CFG_BYPASS_ADDR 0x0204 ++#define XG_LINK_STATUS_ADDR 0x0228 ++#define XG_ENET_SPARE_CFG_REG_ADDR 0x040c ++#define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 ++#define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 ++ ++extern struct xgene_mac_ops xgene_xgmac_ops; ++extern struct xgene_port_ops xgene_xgport_ops; ++ ++#endif /* __XGENE_ENET_XGMAC_H__ */ +-- +2.1.0 + diff --git a/patches.arch/arm64-0012-ahci_xgene-Skip-the-PHY-and-clock-initialization-if-.patch b/patches.arch/arm64-0012-ahci_xgene-Skip-the-PHY-and-clock-initialization-if-.patch new file mode 100644 index 0000000..2f8d105 --- /dev/null +++ b/patches.arch/arm64-0012-ahci_xgene-Skip-the-PHY-and-clock-initialization-if-.patch @@ -0,0 +1,63 @@ +From f922d88854081d8f894f8c1767b0bded2be04342 Mon Sep 17 00:00:00 2001 +From: Suman Tripathi <stripathi@apm.com> +Date: Thu, 28 Aug 2014 14:51:21 +0530 +Subject: [PATCH 12/38] ahci_xgene: Skip the PHY and clock initialization if + already configured by the firmware. +Git-commit: 0bed13bebd6c99d097796d2ca6c4f10fb5b2eabc +Patch-mainline: v3.17-rc5 +References: bnc#902632 + +This patch implements the feature to skip the PHY and clock +initialization if it is already configured by the firmware. + +Signed-off-by: Loc Ho <lho@apm.com> +Signed-off-by: Suman Tripathi <stripathi@apm.com> +Signed-off-by: Tejun Heo <tj@kernel.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/ata/ahci_xgene.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c +index 10d5246..db2fa11 100644 +--- a/drivers/ata/ahci_xgene.c ++++ b/drivers/ata/ahci_xgene.c +@@ -142,6 +142,14 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc) + return rc; + } + ++static bool xgene_ahci_is_memram_inited(struct xgene_ahci_context *ctx) ++{ ++ void __iomem *diagcsr = ctx->csr_diag; ++ ++ return (readl(diagcsr + CFG_MEM_RAM_SHUTDOWN) == 0 && ++ readl(diagcsr + BLOCK_MEM_RDY) == 0xFFFFFFFF); ++} ++ + /** + * xgene_ahci_read_id - Read ID data from the specified device + * @dev: device +@@ -461,6 +469,11 @@ static int xgene_ahci_probe(struct platform_device *pdev) + return -ENODEV; + } + ++ if (xgene_ahci_is_memram_inited(ctx)) { ++ dev_info(dev, "skip clock and PHY initialization\n"); ++ goto skip_clk_phy; ++ } ++ + /* Due to errata, HW requires full toggle transition */ + rc = ahci_platform_enable_clks(hpriv); + if (rc) +@@ -484,6 +497,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) + goto disable_resources; + } + ++skip_clk_phy: + hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; + + rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, +-- +2.1.0 + diff --git a/patches.arch/arm64-0013-arm64-adjust-el0_sync-so-that-a-function-can-be-call.patch b/patches.arch/arm64-0013-arm64-adjust-el0_sync-so-that-a-function-can-be-call.patch new file mode 100644 index 0000000..0949313 --- /dev/null +++ b/patches.arch/arm64-0013-arm64-adjust-el0_sync-so-that-a-function-can-be-call.patch @@ -0,0 +1,128 @@ +From 99f01798c79c8b0b82f57c0dae94c4a5ef2ca397 Mon Sep 17 00:00:00 2001 +From: Larry Bassel <larry.bassel@linaro.org> +Date: Fri, 30 May 2014 20:34:14 +0100 +Subject: [PATCH 13/38] arm64: adjust el0_sync so that a function can be called +Git-commit: 6ab6463aeb5fbc75fa3227befb508fc33b34dbf1 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +To implement the context tracker properly on arm64, +a function call needs to be made after debugging and +interrupts are turned on, but before the lr is changed +to point to ret_to_user(). If the function call +is made after the lr is changed the function will not +return to the correct place. + +For similar reasons, defer the setting of x0 so that +it doesn't need to be saved around the function call +(save far_el1 in x26 temporarily instead). + +Acked-by: Will Deacon <will.deacon@arm.com> +Reviewed-by: Kevin Hilman <khilman@linaro.org> +Tested-by: Kevin Hilman <khilman@linaro.org> +Signed-off-by: Larry Bassel <larry.bassel@linaro.org> +Signed-off-by: Will Deacon <will.deacon@arm.com> +Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/kernel/entry.S | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S +index 9ce04ba..d7230bf 100644 +--- a/arch/arm64/kernel/entry.S ++++ b/arch/arm64/kernel/entry.S +@@ -353,7 +353,6 @@ el0_sync: + lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class + cmp x24, #ESR_EL1_EC_SVC64 // SVC in 64-bit state + b.eq el0_svc +- adr lr, ret_to_user + cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 + b.eq el0_da + cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 +@@ -382,7 +381,6 @@ el0_sync_compat: + lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class + cmp x24, #ESR_EL1_EC_SVC32 // SVC in 32-bit state + b.eq el0_svc_compat +- adr lr, ret_to_user + cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 + b.eq el0_da + cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 +@@ -425,22 +423,25 @@ el0_da: + /* + * Data abort handling + */ +- mrs x0, far_el1 +- bic x0, x0, #(0xff << 56) ++ mrs x26, far_el1 + // enable interrupts before calling the main handler + enable_dbg_and_irq ++ bic x0, x26, #(0xff << 56) + mov x1, x25 + mov x2, sp ++ adr lr, ret_to_user + b do_mem_abort + el0_ia: + /* + * Instruction abort handling + */ +- mrs x0, far_el1 ++ mrs x26, far_el1 + // enable interrupts before calling the main handler + enable_dbg_and_irq ++ mov x0, x26 + orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts + mov x2, sp ++ adr lr, ret_to_user + b do_mem_abort + el0_fpsimd_acc: + /* +@@ -449,6 +450,7 @@ el0_fpsimd_acc: + enable_dbg + mov x0, x25 + mov x1, sp ++ adr lr, ret_to_user + b do_fpsimd_acc + el0_fpsimd_exc: + /* +@@ -457,16 +459,19 @@ el0_fpsimd_exc: + enable_dbg + mov x0, x25 + mov x1, sp ++ adr lr, ret_to_user + b do_fpsimd_exc + el0_sp_pc: + /* + * Stack or PC alignment exception handling + */ +- mrs x0, far_el1 ++ mrs x26, far_el1 + // enable interrupts before calling the main handler + enable_dbg_and_irq ++ mov x0, x26 + mov x1, x25 + mov x2, sp ++ adr lr, ret_to_user + b do_sp_pc_abort + el0_undef: + /* +@@ -475,6 +480,7 @@ el0_undef: + // enable interrupts before calling the main handler + enable_dbg_and_irq + mov x0, sp ++ adr lr, ret_to_user + b do_undefinstr + el0_dbg: + /* +@@ -492,6 +498,7 @@ el0_inv: + mov x0, sp + mov x1, #BAD_SYNC + mrs x2, esr_el1 ++ adr lr, ret_to_user + b bad_mode + ENDPROC(el0_sync) + +-- +2.1.0 + diff --git a/patches.arch/arm64-0014-arm-arm64-KVM-Fix-and-refactor-unmap_range.patch b/patches.arch/arm64-0014-arm-arm64-KVM-Fix-and-refactor-unmap_range.patch new file mode 100644 index 0000000..8d59a1c --- /dev/null +++ b/patches.arch/arm64-0014-arm-arm64-KVM-Fix-and-refactor-unmap_range.patch @@ -0,0 +1,273 @@ +From b5c19db264bdef37f0ca63e40f2cc4d3b2521c4c Mon Sep 17 00:00:00 2001 +From: Christoffer Dall <christoffer.dall@linaro.org> +Date: Fri, 9 May 2014 23:31:31 +0200 +Subject: [PATCH 14/38] arm/arm64: KVM: Fix and refactor unmap_range +Git-commit: 4f853a714bf16338ff5261128e6c7ae2569e9505 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +unmap_range() was utterly broken, to quote Marc, and broke in all sorts +of situations. It was also quite complicated to follow and didn't +follow the usual scheme of having a separate iterating function for each +level of page tables. + +Address this by refactoring the code and introduce a pgd_clear() +function. + +Reviewed-by: Jungseok Lee <jays.lee@samsung.com> +Reviewed-by: Mario Smarduch <m.smarduch@samsung.com> +Acked-by: Marc Zyngier <marc.zyngier@arm.com> +Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm/include/asm/kvm_mmu.h | 12 +++ + arch/arm/kvm/mmu.c | 157 +++++++++++++++++++++------------------ + arch/arm64/include/asm/kvm_mmu.h | 15 ++++ + 3 files changed, 111 insertions(+), 73 deletions(-) + +diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h +index 77500b0..03a08bb 100644 +--- a/arch/arm/include/asm/kvm_mmu.h ++++ b/arch/arm/include/asm/kvm_mmu.h +@@ -128,6 +128,18 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd) + (__boundary - 1 < (end) - 1)? __boundary: (end); \ + }) + ++static inline bool kvm_page_empty(void *ptr) ++{ ++ struct page *ptr_page = virt_to_page(ptr); ++ return page_count(ptr_page) == 1; ++} ++ ++ ++#define kvm_pte_table_empty(ptep) kvm_page_empty(ptep) ++#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp) ++#define kvm_pud_table_empty(pudp) (0) ++ ++ + struct kvm; + + #define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) +diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c +index 16f8049..2336061 100644 +--- a/arch/arm/kvm/mmu.c ++++ b/arch/arm/kvm/mmu.c +@@ -90,104 +90,115 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) + return p; + } + +-static bool page_empty(void *ptr) ++static void clear_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr) + { +- struct page *ptr_page = virt_to_page(ptr); +- return page_count(ptr_page) == 1; ++ pud_t *pud_table __maybe_unused = pud_offset(pgd, 0); ++ pgd_clear(pgd); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ pud_free(NULL, pud_table); ++ put_page(virt_to_page(pgd)); + } + + static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) + { +- if (pud_huge(*pud)) { +- pud_clear(pud); +- kvm_tlb_flush_vmid_ipa(kvm, addr); +- } else { +- pmd_t *pmd_table = pmd_offset(pud, 0); +- pud_clear(pud); +- kvm_tlb_flush_vmid_ipa(kvm, addr); +- pmd_free(NULL, pmd_table); +- } ++ pmd_t *pmd_table = pmd_offset(pud, 0); ++ VM_BUG_ON(pud_huge(*pud)); ++ pud_clear(pud); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ pmd_free(NULL, pmd_table); + put_page(virt_to_page(pud)); + } + + static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) + { +- if (kvm_pmd_huge(*pmd)) { +- pmd_clear(pmd); +- kvm_tlb_flush_vmid_ipa(kvm, addr); +- } else { +- pte_t *pte_table = pte_offset_kernel(pmd, 0); +- pmd_clear(pmd); +- kvm_tlb_flush_vmid_ipa(kvm, addr); +- pte_free_kernel(NULL, pte_table); +- } ++ pte_t *pte_table = pte_offset_kernel(pmd, 0); ++ VM_BUG_ON(kvm_pmd_huge(*pmd)); ++ pmd_clear(pmd); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ pte_free_kernel(NULL, pte_table); + put_page(virt_to_page(pmd)); + } + +-static void clear_pte_entry(struct kvm *kvm, pte_t *pte, phys_addr_t addr) ++static void unmap_ptes(struct kvm *kvm, pmd_t *pmd, ++ phys_addr_t addr, phys_addr_t end) + { +- if (pte_present(*pte)) { +- kvm_set_pte(pte, __pte(0)); +- put_page(virt_to_page(pte)); +- kvm_tlb_flush_vmid_ipa(kvm, addr); +- } ++ phys_addr_t start_addr = addr; ++ pte_t *pte, *start_pte; ++ ++ start_pte = pte = pte_offset_kernel(pmd, addr); ++ do { ++ if (!pte_none(*pte)) { ++ kvm_set_pte(pte, __pte(0)); ++ put_page(virt_to_page(pte)); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ } ++ } while (pte++, addr += PAGE_SIZE, addr != end); ++ ++ if (kvm_pte_table_empty(start_pte)) ++ clear_pmd_entry(kvm, pmd, start_addr); + } + +-static void unmap_range(struct kvm *kvm, pgd_t *pgdp, +- unsigned long long start, u64 size) ++static void unmap_pmds(struct kvm *kvm, pud_t *pud, ++ phys_addr_t addr, phys_addr_t end) + { +- pgd_t *pgd; +- pud_t *pud; +- pmd_t *pmd; +- pte_t *pte; +- unsigned long long addr = start, end = start + size; +- u64 next; ++ phys_addr_t next, start_addr = addr; ++ pmd_t *pmd, *start_pmd; + +- while (addr < end) { +- pgd = pgdp + pgd_index(addr); +- pud = pud_offset(pgd, addr); +- pte = NULL; +- if (pud_none(*pud)) { +- addr = kvm_pud_addr_end(addr, end); +- continue; +- } +- +- if (pud_huge(*pud)) { +- /* +- * If we are dealing with a huge pud, just clear it and +- * move on. +- */ +- clear_pud_entry(kvm, pud, addr); +- addr = kvm_pud_addr_end(addr, end); +- continue; ++ start_pmd = pmd = pmd_offset(pud, addr); ++ do { ++ next = kvm_pmd_addr_end(addr, end); ++ if (!pmd_none(*pmd)) { ++ if (kvm_pmd_huge(*pmd)) { ++ pmd_clear(pmd); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ put_page(virt_to_page(pmd)); ++ } else { ++ unmap_ptes(kvm, pmd, addr, next); ++ } + } ++ } while (pmd++, addr = next, addr != end); + +- pmd = pmd_offset(pud, addr); +- if (pmd_none(*pmd)) { +- addr = kvm_pmd_addr_end(addr, end); +- continue; +- } ++ if (kvm_pmd_table_empty(start_pmd)) ++ clear_pud_entry(kvm, pud, start_addr); ++} + +- if (!kvm_pmd_huge(*pmd)) { +- pte = pte_offset_kernel(pmd, addr); +- clear_pte_entry(kvm, pte, addr); +- next = addr + PAGE_SIZE; +- } ++static void unmap_puds(struct kvm *kvm, pgd_t *pgd, ++ phys_addr_t addr, phys_addr_t end) ++{ ++ phys_addr_t next, start_addr = addr; ++ pud_t *pud, *start_pud; + +- /* +- * If the pmd entry is to be cleared, walk back up the ladder +- */ +- if (kvm_pmd_huge(*pmd) || (pte && page_empty(pte))) { +- clear_pmd_entry(kvm, pmd, addr); +- next = kvm_pmd_addr_end(addr, end); +- if (page_empty(pmd) && !page_empty(pud)) { +- clear_pud_entry(kvm, pud, addr); +- next = kvm_pud_addr_end(addr, end); ++ start_pud = pud = pud_offset(pgd, addr); ++ do { ++ next = kvm_pud_addr_end(addr, end); ++ if (!pud_none(*pud)) { ++ if (pud_huge(*pud)) { ++ pud_clear(pud); ++ kvm_tlb_flush_vmid_ipa(kvm, addr); ++ put_page(virt_to_page(pud)); ++ } else { ++ unmap_pmds(kvm, pud, addr, next); + } + } ++ } while (pud++, addr = next, addr != end); + +- addr = next; +- } ++ if (kvm_pud_table_empty(start_pud)) ++ clear_pgd_entry(kvm, pgd, start_addr); ++} ++ ++ ++static void unmap_range(struct kvm *kvm, pgd_t *pgdp, ++ phys_addr_t start, u64 size) ++{ ++ pgd_t *pgd; ++ phys_addr_t addr = start, end = start + size; ++ phys_addr_t next; ++ ++ pgd = pgdp + pgd_index(addr); ++ do { ++ next = kvm_pgd_addr_end(addr, end); ++ unmap_puds(kvm, pgd, addr, next); ++ } while (pgd++, addr = next, addr != end); + } + + static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd, +diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h +index ff97a1f..1c70b2f 100644 +--- a/arch/arm64/include/asm/kvm_mmu.h ++++ b/arch/arm64/include/asm/kvm_mmu.h +@@ -125,6 +125,21 @@ static inline void kvm_set_s2pmd_writable(pmd_t *pmd) + #define kvm_pud_addr_end(addr, end) pud_addr_end(addr, end) + #define kvm_pmd_addr_end(addr, end) pmd_addr_end(addr, end) + ++static inline bool kvm_page_empty(void *ptr) ++{ ++ struct page *ptr_page = virt_to_page(ptr); ++ return page_count(ptr_page) == 1; ++} ++ ++#define kvm_pte_table_empty(ptep) kvm_page_empty(ptep) ++#ifndef CONFIG_ARM64_64K_PAGES ++#define kvm_pmd_table_empty(pmdp) kvm_page_empty(pmdp) ++#else ++#define kvm_pmd_table_empty(pmdp) (0) ++#endif ++#define kvm_pud_table_empty(pudp) (0) ++ ++ + struct kvm; + + #define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l)) +-- +2.1.0 + diff --git a/patches.arch/arm64-0015-arm64-fpsimd-fix-a-typo-in-fpsimd_save_partial_state.patch b/patches.arch/arm64-0015-arm64-fpsimd-fix-a-typo-in-fpsimd_save_partial_state.patch new file mode 100644 index 0000000..a7b0143 --- /dev/null +++ b/patches.arch/arm64-0015-arm64-fpsimd-fix-a-typo-in-fpsimd_save_partial_state.patch @@ -0,0 +1,39 @@ +From 74c686e673f0472523e1ff9c8f342ae2d2df12a7 Mon Sep 17 00:00:00 2001 +From: "byungchul.park" <byungchul.park@lge.com> +Date: Thu, 31 Jul 2014 11:05:36 +0100 +Subject: [PATCH 15/38] arm64: fpsimd: fix a typo in fpsimd_save_partial_state + ENDPROC +Git-commit: e4aa297a490e16c44dc464361daab145a7c451c5 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +Commit 190f1ca85d07 ("arm64: add support for kernel mode NEON in interrupt +context") introduced a typing error in fpsimd_save_partial_state ENDPROC. + +This patch fixes the typing error. + +Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Signed-off-by: byungchul.park <byungchul.park@lge.com> +Signed-off-by: Will Deacon <will.deacon@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/kernel/entry-fpsimd.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S +index d358cca..c44a82f 100644 +--- a/arch/arm64/kernel/entry-fpsimd.S ++++ b/arch/arm64/kernel/entry-fpsimd.S +@@ -52,7 +52,7 @@ ENDPROC(fpsimd_load_state) + ENTRY(fpsimd_save_partial_state) + fpsimd_save_partial x0, 1, 8, 9 + ret +-ENDPROC(fpsimd_load_partial_state) ++ENDPROC(fpsimd_save_partial_state) + + /* + * Load the bottom n FP registers. +-- +2.1.0 + diff --git a/patches.arch/arm64-0016-arm64-fix-bug-for-reloading-FPSIMD-state-after-cpu-p.patch b/patches.arch/arm64-0016-arm64-fix-bug-for-reloading-FPSIMD-state-after-cpu-p.patch new file mode 100644 index 0000000..8042bfe --- /dev/null +++ b/patches.arch/arm64-0016-arm64-fix-bug-for-reloading-FPSIMD-state-after-cpu-p.patch @@ -0,0 +1,45 @@ +From f0bb87c55a0036ea9d5e52f789cc16154000d52a Mon Sep 17 00:00:00 2001 +From: Leo Yan <leoy@marvell.com> +Date: Mon, 1 Sep 2014 11:09:51 +0800 +Subject: [PATCH 16/38] arm64: fix bug for reloading FPSIMD state after cpu + power off +Git-commit: 7c68a9cc040216c902f93f9c80305df55d9beff7 +Patch-mainline: v3.17-rc5 +References: bnc#902632 + +Now arm64 defers reloading FPSIMD state, but this optimization also +introduces the bug after cpu resume back from low power mode. + +The reason is after the cpu has been powered off, s/w need set the +cpu's fpsimd_last_state to NULL so that it will force to reload +FPSIMD state for the thread, otherwise there has the chance to meet +the condition for both the task's fpsimd_state.cpu field contains the +id of the current cpu, and the cpu's fpsimd_last_state per-cpu variable +points to the task's fpsimd_state, so finally kernel will skip to reload +the context during it return back to userland. + +Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Leo Yan <leoy@marvell.com> +Signed-off-by: Will Deacon <will.deacon@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/kernel/fpsimd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c +index ad8aebb..3dca156 100644 +--- a/arch/arm64/kernel/fpsimd.c ++++ b/arch/arm64/kernel/fpsimd.c +@@ -270,6 +270,7 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self, + case CPU_PM_ENTER: + if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE)) + fpsimd_save_state(¤t->thread.fpsimd_state); ++ this_cpu_write(fpsimd_last_state, NULL); + break; + case CPU_PM_EXIT: + if (current->mm) +-- +2.1.0 + diff --git a/patches.arch/arm64-0017-ahci-xgene-Remove-logic-to-set-64-bit-DMA-mask.patch b/patches.arch/arm64-0017-ahci-xgene-Remove-logic-to-set-64-bit-DMA-mask.patch new file mode 100644 index 0000000..b1596d7 --- /dev/null +++ b/patches.arch/arm64-0017-ahci-xgene-Remove-logic-to-set-64-bit-DMA-mask.patch @@ -0,0 +1,48 @@ +From c97b64bbc2dc4843bbdcd430ac582634c6b52843 Mon Sep 17 00:00:00 2001 +From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Date: Thu, 12 Jun 2014 12:40:24 -0500 +Subject: [PATCH 17/38] ahci/xgene: Remove logic to set 64-bit DMA mask +Git-commit: be64beb40df808385f7883d2e6f01ff7c79eeae4 +Patch-mainline: v3.17-rc1 +References: bnc#902632 + +Instead of doing the check here, this should be handled +in the common AHCI platform code. + +Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Suggested-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> +Cc: Loc Ho <lho@apm.com> +Cc: Tuan Phan <tphan@apm.com> +Cc: Suman Triphati <stripathi@apm.com> +Signed-off-by: Tejun Heo <tj@kernel.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/ata/ahci_xgene.c | 10 ---------- + drivers/ata/libahci_platform.c | 5 ++--- + 2 files changed, 2 insertions(+), 13 deletions(-) + +diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c +index db2fa11..d758735 100644 +--- a/drivers/ata/ahci_xgene.c ++++ b/drivers/ata/ahci_xgene.c +@@ -487,16 +487,6 @@ static int xgene_ahci_probe(struct platform_device *pdev) + /* Configure the host controller */ + xgene_ahci_hw_init(hpriv); + +- /* +- * Setup DMA mask. This is preliminary until the DMA range is sorted +- * out. +- */ +- rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); +- if (rc) { +- dev_err(dev, "Unable to set dma mask\n"); +- goto disable_resources; +- } +- + skip_clk_phy: + hflags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; + +-- +2.1.0 + diff --git a/patches.arch/arm64-0018-arm64-dts-Add-X-Gene-reboot-driver-dts-node.patch b/patches.arch/arm64-0018-arm64-dts-Add-X-Gene-reboot-driver-dts-node.patch new file mode 100644 index 0000000..05c785a --- /dev/null +++ b/patches.arch/arm64-0018-arm64-dts-Add-X-Gene-reboot-driver-dts-node.patch @@ -0,0 +1,49 @@ +From 1e30856aaaeba4b9f755860832951162de993d70 Mon Sep 17 00:00:00 2001 +From: Feng Kan <fkan@apm.com> +Date: Thu, 23 Oct 2014 18:24:18 -0700 +Subject: [PATCH 18/38] arm64: dts: Add X-Gene reboot driver dts node +Patch-mainline: No +References: bnc#902632 + +Add X-Gene platform reboot driver dts node. + +Signed-off-by: Feng Kan <fkan@apm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/boot/dts/apm-storm.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi +index cea114b..d0d533a 100644 +--- a/arch/arm64/boot/dts/apm-storm.dtsi ++++ b/arch/arm64/boot/dts/apm-storm.dtsi +@@ -103,6 +103,11 @@ + #size-cells = <2>; + ranges; + ++ scu: system-clk-controller@17000000 { ++ compatible = "apm,xgene-scu","syscon"; ++ reg = <0x0 0x17000000 0x0 0x400>; ++ }; ++ + clocks { + #address-cells = <2>; + #size-cells = <2>; +@@ -341,6 +346,13 @@ + }; + }; + ++ reboot: reboot@17000014 { ++ compatible = "syscon-reboot"; ++ regmap = <&scu>; ++ offset = <0x14>; ++ mask = <0x1>; ++ }; ++ + pcie0: pcie@1f2b0000 { + status = "disabled"; + device_type = "pci"; +-- +2.1.0 + diff --git a/patches.arch/arm64-0019-power-reset-Add-generic-SYSCON-register-mapped-reset.patch b/patches.arch/arm64-0019-power-reset-Add-generic-SYSCON-register-mapped-reset.patch new file mode 100644 index 0000000..3cb1ecf --- /dev/null +++ b/patches.arch/arm64-0019-power-reset-Add-generic-SYSCON-register-mapped-reset.patch @@ -0,0 +1,140 @@ +From 5e525484c87efb9ff4602a3eb9fee806c794bb7f Mon Sep 17 00:00:00 2001 +From: Feng Kan <fkan@apm.com> +Date: Tue, 30 Sep 2014 16:25:03 -0700 +Subject: [PATCH 19/38] power: reset: Add generic SYSCON register mapped reset +Git-commit: 09fb07bcaf529a21612fbebd1297d8c5dd1abf1b +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Add a generic SYSCON register mapped reset mechanism. + +Signed-off-by: Feng Kan <fkan@apm.com> +[agraf: rebase to 3.16] +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/power/reset/Kconfig | 5 +++ + drivers/power/reset/Makefile | 1 + + drivers/power/reset/syscon-reboot.c | 88 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 94 insertions(+) + create mode 100644 drivers/power/reset/syscon-reboot.c + +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index bdcf517..fd5f9e5 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -80,3 +80,8 @@ config POWER_RESET_KEYSTONE + help + Reboot support for the KEYSTONE SoCs. + ++config POWER_RESET_SYSCON ++ bool "Generic SYSCON regmap reset driver" ++ depends on POWER_RESET && MFD_SYSCON && OF ++ help ++ Reboot support for generic SYSCON mapped register reset. +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index dde2e8b..b1b5ab3 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o + obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o + obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o + obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o ++obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o +diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c +new file mode 100644 +index 0000000..df1589d +--- /dev/null ++++ b/drivers/power/reset/syscon-reboot.c +@@ -0,0 +1,88 @@ ++/* ++ * Generic Syscon Reboot Driver ++ * ++ * Copyright (c) 2013, Applied Micro Circuits Corporation ++ * Author: Feng Kan <fkan@apm.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include <linux/io.h> ++#include <linux/of_device.h> ++#include <linux/of_address.h> ++#include <linux/platform_device.h> ++#include <linux/notifier.h> ++#include <linux/mfd/syscon.h> ++#include <linux/regmap.h> ++#include <linux/reboot.h> ++#include <asm/system_misc.h> ++ ++struct syscon_reboot_context { ++ struct regmap *map; ++ u32 offset; ++ u32 mask; ++}; ++ ++static struct syscon_reboot_context *syscon_reboot_ctx; ++ ++static void syscon_restart(enum reboot_mode reboot_mode, const char *cmd) ++{ ++ struct syscon_reboot_context *ctx = syscon_reboot_ctx; ++ unsigned long timeout; ++ ++ /* Issue the reboot */ ++ if (ctx->map) ++ regmap_write(ctx->map, ctx->offset, ctx->mask); ++ ++ timeout = jiffies + HZ; ++ while (time_before(jiffies, timeout)) ++ cpu_relax(); ++ ++ pr_emerg("Unable to restart system\n"); ++} ++ ++static int syscon_reboot_probe(struct platform_device *pdev) ++{ ++ struct syscon_reboot_context *ctx; ++ struct device *dev = &pdev->dev; ++ ++ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); ++ if (IS_ERR(ctx->map)) ++ return PTR_ERR(ctx->map); ++ ++ if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) ++ return -EINVAL; ++ ++ if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask)) ++ return -EINVAL; ++ ++ arm_pm_restart = syscon_restart; ++ syscon_reboot_ctx = ctx; ++ ++ return 0; ++} ++ ++static struct of_device_id syscon_reboot_of_match[] = { ++ { .compatible = "syscon-reboot" }, ++ {} ++}; ++ ++static struct platform_driver syscon_reboot_driver = { ++ .probe = syscon_reboot_probe, ++ .driver = { ++ .name = "syscon-reboot", ++ .of_match_table = syscon_reboot_of_match, ++ }, ++}; ++module_platform_driver(syscon_reboot_driver); +-- +2.1.0 + diff --git a/patches.arch/arm64-0020-arm64-Select-reboot-driver-for-X-Gene-platform.patch b/patches.arch/arm64-0020-arm64-Select-reboot-driver-for-X-Gene-platform.patch new file mode 100644 index 0000000..ba75b44 --- /dev/null +++ b/patches.arch/arm64-0020-arm64-Select-reboot-driver-for-X-Gene-platform.patch @@ -0,0 +1,32 @@ +From 364462f3a06241f58a51ac32ceec3897bca203f6 Mon Sep 17 00:00:00 2001 +From: Feng Kan <fkan@apm.com> +Date: Tue, 30 Sep 2014 16:25:07 -0700 +Subject: [PATCH 20/38] arm64: Select reboot driver for X-Gene platform +Patch-mainline: No +References: bnc#902632 + +Select reboot driver for X-Gene platform. + +Signed-off-by: Feng Kan <fkan@apm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/Kconfig | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index 839f48c..df6a646 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -141,6 +141,8 @@ config ARCH_VEXPRESS + + config ARCH_XGENE + bool "AppliedMicro X-Gene SOC Family" ++ select MFD_SYSCON ++ select POWER_RESET_SYSCON + help + This enables support for AppliedMicro X-Gene SOC Family + +-- +2.1.0 + diff --git a/patches.arch/arm64-0021-power-reset-Remove-X-Gene-reboot-driver.patch b/patches.arch/arm64-0021-power-reset-Remove-X-Gene-reboot-driver.patch new file mode 100644 index 0000000..ec431d1 --- /dev/null +++ b/patches.arch/arm64-0021-power-reset-Remove-X-Gene-reboot-driver.patch @@ -0,0 +1,161 @@ +From 124e39107dc1de95aab314230591b7f6aa53eddd Mon Sep 17 00:00:00 2001 +From: Feng Kan <fkan@apm.com> +Date: Tue, 30 Sep 2014 16:25:08 -0700 +Subject: [PATCH 21/38] power: reset: Remove X-Gene reboot driver +Patch-mainline: No +References: bnc#902632 + +Remove X-Gene reboot driver. + +Signed-off-by: Feng Kan <fkan@apm.com> +Signed-off-by: Loc Ho <lho@apm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/power/reset/Kconfig | 7 --- + drivers/power/reset/Makefile | 1 - + drivers/power/reset/xgene-reboot.c | 103 ------------------------------------- + 3 files changed, 111 deletions(-) + delete mode 100644 drivers/power/reset/xgene-reboot.c + +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index fd5f9e5..48b3cb3 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -66,13 +66,6 @@ config POWER_RESET_VEXPRESS + Power off and reset support for the ARM Ltd. Versatile + Express boards. + +-config POWER_RESET_XGENE +- bool "APM SoC X-Gene reset driver" +- depends on ARM64 +- depends on POWER_RESET +- help +- Reboot support for the APM SoC X-Gene Eval boards. +- + config POWER_RESET_KEYSTONE + bool "Keystone reset driver" + depends on ARCH_KEYSTONE +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index b1b5ab3..62088d8 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -6,6 +6,5 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o + obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o + obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o + obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o +-obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o + obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o + obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o +diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c +deleted file mode 100644 +index ecd55f8..0000000 +--- a/drivers/power/reset/xgene-reboot.c ++++ /dev/null +@@ -1,103 +0,0 @@ +-/* +- * AppliedMicro X-Gene SoC Reboot Driver +- * +- * Copyright (c) 2013, Applied Micro Circuits Corporation +- * Author: Feng Kan <fkan@apm.com> +- * Author: Loc Ho <lho@apm.com> +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation; either version 2 of +- * the License, or (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * 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., 59 Temple Place, Suite 330, Boston, +- * MA 02111-1307 USA +- * +- * This driver provides system reboot functionality for APM X-Gene SoC. +- * For system shutdown, this is board specify. If a board designer +- * implements GPIO shutdown, use the gpio-poweroff.c driver. +- */ +-#include <linux/io.h> +-#include <linux/of_device.h> +-#include <linux/of_address.h> +-#include <linux/platform_device.h> +-#include <linux/stat.h> +-#include <linux/slab.h> +-#include <asm/system_misc.h> +- +-struct xgene_reboot_context { +- struct platform_device *pdev; +- void *csr; +- u32 mask; +-}; +- +-static struct xgene_reboot_context *xgene_restart_ctx; +- +-static void xgene_restart(char str, const char *cmd) +-{ +- struct xgene_reboot_context *ctx = xgene_restart_ctx; +- unsigned long timeout; +- +- /* Issue the reboot */ +- if (ctx) +- writel(ctx->mask, ctx->csr); +- +- timeout = jiffies + HZ; +- while (time_before(jiffies, timeout)) +- cpu_relax(); +- +- dev_emerg(&ctx->pdev->dev, "Unable to restart system\n"); +-} +- +-static int xgene_reboot_probe(struct platform_device *pdev) +-{ +- struct xgene_reboot_context *ctx; +- +- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); +- if (!ctx) { +- dev_err(&pdev->dev, "out of memory for context\n"); +- return -ENODEV; +- } +- +- ctx->csr = of_iomap(pdev->dev.of_node, 0); +- if (!ctx->csr) { +- devm_kfree(&pdev->dev, ctx); +- dev_err(&pdev->dev, "can not map resource\n"); +- return -ENODEV; +- } +- +- if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask)) +- ctx->mask = 0xFFFFFFFF; +- +- ctx->pdev = pdev; +- arm_pm_restart = xgene_restart; +- xgene_restart_ctx = ctx; +- +- return 0; +-} +- +-static struct of_device_id xgene_reboot_of_match[] = { +- { .compatible = "apm,xgene-reboot" }, +- {} +-}; +- +-static struct platform_driver xgene_reboot_driver = { +- .probe = xgene_reboot_probe, +- .driver = { +- .name = "xgene-reboot", +- .of_match_table = xgene_reboot_of_match, +- }, +-}; +- +-static int __init xgene_reboot_init(void) +-{ +- return platform_driver_register(&xgene_reboot_driver); +-} +-device_initcall(xgene_reboot_init); +-- +2.1.0 + diff --git a/patches.arch/arm64-0022-irqchip-gic-preserve-gic-V2-bypass-bits-in-cpu-ctrl-.patch b/patches.arch/arm64-0022-irqchip-gic-preserve-gic-V2-bypass-bits-in-cpu-ctrl-.patch new file mode 100644 index 0000000..d9f1777 --- /dev/null +++ b/patches.arch/arm64-0022-irqchip-gic-preserve-gic-V2-bypass-bits-in-cpu-ctrl-.patch @@ -0,0 +1,97 @@ +From d8d21f8c7c464999c837894d5f583f756e26e79c Mon Sep 17 00:00:00 2001 +From: Feng Kan <fkan@apm.com> +Date: Thu, 28 Aug 2014 12:00:05 +0530 +Subject: [PATCH 22/38] irqchip: gic: preserve gic V2 bypass bits in cpu ctrl + register +Git-commit: 3228950621d92f0f212378f95a6998ef3a1be0bb +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +This change is made to preserve the GIC v2 bypass bits in the +GIC_CPU_CTRL register (also known as the GICC_CTLR register in spec). +This code will preserve all bits configured by the bootloader regarding +v2 bypass group bits. In the X-Gene platform, the bypass functionality +is not used and bypass bits should not be changed by the kernel gic +code as it could lead to incorrect behavior. + +Signed-off-by: Vinayak Kale <vkale@apm.com> +Signed-off-by: Feng Kan <fkan@apm.com> +Reviewed-by: Anup Patel <apatel@apm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/irqchip/irq-gic.c | 24 +++++++++++++++++++++--- + include/linux/irqchip/arm-gic.h | 3 +++ + 2 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c +index 7c131cf..cfee5b6 100644 +--- a/drivers/irqchip/irq-gic.c ++++ b/drivers/irqchip/irq-gic.c +@@ -378,6 +378,20 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) + return mask; + } + ++static void gic_cpu_if_up(void) ++{ ++ void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); ++ u32 bypass; ++ ++ /* ++ * Preserve bypass disable bits to be written back later ++ */ ++ bypass = readl(cpu_base + GIC_CPU_CTRL); ++ bypass &= GICC_CTRL_DIS_BYPASS_MASK; ++ ++ writel_relaxed(bypass | GICC_CTRL_ENABLE, cpu_base + GIC_CPU_CTRL); ++} ++ + static void __init gic_dist_init(struct gic_chip_data *gic) + { + unsigned int i; +@@ -454,13 +468,17 @@ static void gic_cpu_init(struct gic_chip_data *gic) + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); + + writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); +- writel_relaxed(1, base + GIC_CPU_CTRL); ++ gic_cpu_if_up(); + } + + void gic_cpu_if_down(void) + { + void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); +- writel_relaxed(0, cpu_base + GIC_CPU_CTRL); ++ u32 val; ++ ++ val = readl(cpu_base + GIC_CPU_CTRL); ++ val &= ~GICC_CTRL_ENABLE; ++ writel_relaxed(val, cpu_base + GIC_CPU_CTRL); + } + + #ifdef CONFIG_CPU_PM +@@ -595,7 +613,7 @@ static void gic_cpu_restore(unsigned int gic_nr) + writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); + + writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); +- writel_relaxed(1, cpu_base + GIC_CPU_CTRL); ++ gic_cpu_if_up(); + } + + static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) +diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h +index 45e2d8c..cc2977c 100644 +--- a/include/linux/irqchip/arm-gic.h ++++ b/include/linux/irqchip/arm-gic.h +@@ -21,6 +21,9 @@ + #define GIC_CPU_ACTIVEPRIO 0xd0 + #define GIC_CPU_IDENT 0xfc + ++#define GICC_CTRL_ENABLE 0x1 ++#define GICC_CTRL_DIS_BYPASS_MASK 0x1e0 ++ + #define GICC_IAR_INT_ID_MASK 0x3ff + + #define GIC_DIST_CTRL 0x000 +-- +2.1.0 + diff --git a/patches.arch/arm64-0023-arm64-efi-efistub-cover-entire-static-mem-footprint-.patch b/patches.arch/arm64-0023-arm64-efi-efistub-cover-entire-static-mem-footprint-.patch new file mode 100644 index 0000000..2097eb8 --- /dev/null +++ b/patches.arch/arm64-0023-arm64-efi-efistub-cover-entire-static-mem-footprint-.patch @@ -0,0 +1,68 @@ +From 10ede6167e855799837aea0ce93f145ed5ae607a Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Date: Wed, 30 Jul 2014 11:59:03 +0100 +Subject: [PATCH 23/38] arm64/efi: efistub: cover entire static mem footprint + in PE/COFF .text +Git-commit: c16173fa568582113145daee70fc317b10bc51e0 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The static memory footprint of a kernel Image at boot is larger than the +Image file itself. Things like .bss data and initial page tables are allocated +statically but populated dynamically so their content is not contained in the +Image file. + +However, if EFI (or GRUB) has loaded the Image at precisely the desired offset +of base of DRAM + TEXT_OFFSET, the Image will be booted in place, and we have +to make sure that the allocation done by the PE/COFF loader is large enough. + +Fix this by growing the PE/COFF .text section to cover the entire static +memory footprint. The part of the section that is not covered by the payload +will be zero initialised by the PE/COFF loader. + +Acked-by: Mark Salter <msalter@redhat.com> +Acked-by: Mark Rutland <mark.rutland@arm.com> +Acked-by: Leif Lindholm <leif.lindholm@linaro.org> +Tested-by: Leif Lindholm <leif.lindholm@linaro.org> +Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Signed-off-by: Will Deacon <will.deacon@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/kernel/head.S | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S +index a2c1195..d59d27b 100644 +--- a/arch/arm64/kernel/head.S ++++ b/arch/arm64/kernel/head.S +@@ -156,7 +156,7 @@ optional_header: + .short 0x20b // PE32+ format + .byte 0x02 // MajorLinkerVersion + .byte 0x14 // MinorLinkerVersion +- .long _edata - stext // SizeOfCode ++ .long _end - stext // SizeOfCode + .long 0 // SizeOfInitializedData + .long 0 // SizeOfUninitializedData + .long efi_stub_entry - efi_head // AddressOfEntryPoint +@@ -174,7 +174,7 @@ extra_header_fields: + .short 0 // MinorSubsystemVersion + .long 0 // Win32VersionValue + +- .long _edata - efi_head // SizeOfImage ++ .long _end - efi_head // SizeOfImage + + // Everything before the kernel image is considered part of the header + .long stext - efi_head // SizeOfHeaders +@@ -221,7 +221,7 @@ section_table: + .byte 0 + .byte 0 + .byte 0 // end of 0 padding of section name +- .long _edata - stext // VirtualSize ++ .long _end - stext // VirtualSize + .long stext - efi_head // VirtualAddress + .long _edata - stext // SizeOfRawData + .long stext - efi_head // PointerToRawData +-- +2.1.0 + diff --git a/patches.arch/arm64-0024-arm64-efi-efistub-don-t-abort-if-base-of-DRAM-is-occ.patch b/patches.arch/arm64-0024-arm64-efi-efistub-don-t-abort-if-base-of-DRAM-is-occ.patch new file mode 100644 index 0000000..97e946e --- /dev/null +++ b/patches.arch/arm64-0024-arm64-efi-efistub-don-t-abort-if-base-of-DRAM-is-occ.patch @@ -0,0 +1,60 @@ +From 43684b7f9a7f0f5adf35e4145035639be7a67b8a Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Date: Wed, 30 Jul 2014 11:59:04 +0100 +Subject: [PATCH 24/38] arm64/efi: efistub: don't abort if base of DRAM is + occupied +Git-commit: 58015ec6b8e13c980c20d9fff3f986838c004348 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +If we cannot relocate the kernel Image to its preferred offset of base of DRAM +plus TEXT_OFFSET, instead relocate it to the lowest available 2 MB boundary plus +TEXT_OFFSET. We may lose a bit of memory at the low end, but we can still +proceed normally otherwise. + +Acked-by: Mark Salter <msalter@redhat.com> +Acked-by: Mark Rutland <mark.rutland@arm.com> +Acked-by: Leif Lindholm <leif.lindholm@linaro.org> +Tested-by: Leif Lindholm <leif.lindholm@linaro.org> +Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> +Signed-off-by: Will Deacon <will.deacon@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/kernel/efi-stub.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c +index e786e6c..320ef48 100644 +--- a/arch/arm64/kernel/efi-stub.c ++++ b/arch/arm64/kernel/efi-stub.c +@@ -58,20 +58,16 @@ static efi_status_t handle_kernel_image(efi_system_table_t *sys_table, + kernel_size = _edata - _text; + if (*image_addr != (dram_base + TEXT_OFFSET)) { + kernel_memsize = kernel_size + (_end - _edata); +- status = efi_relocate_kernel(sys_table, image_addr, +- kernel_size, kernel_memsize, +- dram_base + TEXT_OFFSET, +- PAGE_SIZE); ++ status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET, ++ SZ_2M, reserve_addr); + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table, "Failed to relocate kernel\n"); + return status; + } +- if (*image_addr != (dram_base + TEXT_OFFSET)) { +- pr_efi_err(sys_table, "Failed to alloc kernel memory\n"); +- efi_free(sys_table, kernel_memsize, *image_addr); +- return EFI_ERROR; +- } +- *image_size = kernel_memsize; ++ memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr, ++ kernel_size); ++ *image_addr = *reserve_addr + TEXT_OFFSET; ++ *reserve_size = kernel_memsize + TEXT_OFFSET; + } + + +-- +2.1.0 + diff --git a/patches.arch/arm64-0025-asm-generic-io.h-Fix-ioport_map-for-CONFIG_GENERIC_I.patch b/patches.arch/arm64-0025-asm-generic-io.h-Fix-ioport_map-for-CONFIG_GENERIC_I.patch new file mode 100644 index 0000000..8efc4c8 --- /dev/null +++ b/patches.arch/arm64-0025-asm-generic-io.h-Fix-ioport_map-for-CONFIG_GENERIC_I.patch @@ -0,0 +1,41 @@ +From 3c5055fcc9b8818b6be2dfa4862e9b01cb3c907d Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:20 +0100 +Subject: [PATCH 25/38] asm-generic/io.h: Fix ioport_map() for + !CONFIG_GENERIC_IOMAP +Git-commit: 112eeaa7f87bbd2925e919486bb504f8954fa675 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The !CONFIG_GENERIC_IOMAP version of ioport_map() is wrong. It returns a +mapped, i.e., virtual, address that can start from zero and completely +ignores the PCI_IOBASE and IO_SPACE_LIMIT that most architectures that use +!CONFIG_GENERIC_MAP define. + +Tested-by: Tanmay Inamdar <tinamdar@apm.com> +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + include/asm-generic/io.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h +index 975e1cc..b8fdc57 100644 +--- a/include/asm-generic/io.h ++++ b/include/asm-generic/io.h +@@ -331,7 +331,7 @@ static inline void iounmap(void __iomem *addr) + #ifndef CONFIG_GENERIC_IOMAP + static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) + { +- return (void __iomem *) port; ++ return PCI_IOBASE + (port & IO_SPACE_LIMIT); + } + + static inline void ioport_unmap(void __iomem *p) +-- +2.1.0 + diff --git a/patches.arch/arm64-0026-of-pci-Add-pci_register_io_range-and-pci_pio_to_addr.patch b/patches.arch/arm64-0026-of-pci-Add-pci_register_io_range-and-pci_pio_to_addr.patch new file mode 100644 index 0000000..890b7cc --- /dev/null +++ b/patches.arch/arm64-0026-of-pci-Add-pci_register_io_range-and-pci_pio_to_addr.patch @@ -0,0 +1,200 @@ +From 1c22b41cfa78dc19e618a99fef48540764b3b9c9 Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:21 +0100 +Subject: [PATCH 26/38] of/pci: Add pci_register_io_range() and + pci_pio_to_address() +Git-commit: 41f8bba7f5552d033583777dede2df7c36e7853d +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Some architectures do not have a simple view of the PCI I/O space and +instead use a range of CPU addresses that map to bus addresses. For some +architectures these ranges will be expressed by OF bindings in a device +tree file. + +This patch introduces a pci_register_io_range() helper function with a +generic implementation that can be used by such architectures to keep track +of the I/O ranges described by the PCI bindings. If the PCI_IOBASE macro +is not defined, that signals lack of support for PCI and we return an +error. + +In order to retrieve the CPU address associated with an I/O port, a new +helper function pci_pio_to_address() is introduced. This will search in +the list of ranges registered with pci_register_io_range() and return the +CPU address that corresponds to the given port. + +[arnd: add dummy !CONFIG_OF pci_pio_to_address() to fix build errors] +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> +Acked-by: Rob Herring <robh@kernel.org> +Cc: Grant Likely <grant.likely@linaro.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/of/address.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ + include/linux/of_address.h | 7 +++ + 2 files changed, 116 insertions(+) + +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 5edfcb0..48218cb 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -5,6 +5,8 @@ + #include <linux/module.h> + #include <linux/of_address.h> + #include <linux/pci_regs.h> ++#include <linux/sizes.h> ++#include <linux/slab.h> + #include <linux/string.h> + + /* Max address size we deal with */ +@@ -601,12 +603,119 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, + } + EXPORT_SYMBOL(of_get_address); + ++#ifdef PCI_IOBASE ++struct io_range { ++ struct list_head list; ++ phys_addr_t start; ++ resource_size_t size; ++}; ++ ++static LIST_HEAD(io_range_list); ++static DEFINE_SPINLOCK(io_range_lock); ++#endif ++ ++/* ++ * Record the PCI IO range (expressed as CPU physical address + size). ++ * Return a negative value if an error has occured, zero otherwise ++ */ ++int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size) ++{ ++ int err = 0; ++ ++#ifdef PCI_IOBASE ++ struct io_range *range; ++ resource_size_t allocated_size = 0; ++ ++ /* check if the range hasn't been previously recorded */ ++ spin_lock(&io_range_lock); ++ list_for_each_entry(range, &io_range_list, list) { ++ if (addr >= range->start && addr + size <= range->start + size) { ++ /* range already registered, bail out */ ++ goto end_register; ++ } ++ allocated_size += range->size; ++ } ++ ++ /* range not registed yet, check for available space */ ++ if (allocated_size + size - 1 > IO_SPACE_LIMIT) { ++ /* if it's too big check if 64K space can be reserved */ ++ if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) { ++ err = -E2BIG; ++ goto end_register; ++ } ++ ++ size = SZ_64K; ++ pr_warn("Requested IO range too big, new size set to 64K\n"); ++ } ++ ++ /* add the range to the list */ ++ range = kzalloc(sizeof(*range), GFP_KERNEL); ++ if (!range) { ++ err = -ENOMEM; ++ goto end_register; ++ } ++ ++ range->start = addr; ++ range->size = size; ++ ++ list_add_tail(&range->list, &io_range_list); ++ ++end_register: ++ spin_unlock(&io_range_lock); ++#endif ++ ++ return err; ++} ++ ++phys_addr_t pci_pio_to_address(unsigned long pio) ++{ ++ phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; ++ ++#ifdef PCI_IOBASE ++ struct io_range *range; ++ resource_size_t allocated_size = 0; ++ ++ if (pio > IO_SPACE_LIMIT) ++ return address; ++ ++ spin_lock(&io_range_lock); ++ list_for_each_entry(range, &io_range_list, list) { ++ if (pio >= allocated_size && pio < allocated_size + range->size) { ++ address = range->start + pio - allocated_size; ++ break; ++ } ++ allocated_size += range->size; ++ } ++ spin_unlock(&io_range_lock); ++#endif ++ ++ return address; ++} ++ + unsigned long __weak pci_address_to_pio(phys_addr_t address) + { ++#ifdef PCI_IOBASE ++ struct io_range *res; ++ resource_size_t offset = 0; ++ unsigned long addr = -1; ++ ++ spin_lock(&io_range_lock); ++ list_for_each_entry(res, &io_range_list, list) { ++ if (address >= res->start && address < res->start + res->size) { ++ addr = res->start - address + offset; ++ break; ++ } ++ offset += res->size; ++ } ++ spin_unlock(&io_range_lock); ++ ++ return addr; ++#else + if (address > IO_SPACE_LIMIT) + return (unsigned long)-1; + + return (unsigned long) address; ++#endif + } + + static int __of_address_to_resource(struct device_node *dev, +diff --git a/include/linux/of_address.h b/include/linux/of_address.h +index c13b878..4b7c4de 100644 +--- a/include/linux/of_address.h ++++ b/include/linux/of_address.h +@@ -55,7 +55,9 @@ extern void __iomem *of_iomap(struct device_node *device, int index); + extern const __be32 *of_get_address(struct device_node *dev, int index, + u64 *size, unsigned int *flags); + ++extern int pci_register_io_range(phys_addr_t addr, resource_size_t size); + extern unsigned long pci_address_to_pio(phys_addr_t addr); ++extern phys_addr_t pci_pio_to_address(unsigned long pio); + + extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node); +@@ -80,6 +82,11 @@ static inline const __be32 *of_get_address(struct device_node *dev, int index, + return NULL; + } + ++static inline phys_addr_t pci_pio_to_address(unsigned long pio) ++{ ++ return 0; ++} ++ + static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) + { +-- +2.1.0 + diff --git a/patches.arch/arm64-0027-ARM-Define-PCI_IOBASE-as-the-base-of-virtual-PCI-IO-.patch b/patches.arch/arm64-0027-ARM-Define-PCI_IOBASE-as-the-base-of-virtual-PCI-IO-.patch new file mode 100644 index 0000000..2d847df --- /dev/null +++ b/patches.arch/arm64-0027-ARM-Define-PCI_IOBASE-as-the-base-of-virtual-PCI-IO-.patch @@ -0,0 +1,40 @@ +From bf1747cd1bec0d05c61f6b209264bbac4726dec2 Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:22 +0100 +Subject: [PATCH 27/38] ARM: Define PCI_IOBASE as the base of virtual PCI IO + space +Git-commit: dad13e3c08e7005854271e562eda4ffa5c71bc38 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +This is needed for calls into OF code that parses PCI ranges. It signals +support for memory mapped PCI I/O accesses that are described by device +trees. + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Cc: Russell King <linux@arm.linux.org.uk> +Cc: Rob Herring <robh+dt@kernel.org> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm/include/asm/io.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h +index 3d23418..1805674 100644 +--- a/arch/arm/include/asm/io.h ++++ b/arch/arm/include/asm/io.h +@@ -178,6 +178,7 @@ static inline void __iomem *__typesafe_io(unsigned long addr) + + /* PCI fixed i/o mapping */ + #define PCI_IO_VIRT_BASE 0xfee00000 ++#define PCI_IOBASE ((void __iomem *)PCI_IO_VIRT_BASE) + + #if defined(CONFIG_PCI) + void pci_ioremap_set_mem_type(int mem_type); +-- +2.1.0 + diff --git a/patches.arch/arm64-0028-of-pci-Move-of_pci_range_to_resource-to-of-address.c.patch b/patches.arch/arm64-0028-of-pci-Move-of_pci_range_to_resource-to-of-address.c.patch new file mode 100644 index 0000000..90bc54a --- /dev/null +++ b/patches.arch/arm64-0028-of-pci-Move-of_pci_range_to_resource-to-of-address.c.patch @@ -0,0 +1,102 @@ +From 0b95d3aa85cd8166efc8ea830ae509c0826859ef Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:24 +0100 +Subject: [PATCH 28/38] of/pci: Move of_pci_range_to_resource() to of/address.c +Git-commit: 83bbde1cc0ec9d156b9271e29ffe0dc89c687feb +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +We need to enhance of_pci_range_to_resources() enough that it won't make +sense for it to be inline anymore. Move it to drivers/of/address.c, under +#ifdef CONFIG_PCI. + +of_address.h previously implemented of_pci_range_to_resources() +unconditionally, regardless of any config options. The implementation in +address.c is defined only when CONFIG_OF_ADDRESS=y and CONFIG_PCI=y, +so add a dummy version to avoid build errors when CONFIG_OF or +CONFIG_OF_ADDRESS is not defined. + +[bhelgaas: drop extra detail from changelog, move def under CONFIG_PCI, +add dummy of_pci_range_to_resource() for build errors (from Arnd)] + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Cc: Grant Likely <grant.likely@linaro.org> +Cc: Rob Herring <robh+dt@kernel.org> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/of/address.c | 9 +++++++++ + include/linux/of_address.h | 20 +++++++++----------- + 2 files changed, 18 insertions(+), 11 deletions(-) + +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 48218cb..9fdfcdb 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -295,6 +295,15 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, + } + EXPORT_SYMBOL_GPL(of_pci_range_parser_one); + ++void of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, struct resource *res) ++{ ++ res->flags = range->flags; ++ res->start = range->cpu_addr; ++ res->end = range->cpu_addr + range->size - 1; ++ res->parent = res->child = res->sibling = NULL; ++ res->name = np->full_name; ++} + #endif /* CONFIG_PCI */ + + /* +diff --git a/include/linux/of_address.h b/include/linux/of_address.h +index 4b7c4de..24f5e32 100644 +--- a/include/linux/of_address.h ++++ b/include/linux/of_address.h +@@ -23,17 +23,6 @@ struct of_pci_range { + #define for_each_of_pci_range(parser, range) \ + for (; of_pci_range_parser_one(parser, range);) + +-static inline void of_pci_range_to_resource(struct of_pci_range *range, +- struct device_node *np, +- struct resource *res) +-{ +- res->flags = range->flags; +- res->start = range->cpu_addr; +- res->end = range->cpu_addr + range->size - 1; +- res->parent = res->child = res->sibling = NULL; +- res->name = np->full_name; +-} +- + /* Translate a DMA address from device space to CPU space */ + extern u64 of_translate_dma_address(struct device_node *dev, + const __be32 *in_addr); +@@ -134,6 +123,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, + u64 *size, unsigned int *flags); + extern int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r); ++extern void of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res); + #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ + static inline int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +@@ -146,6 +138,12 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, + { + return NULL; + } ++static inline void of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res) ++{ ++ return -ENOSYS; ++} + #endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */ + + #endif /* __OF_ADDRESS_H */ +-- +2.1.0 + diff --git a/patches.arch/arm64-0029-of-pci-Fix-the-conversion-of-IO-ranges-into-IO-resou.patch b/patches.arch/arm64-0029-of-pci-Fix-the-conversion-of-IO-ranges-into-IO-resou.patch new file mode 100644 index 0000000..1ab8f94 --- /dev/null +++ b/patches.arch/arm64-0029-of-pci-Fix-the-conversion-of-IO-ranges-into-IO-resou.patch @@ -0,0 +1,312 @@ +From f7d64748850cb4391edfb32a769e3889251a3de2 Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:25 +0100 +Subject: [PATCH 29/38] of/pci: Fix the conversion of IO ranges into IO + resources +Git-commit: 0b0b0893d49b34201a6c4416b1a707b580b91e3d +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The ranges property for a host bridge controller in DT describes the +mapping between the PCI bus address and the CPU physical address. The +resources framework however expects that the IO resources start at a pseudo +"port" address 0 (zero) and have a maximum size of IO_SPACE_LIMIT. The +conversion from PCI ranges to resources failed to take that into account, +returning a CPU physical address instead of a port number. + +Also fix all the drivers that depend on the old behaviour by fetching the +CPU physical address based on the port number where it is being needed. + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Acked-by: Linus Walleij <linus.walleij@linaro.org> +Cc: Grant Likely <grant.likely@linaro.org> +Cc: Rob Herring <robh+dt@kernel.org> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Thierry Reding <thierry.reding@gmail.com> +Cc: Simon Horman <horms@verge.net.au> +Cc: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm/mach-integrator/pci_v3.c | 23 ++++++++++---------- + drivers/of/address.c | 44 +++++++++++++++++++++++++++++++++++---- + drivers/pci/host/pci-tegra.c | 10 ++++++--- + drivers/pci/host/pcie-rcar.c | 21 +++++++++++++------ + include/linux/of_address.h | 12 +++++------ + 5 files changed, 80 insertions(+), 30 deletions(-) + +diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c +index 05e1f73..c186a17 100644 +--- a/arch/arm/mach-integrator/pci_v3.c ++++ b/arch/arm/mach-integrator/pci_v3.c +@@ -660,6 +660,7 @@ static void __init pci_v3_preinit(void) + { + unsigned long flags; + unsigned int temp; ++ phys_addr_t io_address = pci_pio_to_address(io_mem.start); + + pcibios_min_mem = 0x00100000; + +@@ -701,7 +702,7 @@ static void __init pci_v3_preinit(void) + /* + * Setup window 2 - PCI IO + */ +- v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_mem.start) | ++ v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_address) | + V3_LB_BASE_ENABLE); + v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0)); + +@@ -742,6 +743,7 @@ static void __init pci_v3_preinit(void) + static void __init pci_v3_postinit(void) + { + unsigned int pci_cmd; ++ phys_addr_t io_address = pci_pio_to_address(io_mem.start); + + pci_cmd = PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; +@@ -758,7 +760,7 @@ static void __init pci_v3_postinit(void) + "interrupt: %d\n", ret); + #endif + +- register_isa_ports(non_mem.start, io_mem.start, 0); ++ register_isa_ports(non_mem.start, io_address, 0); + } + + /* +@@ -867,33 +869,32 @@ static int __init pci_v3_probe(struct platform_device *pdev) + + for_each_of_pci_range(&parser, &range) { + if (!range.flags) { +- of_pci_range_to_resource(&range, np, &conf_mem); ++ ret = of_pci_range_to_resource(&range, np, &conf_mem); + conf_mem.name = "PCIv3 config"; + } + if (range.flags & IORESOURCE_IO) { +- of_pci_range_to_resource(&range, np, &io_mem); ++ ret = of_pci_range_to_resource(&range, np, &io_mem); + io_mem.name = "PCIv3 I/O"; + } + if ((range.flags & IORESOURCE_MEM) && + !(range.flags & IORESOURCE_PREFETCH)) { + non_mem_pci = range.pci_addr; + non_mem_pci_sz = range.size; +- of_pci_range_to_resource(&range, np, &non_mem); ++ ret = of_pci_range_to_resource(&range, np, &non_mem); + non_mem.name = "PCIv3 non-prefetched mem"; + } + if ((range.flags & IORESOURCE_MEM) && + (range.flags & IORESOURCE_PREFETCH)) { + pre_mem_pci = range.pci_addr; + pre_mem_pci_sz = range.size; +- of_pci_range_to_resource(&range, np, &pre_mem); ++ ret = of_pci_range_to_resource(&range, np, &pre_mem); + pre_mem.name = "PCIv3 prefetched mem"; + } +- } + +- if (!conf_mem.start || !io_mem.start || +- !non_mem.start || !pre_mem.start) { +- dev_err(&pdev->dev, "missing ranges in device node\n"); +- return -EINVAL; ++ if (ret < 0) { ++ dev_err(&pdev->dev, "missing ranges in device node\n"); ++ return ret; ++ } + } + + pci_v3.map_irq = of_irq_parse_and_map_pci; +diff --git a/drivers/of/address.c b/drivers/of/address.c +index 9fdfcdb..04b8867 100644 +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -295,14 +295,50 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser, + } + EXPORT_SYMBOL_GPL(of_pci_range_parser_one); + +-void of_pci_range_to_resource(struct of_pci_range *range, +- struct device_node *np, struct resource *res) ++/* ++ * of_pci_range_to_resource - Create a resource from an of_pci_range ++ * @range: the PCI range that describes the resource ++ * @np: device node where the range belongs to ++ * @res: pointer to a valid resource that will be updated to ++ * reflect the values contained in the range. ++ * ++ * Returns EINVAL if the range cannot be converted to resource. ++ * ++ * Note that if the range is an IO range, the resource will be converted ++ * using pci_address_to_pio() which can fail if it is called too early or ++ * if the range cannot be matched to any host bridge IO space (our case here). ++ * To guard against that we try to register the IO range first. ++ * If that fails we know that pci_address_to_pio() will do too. ++ */ ++int of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, struct resource *res) + { ++ int err; + res->flags = range->flags; +- res->start = range->cpu_addr; +- res->end = range->cpu_addr + range->size - 1; + res->parent = res->child = res->sibling = NULL; + res->name = np->full_name; ++ ++ if (res->flags & IORESOURCE_IO) { ++ unsigned long port; ++ err = pci_register_io_range(range->cpu_addr, range->size); ++ if (err) ++ goto invalid_range; ++ port = pci_address_to_pio(range->cpu_addr); ++ if (port == (unsigned long)-1) { ++ err = -EINVAL; ++ goto invalid_range; ++ } ++ res->start = port; ++ } else { ++ res->start = range->cpu_addr; ++ } ++ res->end = res->start + range->size - 1; ++ return 0; ++ ++invalid_range: ++ res->start = (resource_size_t)OF_BAD_ADDR; ++ res->end = (resource_size_t)OF_BAD_ADDR; ++ return err; + } + #endif /* CONFIG_PCI */ + +diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c +index 083cf37..e67ebfe 100644 +--- a/drivers/pci/host/pci-tegra.c ++++ b/drivers/pci/host/pci-tegra.c +@@ -625,13 +625,14 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); + static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) + { + struct tegra_pcie *pcie = sys_to_pcie(sys); ++ phys_addr_t io_start = pci_pio_to_address(pcie->io.start); + + pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); + pci_add_resource_offset(&sys->resources, &pcie->prefetch, + sys->mem_offset); + pci_add_resource(&sys->resources, &pcie->busn); + +- pci_ioremap_io(nr * SZ_64K, pcie->io.start); ++ pci_ioremap_io(nr * SZ_64K, io_start); + + return 1; + } +@@ -736,6 +737,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) + static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) + { + u32 fpci_bar, size, axi_address; ++ phys_addr_t io_start = pci_pio_to_address(pcie->io.start); + + /* Bar 0: type 1 extended configuration space */ + fpci_bar = 0xfe100000; +@@ -748,7 +750,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) + /* Bar 1: downstream IO bar */ + fpci_bar = 0xfdfc0000; + size = resource_size(&pcie->io); +- axi_address = pcie->io.start; ++ axi_address = io_start; + afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); + afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); + afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); +@@ -1424,7 +1426,9 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) + } + + for_each_of_pci_range(&parser, &range) { +- of_pci_range_to_resource(&range, np, &res); ++ err = of_pci_range_to_resource(&range, np, &res); ++ if (err < 0) ++ return err; + + switch (res.flags & IORESOURCE_TYPE_BITS) { + case IORESOURCE_IO: +diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c +index f7d3de3..718844d 100644 +--- a/drivers/pci/host/pcie-rcar.c ++++ b/drivers/pci/host/pcie-rcar.c +@@ -331,6 +331,7 @@ static void rcar_pcie_setup_window(int win, struct resource *res, + { + /* Setup PCIe address space mappings for each resource */ + resource_size_t size; ++ resource_size_t res_start; + u32 mask; + + pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win)); +@@ -343,8 +344,13 @@ static void rcar_pcie_setup_window(int win, struct resource *res, + mask = (roundup_pow_of_two(size) / SZ_128) - 1; + pci_write_reg(pcie, mask << 7, PCIEPAMR(win)); + +- pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win)); +- pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win)); ++ if (res->flags & IORESOURCE_IO) ++ res_start = pci_pio_to_address(res->start); ++ else ++ res_start = res->start; ++ ++ pci_write_reg(pcie, upper_32_bits(res_start), PCIEPARH(win)); ++ pci_write_reg(pcie, lower_32_bits(res_start), PCIEPARL(win)); + + /* First resource is for IO */ + mask = PAR_ENABLE; +@@ -371,9 +377,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys) + + rcar_pcie_setup_window(i, res, pcie); + +- if (res->flags & IORESOURCE_IO) +- pci_ioremap_io(nr * SZ_64K, res->start); +- else ++ if (res->flags & IORESOURCE_IO) { ++ phys_addr_t io_start = pci_pio_to_address(res->start); ++ pci_ioremap_io(nr * SZ_64K, io_start); ++ } else + pci_add_resource(&sys->resources, res); + } + pci_add_resource(&sys->resources, &pcie->busn); +@@ -949,8 +956,10 @@ static int rcar_pcie_probe(struct platform_device *pdev) + } + + for_each_of_pci_range(&parser, &range) { +- of_pci_range_to_resource(&range, pdev->dev.of_node, ++ err = of_pci_range_to_resource(&range, pdev->dev.of_node, + &pcie->res[win++]); ++ if (err < 0) ++ return err; + + if (win > PCI_MAX_RESOURCES) + break; +diff --git a/include/linux/of_address.h b/include/linux/of_address.h +index 24f5e32..9496c97 100644 +--- a/include/linux/of_address.h ++++ b/include/linux/of_address.h +@@ -123,9 +123,9 @@ extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, + u64 *size, unsigned int *flags); + extern int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r); +-extern void of_pci_range_to_resource(struct of_pci_range *range, +- struct device_node *np, +- struct resource *res); ++extern int of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res); + #else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ + static inline int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +@@ -138,9 +138,9 @@ static inline const __be32 *of_get_pci_address(struct device_node *dev, + { + return NULL; + } +-static inline void of_pci_range_to_resource(struct of_pci_range *range, +- struct device_node *np, +- struct resource *res) ++static inline int of_pci_range_to_resource(struct of_pci_range *range, ++ struct device_node *np, ++ struct resource *res) + { + return -ENOSYS; + } +-- +2.1.0 + diff --git a/patches.arch/arm64-0030-PCI-Add-generic-domain-handling.patch b/patches.arch/arm64-0030-PCI-Add-generic-domain-handling.patch new file mode 100644 index 0000000..a591a7e --- /dev/null +++ b/patches.arch/arm64-0030-PCI-Add-generic-domain-handling.patch @@ -0,0 +1,126 @@ +From 9b56910b454e1d7c01bb846da8f8a045a163cab4 Mon Sep 17 00:00:00 2001 +From: Catalin Marinas <catalin.marinas@arm.com> +Date: Mon, 29 Sep 2014 15:29:26 +0100 +Subject: [PATCH 30/38] PCI: Add generic domain handling +Git-commit: 670ba0c8883b576d0aec28bd7a838358a4be1406 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +The handling of PCI domains (or PCI segments in ACPI speak) is usually a +straightforward affair but its implementation is currently left to the +architectural code, with pci_domain_nr(b) querying the value of the domain +associated with bus b. + +This patch introduces CONFIG_PCI_DOMAINS_GENERIC as an option that can be +selected if an architecture wants a simple implementation where the value +of the domain associated with a bus is stored in struct pci_bus. + +The architectures that select CONFIG_PCI_DOMAINS_GENERIC will then have to +implement pci_bus_assign_domain_nr() as a way of setting the domain number +associated with a root bus. All child buses except the root bus will +inherit the domain_nr value from their parent. + +Signed-off-by: Catalin Marinas <Catalin.Marinas@arm.com> +[Renamed pci_set_domain_nr() to pci_bus_assign_domain_nr()] + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/pci/probe.c | 11 ++++++++--- + include/linux/pci.h | 21 +++++++++++++++++++++ + 2 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c +index 4170113..c69f1bb 100644 +--- a/drivers/pci/probe.c ++++ b/drivers/pci/probe.c +@@ -485,7 +485,7 @@ void pci_read_bridge_bases(struct pci_bus *child) + } + } + +-static struct pci_bus *pci_alloc_bus(void) ++static struct pci_bus *pci_alloc_bus(struct pci_bus *parent) + { + struct pci_bus *b; + +@@ -500,6 +500,10 @@ static struct pci_bus *pci_alloc_bus(void) + INIT_LIST_HEAD(&b->resources); + b->max_bus_speed = PCI_SPEED_UNKNOWN; + b->cur_bus_speed = PCI_SPEED_UNKNOWN; ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++ if (parent) ++ b->domain_nr = parent->domain_nr; ++#endif + return b; + } + +@@ -671,7 +675,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, + /* + * Allocate a new bus, and inherit stuff from the parent.. + */ +- child = pci_alloc_bus(); ++ child = pci_alloc_bus(parent); + if (!child) + return NULL; + +@@ -1751,13 +1755,14 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + char bus_addr[64]; + char *fmt; + +- b = pci_alloc_bus(); ++ b = pci_alloc_bus(NULL); + if (!b) + return NULL; + + b->sysdata = sysdata; + b->ops = ops; + b->number = b->busn_res.start = bus; ++ pci_bus_assign_domain_nr(b, parent); + b2 = pci_find_bus(pci_domain_nr(b), bus); + if (b2) { + /* If we already got to this bus through a different bridge, ignore it */ +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 97fe7eb..b2fd55f 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -457,6 +457,9 @@ struct pci_bus { + unsigned char primary; /* number of primary bridge */ + unsigned char max_bus_speed; /* enum pci_bus_speed */ + unsigned char cur_bus_speed; /* enum pci_bus_speed */ ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++ int domain_nr; ++#endif + + char name[48]; + +@@ -1294,6 +1297,24 @@ static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } + static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } + #endif /* CONFIG_PCI_DOMAINS */ + ++/* ++ * Generic implementation for PCI domain support. If your ++ * architecture does not need custom management of PCI ++ * domains then this implementation will be used ++ */ ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++static inline int pci_domain_nr(struct pci_bus *bus) ++{ ++ return bus->domain_nr; ++} ++void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent); ++#else ++static inline void pci_bus_assign_domain_nr(struct pci_bus *bus, ++ struct device *parent) ++{ ++} ++#endif ++ + /* some architectures require additional setup to direct VGA traffic */ + typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, + unsigned int command_bits, u32 flags); +-- +2.1.0 + diff --git a/patches.arch/arm64-0031-of-pci-Add-pci_get_new_domain_nr-and-of_get_pci_doma.patch b/patches.arch/arm64-0031-of-pci-Add-pci_get_new_domain_nr-and-of_get_pci_doma.patch new file mode 100644 index 0000000..2a9dd75 --- /dev/null +++ b/patches.arch/arm64-0031-of-pci-Add-pci_get_new_domain_nr-and-of_get_pci_doma.patch @@ -0,0 +1,145 @@ +From dc19e065d104460783bb156bf9975052cbbf75fe Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:27 +0100 +Subject: [PATCH 31/38] of/pci: Add pci_get_new_domain_nr() and + of_get_pci_domain_nr() +Git-commit: 41e5c0f81d3e676d671d96a0a1fafb27abfbd9d7 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Add pci_get_new_domain_nr() to allocate a new domain number and +of_get_pci_domain_nr() to retrieve the PCI domain number of a given device +from DT. Host bridge drivers or architecture-specific code can choose to +implement their PCI domain number policy using these two functions. + +Using of_get_pci_domain_nr() guarantees a stable PCI domain number on every +boot provided that all host bridge controllers are assigned a number in the +device tree using "linux,pci-domain" property. Mixing use of +pci_get_new_domain_nr() and of_get_pci_domain_nr() is not recommended as it +can lead to potentially conflicting domain numbers being assigned to root +buses behind different host bridges. + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Grant Likely <grant.likely@linaro.org> +Cc: Rob Herring <robh+dt@kernel.org> +Cc: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/of/of_pci.c | 25 +++++++++++++++++++++++++ + drivers/pci/pci.c | 9 +++++++++ + include/linux/of_pci.h | 7 +++++++ + include/linux/pci.h | 3 +++ + 4 files changed, 44 insertions(+) + +diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c +index 8481996..82d172f 100644 +--- a/drivers/of/of_pci.c ++++ b/drivers/of/of_pci.c +@@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res) + } + EXPORT_SYMBOL_GPL(of_pci_parse_bus_range); + ++/** ++ * This function will try to obtain the host bridge domain number by ++ * finding a property called "linux,pci-domain" of the given device node. ++ * ++ * @node: device tree node with the domain information ++ * ++ * Returns the associated domain number from DT in the range [0-0xffff], or ++ * a negative value if the required property is not found. ++ */ ++int of_get_pci_domain_nr(struct device_node *node) ++{ ++ const __be32 *value; ++ int len; ++ u16 domain; ++ ++ value = of_get_property(node, "linux,pci-domain", &len); ++ if (!value || len < sizeof(*value)) ++ return -EINVAL; ++ ++ domain = (u16)be32_to_cpup(value); ++ ++ return domain; ++} ++EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); ++ + #ifdef CONFIG_PCI_MSI + + static LIST_HEAD(of_pci_msi_chip_list); +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 81d49d3..463af21 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -4401,6 +4401,15 @@ static void pci_no_domains(void) + #endif + } + ++#ifdef CONFIG_PCI_DOMAINS ++static atomic_t __domain_nr = ATOMIC_INIT(-1); ++ ++int pci_get_new_domain_nr(void) ++{ ++ return atomic_inc_return(&__domain_nr); ++} ++#endif ++ + /** + * pci_ext_cfg_avail - can we access extended PCI config space? + * +diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h +index dde3a4a..71062e9 100644 +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -15,6 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, + int of_pci_get_devfn(struct device_node *np); + int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); + int of_pci_parse_bus_range(struct device_node *node, struct resource *res); ++int of_get_pci_domain_nr(struct device_node *node); + #else + static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq) + { +@@ -43,6 +44,12 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res) + { + return -EINVAL; + } ++ ++static inline int ++of_get_pci_domain_nr(struct device_node *node) ++{ ++ return -1; ++} + #endif + + #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) +diff --git a/include/linux/pci.h b/include/linux/pci.h +index b2fd55f..9e3b60b 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1291,10 +1291,12 @@ void pci_cfg_access_unlock(struct pci_dev *dev); + */ + #ifdef CONFIG_PCI_DOMAINS + extern int pci_domains_supported; ++int pci_get_new_domain_nr(void); + #else + enum { pci_domains_supported = 0 }; + static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } + static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } ++static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } + #endif /* CONFIG_PCI_DOMAINS */ + + /* +@@ -1423,6 +1425,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, + + static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } + static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; } ++static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } + + #define dev_is_pci(d) (false) + #define dev_is_pf(d) (false) +-- +2.1.0 + diff --git a/patches.arch/arm64-0032-of-pci-Add-support-for-parsing-PCI-host-bridge-resou.patch b/patches.arch/arm64-0032-of-pci-Add-support-for-parsing-PCI-host-bridge-resou.patch new file mode 100644 index 0000000..46137a4 --- /dev/null +++ b/patches.arch/arm64-0032-of-pci-Add-support-for-parsing-PCI-host-bridge-resou.patch @@ -0,0 +1,184 @@ +From c31db53bfdc9f8d21373a57da100aa27a265552e Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:28 +0100 +Subject: [PATCH 32/38] of/pci: Add support for parsing PCI host bridge + resources from DT +Git-commit: cbe4097f8ae699ebbdaf8c95ecab38d47e0bd5da +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Provide a function to parse the PCI DT ranges that can be used to create a +pci_host_bridge structure together with its associated bus. + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +[make io_base parameter optional] + +Signed-off-by: Robert Richter <rrichter@cavium.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Grant Likely <grant.likely@linaro.org> +Cc: Rob Herring <robh+dt@kernel.org> +Cc: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/of/of_pci.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/of_pci.h | 6 +++ + 2 files changed, 123 insertions(+) + +diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c +index 82d172f..8882b46 100644 +--- a/drivers/of/of_pci.c ++++ b/drivers/of/of_pci.c +@@ -1,7 +1,9 @@ + #include <linux/kernel.h> + #include <linux/export.h> + #include <linux/of.h> ++#include <linux/of_address.h> + #include <linux/of_pci.h> ++#include <linux/slab.h> + + static inline int __of_pci_pci_compare(struct device_node *node, + unsigned int data) +@@ -114,6 +116,121 @@ int of_get_pci_domain_nr(struct device_node *node) + } + EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); + ++#if defined(CONFIG_OF_ADDRESS) ++/** ++ * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT ++ * @dev: device node of the host bridge having the range property ++ * @busno: bus number associated with the bridge root bus ++ * @bus_max: maximum number of buses for this bridge ++ * @resources: list where the range of resources will be added after DT parsing ++ * @io_base: pointer to a variable that will contain on return the physical ++ * address for the start of the I/O range. Can be NULL if the caller doesn't ++ * expect IO ranges to be present in the device tree. ++ * ++ * It is the caller's job to free the @resources list. ++ * ++ * This function will parse the "ranges" property of a PCI host bridge device ++ * node and setup the resource mapping based on its content. It is expected ++ * that the property conforms with the Power ePAPR document. ++ * ++ * It returns zero if the range parsing has been successful or a standard error ++ * value if it failed. ++ */ ++int of_pci_get_host_bridge_resources(struct device_node *dev, ++ unsigned char busno, unsigned char bus_max, ++ struct list_head *resources, resource_size_t *io_base) ++{ ++ struct resource *res; ++ struct resource *bus_range; ++ struct of_pci_range range; ++ struct of_pci_range_parser parser; ++ char range_type[4]; ++ int err; ++ ++ if (io_base) ++ *io_base = (resource_size_t)OF_BAD_ADDR; ++ ++ bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL); ++ if (!bus_range) ++ return -ENOMEM; ++ ++ pr_info("PCI host bridge %s ranges:\n", dev->full_name); ++ ++ err = of_pci_parse_bus_range(dev, bus_range); ++ if (err) { ++ bus_range->start = busno; ++ bus_range->end = bus_max; ++ bus_range->flags = IORESOURCE_BUS; ++ pr_info(" No bus range found for %s, using %pR\n", ++ dev->full_name, bus_range); ++ } else { ++ if (bus_range->end > bus_range->start + bus_max) ++ bus_range->end = bus_range->start + bus_max; ++ } ++ pci_add_resource(resources, bus_range); ++ ++ /* Check for ranges property */ ++ err = of_pci_range_parser_init(&parser, dev); ++ if (err) ++ goto parse_failed; ++ ++ pr_debug("Parsing ranges property...\n"); ++ for_each_of_pci_range(&parser, &range) { ++ /* Read next ranges element */ ++ if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) ++ snprintf(range_type, 4, " IO"); ++ else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) ++ snprintf(range_type, 4, "MEM"); ++ else ++ snprintf(range_type, 4, "err"); ++ pr_info(" %s %#010llx..%#010llx -> %#010llx\n", range_type, ++ range.cpu_addr, range.cpu_addr + range.size - 1, ++ range.pci_addr); ++ ++ /* ++ * If we failed translation or got a zero-sized region ++ * then skip this range ++ */ ++ if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) ++ continue; ++ ++ res = kzalloc(sizeof(struct resource), GFP_KERNEL); ++ if (!res) { ++ err = -ENOMEM; ++ goto parse_failed; ++ } ++ ++ err = of_pci_range_to_resource(&range, dev, res); ++ if (err) ++ goto conversion_failed; ++ ++ if (resource_type(res) == IORESOURCE_IO) { ++ if (!io_base) { ++ pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n", ++ dev->full_name); ++ err = -EINVAL; ++ goto conversion_failed; ++ } ++ if (*io_base != (resource_size_t)OF_BAD_ADDR) ++ pr_warn("More than one I/O resource converted for %s. CPU base address for old range lost!\n", ++ dev->full_name); ++ *io_base = range.cpu_addr; ++ } ++ ++ pci_add_resource_offset(resources, res, res->start - range.pci_addr); ++ } ++ ++ return 0; ++ ++conversion_failed: ++ kfree(res); ++parse_failed: ++ pci_free_resource_list(resources); ++ return err; ++} ++EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); ++#endif /* CONFIG_OF_ADDRESS */ ++ + #ifdef CONFIG_PCI_MSI + + static LIST_HEAD(of_pci_msi_chip_list); +diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h +index 71062e9..1fd207e 100644 +--- a/include/linux/of_pci.h ++++ b/include/linux/of_pci.h +@@ -52,6 +52,12 @@ of_get_pci_domain_nr(struct device_node *node) + } + #endif + ++#if defined(CONFIG_OF_ADDRESS) ++int of_pci_get_host_bridge_resources(struct device_node *dev, ++ unsigned char busno, unsigned char bus_max, ++ struct list_head *resources, resource_size_t *io_base); ++#endif ++ + #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI) + int of_pci_msi_chip_add(struct msi_chip *chip); + void of_pci_msi_chip_remove(struct msi_chip *chip); +-- +2.1.0 + diff --git a/patches.arch/arm64-0033-PCI-Add-pci_remap_iospace-to-map-bus-I-O-resources.patch b/patches.arch/arm64-0033-PCI-Add-pci_remap_iospace-to-map-bus-I-O-resources.patch new file mode 100644 index 0000000..7053b8b --- /dev/null +++ b/patches.arch/arm64-0033-PCI-Add-pci_remap_iospace-to-map-bus-I-O-resources.patch @@ -0,0 +1,103 @@ +From a538aeaff34f311db2a75940c191a39634eed4b9 Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:30 +0100 +Subject: [PATCH 33/38] PCI: Add pci_remap_iospace() to map bus I/O resources +Git-commit: 8b921acfeffdb0b45085da862fc301a2d25ed2cf +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Add pci_remap_iospace() to map bus I/O resources into the CPU virtual +address space. Architectures with special needs may provide their own +version, but most should be able to use this one. + +This function is useful for PCI host bridge drivers that need to map the +PCI I/O resources into virtual memory space. + +[bhelgaas: phys_addr description, drop temporary "err" variable] +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Reviewed-by: Rob Herring <robh@kernel.org> +Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> +Cc: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/pci/pci.c | 31 +++++++++++++++++++++++++++++++ + include/asm-generic/pgtable.h | 4 ++++ + include/linux/pci.h | 3 +++ + 3 files changed, 38 insertions(+) + +diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c +index 463af21..683fad5 100644 +--- a/drivers/pci/pci.c ++++ b/drivers/pci/pci.c +@@ -2704,6 +2704,37 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) + } + EXPORT_SYMBOL(pci_request_regions_exclusive); + ++/** ++ * pci_remap_iospace - Remap the memory mapped I/O space ++ * @res: Resource describing the I/O space ++ * @phys_addr: physical address of range to be mapped ++ * ++ * Remap the memory mapped I/O space described by the @res ++ * and the CPU physical address @phys_addr into virtual address space. ++ * Only architectures that have memory mapped IO functions defined ++ * (and the PCI_IOBASE value defined) should call this function. ++ */ ++int __weak pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr) ++{ ++#if defined(PCI_IOBASE) && defined(CONFIG_MMU) ++ unsigned long vaddr = (unsigned long)PCI_IOBASE + res->start; ++ ++ if (!(res->flags & IORESOURCE_IO)) ++ return -EINVAL; ++ ++ if (res->end > IO_SPACE_LIMIT) ++ return -EINVAL; ++ ++ return ioremap_page_range(vaddr, vaddr + resource_size(res), phys_addr, ++ pgprot_device(PAGE_KERNEL)); ++#else ++ /* this architecture does not have memory mapped I/O space, ++ so this function should never be called */ ++ WARN_ONCE(1, "This architecture does not support memory mapped I/O\n"); ++ return -ENODEV; ++#endif ++} ++ + static void __pci_set_master(struct pci_dev *dev, bool enable) + { + u16 old_cmd, cmd; +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index 53b2acc..977e545 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -249,6 +249,10 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) + #define pgprot_writecombine pgprot_noncached + #endif + ++#ifndef pgprot_device ++#define pgprot_device pgprot_noncached ++#endif ++ + /* + * When walking page tables, get the address of the next boundary, + * or the end address of the range if that comes earlier. Although no +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 9e3b60b..1965bd0 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1104,6 +1104,9 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, + resource_size_t), + void *alignf_data); + ++ ++int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); ++ + static inline dma_addr_t pci_bus_address(struct pci_dev *pdev, int bar) + { + struct pci_bus_region region; +-- +2.1.0 + diff --git a/patches.arch/arm64-0034-arm64-Add-architectural-support-for-PCI.patch b/patches.arch/arm64-0034-arm64-Add-architectural-support-for-PCI.patch new file mode 100644 index 0000000..3b9cdb1 --- /dev/null +++ b/patches.arch/arm64-0034-arm64-Add-architectural-support-for-PCI.patch @@ -0,0 +1,244 @@ +From 919cf4b12d24a9bd0b665a07d77119ad66be6246 Mon Sep 17 00:00:00 2001 +From: Liviu Dudau <Liviu.Dudau@arm.com> +Date: Mon, 29 Sep 2014 15:29:31 +0100 +Subject: [PATCH 34/38] arm64: Add architectural support for PCI +Git-commit: d1e6dc91b532d3d3dbbd0fa356b775ca320dc2c2 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Use the generic PCI domain and OF functions to provide support for PCI +on arm64. + +[bhelgaas: Change comments to use generic PCI, not just PCIe. Nothing at +this level is PCIe-specific.] + +Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Acked-by: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/Kconfig | 22 ++++++++++++- + arch/arm64/include/asm/Kbuild | 1 + + arch/arm64/include/asm/io.h | 3 +- + arch/arm64/include/asm/pci.h | 37 +++++++++++++++++++++ + arch/arm64/include/asm/pgtable.h | 2 ++ + arch/arm64/kernel/Makefile | 1 + + arch/arm64/kernel/pci.c | 70 ++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 134 insertions(+), 2 deletions(-) + create mode 100644 arch/arm64/include/asm/pci.h + create mode 100644 arch/arm64/kernel/pci.c + +diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig +index df6a646..1953ffa 100644 +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -76,7 +76,7 @@ config MMU + def_bool y + + config NO_IOPORT_MAP +- def_bool y ++ def_bool y if !PCI + + config STACKTRACE_SUPPORT + def_bool y +@@ -153,6 +153,26 @@ menu "Bus support" + config ARM_AMBA + bool + ++config PCI ++ bool "PCI support" ++ help ++ This feature enables support for PCI bus system. If you say Y ++ here, the kernel will include drivers and infrastructure code ++ to support PCI bus devices. ++ ++config PCI_DOMAINS ++ def_bool PCI ++ ++config PCI_DOMAINS_GENERIC ++ def_bool PCI ++ ++config PCI_SYSCALL ++ def_bool PCI ++ ++source "drivers/pci/Kconfig" ++source "drivers/pci/pcie/Kconfig" ++source "drivers/pci/hotplug/Kconfig" ++ + endmenu + + menu "Kernel Features" +diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild +index 0b3fcf8..07cb417 100644 +--- a/arch/arm64/include/asm/Kbuild ++++ b/arch/arm64/include/asm/Kbuild +@@ -29,6 +29,7 @@ generic-y += mman.h + generic-y += msgbuf.h + generic-y += mutex.h + generic-y += pci.h ++generic-y += pci-bridge.h + generic-y += poll.h + generic-y += preempt.h + generic-y += resource.h +diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h +index e0ecdcf..f998d90 100644 +--- a/arch/arm64/include/asm/io.h ++++ b/arch/arm64/include/asm/io.h +@@ -121,7 +121,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr) + /* + * I/O port access primitives. + */ +-#define IO_SPACE_LIMIT 0xffff ++#define arch_has_dev_port() (1) ++#define IO_SPACE_LIMIT (SZ_32M - 1) + #define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M)) + + static inline u8 inb(unsigned long addr) +diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h +new file mode 100644 +index 0000000..872ba93 +--- /dev/null ++++ b/arch/arm64/include/asm/pci.h +@@ -0,0 +1,37 @@ ++#ifndef __ASM_PCI_H ++#define __ASM_PCI_H ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/dma-mapping.h> ++ ++#include <asm/io.h> ++#include <asm-generic/pci-bridge.h> ++#include <asm-generic/pci-dma-compat.h> ++ ++#define PCIBIOS_MIN_IO 0x1000 ++#define PCIBIOS_MIN_MEM 0 ++ ++/* ++ * Set to 1 if the kernel should re-assign all PCI bus numbers ++ */ ++#define pcibios_assign_all_busses() \ ++ (pci_has_flag(PCI_REASSIGN_ALL_BUS)) ++ ++/* ++ * PCI address space differs from physical memory address space ++ */ ++#define PCI_DMA_BUS_IS_PHYS (0) ++ ++extern int isa_dma_bridge_buggy; ++ ++#ifdef CONFIG_PCI ++static inline int pci_proc_domain(struct pci_bus *bus) ++{ ++ return 1; ++} ++#endif /* CONFIG_PCI */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASM_PCI_H */ +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 2a1508c..47aea94 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -288,6 +288,8 @@ static inline int has_transparent_hugepage(void) + __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_device(prot) \ ++ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN) + #define __HAVE_PHYS_MEM_ACCESS_PROT + struct file; + extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, +diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile +index cdaedad..36b117a 100644 +--- a/arch/arm64/kernel/Makefile ++++ b/arch/arm64/kernel/Makefile +@@ -29,6 +29,7 @@ arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o + arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o + arm64-obj-$(CONFIG_KGDB) += kgdb.o + arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o ++arm64-obj-$(CONFIG_PCI) += pci.o + + obj-y += $(arm64-obj-y) vdso/ + obj-m += $(arm64-obj-m) +diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c +new file mode 100644 +index 0000000..ce5836c +--- /dev/null ++++ b/arch/arm64/kernel/pci.c +@@ -0,0 +1,70 @@ ++/* ++ * Code borrowed from powerpc/kernel/pci-common.c ++ * ++ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM ++ * Copyright (C) 2014 ARM Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/of_pci.h> ++#include <linux/of_platform.h> ++#include <linux/slab.h> ++ ++#include <asm/pci-bridge.h> ++ ++/* ++ * Called after each bus is probed, but before its children are examined ++ */ ++void pcibios_fixup_bus(struct pci_bus *bus) ++{ ++ /* nothing to do, expected to be removed in the future */ ++} ++ ++/* ++ * We don't have to worry about legacy ISA devices, so nothing to do here ++ */ ++resource_size_t pcibios_align_resource(void *data, const struct resource *res, ++ resource_size_t size, resource_size_t align) ++{ ++ return res->start; ++} ++ ++/* ++ * Try to assign the IRQ number from DT when adding a new device ++ */ ++int pcibios_add_device(struct pci_dev *dev) ++{ ++ dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); ++ ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PCI_DOMAINS_GENERIC ++static bool dt_domain_found = false; ++ ++void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) ++{ ++ int domain = of_get_pci_domain_nr(parent->of_node); ++ ++ if (domain >= 0) { ++ dt_domain_found = true; ++ } else if (dt_domain_found == true) { ++ dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n", ++ parent->of_node->full_name); ++ return; ++ } else { ++ domain = pci_get_new_domain_nr(); ++ } ++ ++ bus->domain_nr = domain; ++} ++#endif +-- +2.1.0 + diff --git a/patches.arch/arm64-0035-PCI-xgene-Add-APM-X-Gene-PCIe-driver.patch b/patches.arch/arm64-0035-PCI-xgene-Add-APM-X-Gene-PCIe-driver.patch new file mode 100644 index 0000000..9fc6fce --- /dev/null +++ b/patches.arch/arm64-0035-PCI-xgene-Add-APM-X-Gene-PCIe-driver.patch @@ -0,0 +1,808 @@ +From e94d45d47e17242c255c98e89852ff691b62bc80 Mon Sep 17 00:00:00 2001 +From: Tanmay Inamdar <tinamdar@apm.com> +Date: Wed, 1 Oct 2014 13:01:35 -0600 +Subject: [PATCH 35/38] PCI: xgene: Add APM X-Gene PCIe driver +Git-commit: 5f6b6ccdbe1cdfa5aa4347ec5412509b8995db27 +Patch-mainline: v3.18-rc1 +References: bnc#902632 + +Add the AppliedMicro X-Gene SOC PCIe host controller driver. The X-Gene +PCIe controller supports up to 8 lanes and GEN3 speed. The X-Gene SOC +supports up to 5 PCIe ports. + +[bhelgaas: folded in MAINTAINERS and bindings updates] +Tested-by: Ming Lei <ming.lei@canonical.com> +Tested-by: Dann Frazier <dann.frazier@canonical.com> +Signed-off-by: Tanmay Inamdar <tinamdar@apm.com> +Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> +Reviewed-by: Liviu Dudau <Liviu.Dudau@arm.com> (driver) +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + .../devicetree/bindings/pci/xgene-pci.txt | 57 ++ + MAINTAINERS | 8 + + drivers/pci/host/Kconfig | 10 + + drivers/pci/host/Makefile | 1 + + drivers/pci/host/pci-xgene.c | 659 +++++++++++++++++++++ + 5 files changed, 735 insertions(+) + create mode 100644 Documentation/devicetree/bindings/pci/xgene-pci.txt + create mode 100644 drivers/pci/host/pci-xgene.c + +diff --git a/Documentation/devicetree/bindings/pci/xgene-pci.txt b/Documentation/devicetree/bindings/pci/xgene-pci.txt +new file mode 100644 +index 0000000..1070b06 +--- /dev/null ++++ b/Documentation/devicetree/bindings/pci/xgene-pci.txt +@@ -0,0 +1,57 @@ ++* AppliedMicro X-Gene PCIe interface ++ ++Required properties: ++- device_type: set to "pci" ++- compatible: should contain "apm,xgene-pcie" to identify the core. ++- reg: A list of physical base address and length for each set of controller ++ registers. Must contain an entry for each entry in the reg-names ++ property. ++- reg-names: Must include the following entries: ++ "csr": controller configuration registers. ++ "cfg": pcie configuration space registers. ++- #address-cells: set to <3> ++- #size-cells: set to <2> ++- ranges: ranges for the outbound memory, I/O regions. ++- dma-ranges: ranges for the inbound memory regions. ++- #interrupt-cells: set to <1> ++- interrupt-map-mask and interrupt-map: standard PCI properties ++ to define the mapping of the PCIe interface to interrupt ++ numbers. ++- clocks: from common clock binding: handle to pci clock. ++ ++Optional properties: ++- status: Either "ok" or "disabled". ++- dma-coherent: Present if dma operations are coherent ++ ++Example: ++ ++SoC specific DT Entry: ++ ++ pcie0: pcie@1f2b0000 { ++ status = "disabled"; ++ device_type = "pci"; ++ compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ #address-cells = <3>; ++ reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ ++ 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */ ++ reg-names = "csr", "cfg"; ++ ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */ ++ 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */ ++ dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 ++ 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 ++ 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 ++ 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 ++ 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; ++ dma-coherent; ++ clocks = <&pcie0clk 0>; ++ }; ++ ++ ++Board specific DT Entry: ++ &pcie0 { ++ status = "ok"; ++ }; +diff --git a/MAINTAINERS b/MAINTAINERS +index c2066f4..b878713 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -6797,6 +6797,14 @@ F: include/linux/pci* + F: arch/x86/pci/ + F: arch/x86/kernel/quirks.c + ++PCI DRIVER FOR APPLIEDMICRO XGENE ++M: Tanmay Inamdar <tinamdar@apm.com> ++L: linux-pci@vger.kernel.org ++L: linux-arm-kernel@lists.infradead.org ++S: Maintained ++F: Documentation/devicetree/bindings/pci/xgene-pci.txt ++F: drivers/pci/host/pci-xgene.c ++ + PCI DRIVER FOR IMX6 + M: Richard Zhu <r65037@freescale.com> + M: Shawn Guo <shawn.guo@freescale.com> +diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig +index 21df477..3b988a2 100644 +--- a/drivers/pci/host/Kconfig ++++ b/drivers/pci/host/Kconfig +@@ -46,4 +46,14 @@ config PCI_HOST_GENERIC + Say Y here if you want to support a simple generic PCI host + controller, such as the one emulated by kvmtool. + ++config PCI_XGENE ++ bool "X-Gene PCIe controller" ++ depends on ARCH_XGENE ++ depends on OF ++ select PCIEPORTBUS ++ help ++ Say Y here if you want internal PCI support on APM X-Gene SoC. ++ There are 5 internal PCIe ports available. Each port is GEN3 capable ++ and have varied lanes from x1 to x8. ++ + endmenu +diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile +index 611ba4b..0801606 100644 +--- a/drivers/pci/host/Makefile ++++ b/drivers/pci/host/Makefile +@@ -6,3 +6,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o + obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o + obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o + obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o ++obj-$(CONFIG_PCI_XGENE) += pci-xgene.o +diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c +new file mode 100644 +index 0000000..9ecabfa +--- /dev/null ++++ b/drivers/pci/host/pci-xgene.c +@@ -0,0 +1,659 @@ ++/** ++ * APM X-Gene PCIe Driver ++ * ++ * Copyright (c) 2014 Applied Micro Circuits Corporation. ++ * ++ * Author: Tanmay Inamdar <tinamdar@apm.com>. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#include <linux/clk-private.h> ++#include <linux/delay.h> ++#include <linux/io.h> ++#include <linux/jiffies.h> ++#include <linux/memblock.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_address.h> ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++#include <linux/pci.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++ ++#define PCIECORE_CTLANDSTATUS 0x50 ++#define PIM1_1L 0x80 ++#define IBAR2 0x98 ++#define IR2MSK 0x9c ++#define PIM2_1L 0xa0 ++#define IBAR3L 0xb4 ++#define IR3MSKL 0xbc ++#define PIM3_1L 0xc4 ++#define OMR1BARL 0x100 ++#define OMR2BARL 0x118 ++#define OMR3BARL 0x130 ++#define CFGBARL 0x154 ++#define CFGBARH 0x158 ++#define CFGCTL 0x15c ++#define RTDID 0x160 ++#define BRIDGE_CFG_0 0x2000 ++#define BRIDGE_CFG_4 0x2010 ++#define BRIDGE_STATUS_0 0x2600 ++ ++#define LINK_UP_MASK 0x00000100 ++#define AXI_EP_CFG_ACCESS 0x10000 ++#define EN_COHERENCY 0xF0000000 ++#define EN_REG 0x00000001 ++#define OB_LO_IO 0x00000002 ++#define XGENE_PCIE_VENDORID 0x10E8 ++#define XGENE_PCIE_DEVICEID 0xE004 ++#define SZ_1T (SZ_1G*1024ULL) ++#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe) ++ ++struct xgene_pcie_port { ++ struct device_node *node; ++ struct device *dev; ++ struct clk *clk; ++ void __iomem *csr_base; ++ void __iomem *cfg_base; ++ unsigned long cfg_addr; ++ bool link_up; ++}; ++ ++static inline u32 pcie_bar_low_val(u32 addr, u32 flags) ++{ ++ return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; ++} ++ ++/* PCIe Configuration Out/In */ ++static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val) ++{ ++ writel(val, addr + offset); ++} ++ ++static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val) ++{ ++ u32 val32 = readl(addr + (offset & ~0x3)); ++ ++ switch (offset & 0x3) { ++ case 2: ++ val32 &= ~0xFFFF0000; ++ val32 |= (u32)val << 16; ++ break; ++ case 0: ++ default: ++ val32 &= ~0xFFFF; ++ val32 |= val; ++ break; ++ } ++ writel(val32, addr + (offset & ~0x3)); ++} ++ ++static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val) ++{ ++ u32 val32 = readl(addr + (offset & ~0x3)); ++ ++ switch (offset & 0x3) { ++ case 0: ++ val32 &= ~0xFF; ++ val32 |= val; ++ break; ++ case 1: ++ val32 &= ~0xFF00; ++ val32 |= (u32)val << 8; ++ break; ++ case 2: ++ val32 &= ~0xFF0000; ++ val32 |= (u32)val << 16; ++ break; ++ case 3: ++ default: ++ val32 &= ~0xFF000000; ++ val32 |= (u32)val << 24; ++ break; ++ } ++ writel(val32, addr + (offset & ~0x3)); ++} ++ ++static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val) ++{ ++ *val = readl(addr + offset); ++} ++ ++static inline void xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val) ++{ ++ *val = readl(addr + (offset & ~0x3)); ++ ++ switch (offset & 0x3) { ++ case 2: ++ *val >>= 16; ++ break; ++ } ++ ++ *val &= 0xFFFF; ++} ++ ++static inline void xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val) ++{ ++ *val = readl(addr + (offset & ~0x3)); ++ ++ switch (offset & 0x3) { ++ case 3: ++ *val = *val >> 24; ++ break; ++ case 2: ++ *val = *val >> 16; ++ break; ++ case 1: ++ *val = *val >> 8; ++ break; ++ } ++ *val &= 0xFF; ++} ++ ++/* ++ * When the address bit [17:16] is 2'b01, the Configuration access will be ++ * treated as Type 1 and it will be forwarded to external PCIe device. ++ */ ++static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) ++{ ++ struct xgene_pcie_port *port = bus->sysdata; ++ ++ if (bus->number >= (bus->primary + 1)) ++ return port->cfg_base + AXI_EP_CFG_ACCESS; ++ ++ return port->cfg_base; ++} ++ ++/* ++ * For Configuration request, RTDID register is used as Bus Number, ++ * Device Number and Function number of the header fields. ++ */ ++static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) ++{ ++ struct xgene_pcie_port *port = bus->sysdata; ++ unsigned int b, d, f; ++ u32 rtdid_val = 0; ++ ++ b = bus->number; ++ d = PCI_SLOT(devfn); ++ f = PCI_FUNC(devfn); ++ ++ if (!pci_is_root_bus(bus)) ++ rtdid_val = (b << 8) | (d << 3) | f; ++ ++ writel(rtdid_val, port->csr_base + RTDID); ++ /* read the register back to ensure flush */ ++ readl(port->csr_base + RTDID); ++} ++ ++/* ++ * X-Gene PCIe port uses BAR0-BAR1 of RC's configuration space as ++ * the translation from PCI bus to native BUS. Entire DDR region ++ * is mapped into PCIe space using these registers, so it can be ++ * reached by DMA from EP devices. The BAR0/1 of bridge should be ++ * hidden during enumeration to avoid the sizing and resource allocation ++ * by PCIe core. ++ */ ++static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset) ++{ ++ if (pci_is_root_bus(bus) && ((offset == PCI_BASE_ADDRESS_0) || ++ (offset == PCI_BASE_ADDRESS_1))) ++ return true; ++ ++ return false; ++} ++ ++static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct xgene_pcie_port *port = bus->sysdata; ++ void __iomem *addr; ++ ++ if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (xgene_pcie_hide_rc_bars(bus, offset)) { ++ *val = 0; ++ return PCIBIOS_SUCCESSFUL; ++ } ++ ++ xgene_pcie_set_rtdid_reg(bus, devfn); ++ addr = xgene_pcie_get_cfg_base(bus); ++ switch (len) { ++ case 1: ++ xgene_pcie_cfg_in8(addr, offset, val); ++ break; ++ case 2: ++ xgene_pcie_cfg_in16(addr, offset, val); ++ break; ++ default: ++ xgene_pcie_cfg_in32(addr, offset, val); ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct xgene_pcie_port *port = bus->sysdata; ++ void __iomem *addr; ++ ++ if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (xgene_pcie_hide_rc_bars(bus, offset)) ++ return PCIBIOS_SUCCESSFUL; ++ ++ xgene_pcie_set_rtdid_reg(bus, devfn); ++ addr = xgene_pcie_get_cfg_base(bus); ++ switch (len) { ++ case 1: ++ xgene_pcie_cfg_out8(addr, offset, (u8)val); ++ break; ++ case 2: ++ xgene_pcie_cfg_out16(addr, offset, (u16)val); ++ break; ++ default: ++ xgene_pcie_cfg_out32(addr, offset, val); ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops xgene_pcie_ops = { ++ .read = xgene_pcie_read_config, ++ .write = xgene_pcie_write_config ++}; ++ ++static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr, ++ u32 flags, u64 size) ++{ ++ u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags; ++ u32 val32 = 0; ++ u32 val; ++ ++ val32 = readl(csr_base + addr); ++ val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16); ++ writel(val, csr_base + addr); ++ ++ val32 = readl(csr_base + addr + 0x04); ++ val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16); ++ writel(val, csr_base + addr + 0x04); ++ ++ val32 = readl(csr_base + addr + 0x04); ++ val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16); ++ writel(val, csr_base + addr + 0x04); ++ ++ val32 = readl(csr_base + addr + 0x08); ++ val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16); ++ writel(val, csr_base + addr + 0x08); ++ ++ return mask; ++} ++ ++static void xgene_pcie_linkup(struct xgene_pcie_port *port, ++ u32 *lanes, u32 *speed) ++{ ++ void __iomem *csr_base = port->csr_base; ++ u32 val32; ++ ++ port->link_up = false; ++ val32 = readl(csr_base + PCIECORE_CTLANDSTATUS); ++ if (val32 & LINK_UP_MASK) { ++ port->link_up = true; ++ *speed = PIPE_PHY_RATE_RD(val32); ++ val32 = readl(csr_base + BRIDGE_STATUS_0); ++ *lanes = val32 >> 26; ++ } ++} ++ ++static int xgene_pcie_init_port(struct xgene_pcie_port *port) ++{ ++ int rc; ++ ++ port->clk = clk_get(port->dev, NULL); ++ if (IS_ERR(port->clk)) { ++ dev_err(port->dev, "clock not available\n"); ++ return -ENODEV; ++ } ++ ++ rc = clk_prepare_enable(port->clk); ++ if (rc) { ++ dev_err(port->dev, "clock enable failed\n"); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static int xgene_pcie_map_reg(struct xgene_pcie_port *port, ++ struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr"); ++ port->csr_base = devm_ioremap_resource(port->dev, res); ++ if (IS_ERR(port->csr_base)) ++ return PTR_ERR(port->csr_base); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg"); ++ port->cfg_base = devm_ioremap_resource(port->dev, res); ++ if (IS_ERR(port->cfg_base)) ++ return PTR_ERR(port->cfg_base); ++ port->cfg_addr = res->start; ++ ++ return 0; ++} ++ ++static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port, ++ struct resource *res, u32 offset, ++ u64 cpu_addr, u64 pci_addr) ++{ ++ void __iomem *base = port->csr_base + offset; ++ resource_size_t size = resource_size(res); ++ u64 restype = resource_type(res); ++ u64 mask = 0; ++ u32 min_size; ++ u32 flag = EN_REG; ++ ++ if (restype == IORESOURCE_MEM) { ++ min_size = SZ_128M; ++ } else { ++ min_size = 128; ++ flag |= OB_LO_IO; ++ } ++ ++ if (size >= min_size) ++ mask = ~(size - 1) | flag; ++ else ++ dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n", ++ (u64)size, min_size); ++ ++ writel(lower_32_bits(cpu_addr), base); ++ writel(upper_32_bits(cpu_addr), base + 0x04); ++ writel(lower_32_bits(mask), base + 0x08); ++ writel(upper_32_bits(mask), base + 0x0c); ++ writel(lower_32_bits(pci_addr), base + 0x10); ++ writel(upper_32_bits(pci_addr), base + 0x14); ++} ++ ++static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr) ++{ ++ writel(lower_32_bits(addr), csr_base + CFGBARL); ++ writel(upper_32_bits(addr), csr_base + CFGBARH); ++ writel(EN_REG, csr_base + CFGCTL); ++} ++ ++static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, ++ struct list_head *res, ++ resource_size_t io_base) ++{ ++ struct pci_host_bridge_window *window; ++ struct device *dev = port->dev; ++ int ret; ++ ++ list_for_each_entry(window, res, list) { ++ struct resource *res = window->res; ++ u64 restype = resource_type(res); ++ ++ dev_dbg(port->dev, "%pR\n", res); ++ ++ switch (restype) { ++ case IORESOURCE_IO: ++ xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base, ++ res->start - window->offset); ++ ret = pci_remap_iospace(res, io_base); ++ if (ret < 0) ++ return ret; ++ break; ++ case IORESOURCE_MEM: ++ xgene_pcie_setup_ob_reg(port, res, OMR1BARL, res->start, ++ res->start - window->offset); ++ break; ++ case IORESOURCE_BUS: ++ break; ++ default: ++ dev_err(dev, "invalid resource %pR\n", res); ++ return -EINVAL; ++ } ++ } ++ xgene_pcie_setup_cfg_reg(port->csr_base, port->cfg_addr); ++ ++ return 0; ++} ++ ++static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size) ++{ ++ writel(lower_32_bits(pim), addr); ++ writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04); ++ writel(lower_32_bits(size), addr + 0x10); ++ writel(upper_32_bits(size), addr + 0x14); ++} ++ ++/* ++ * X-Gene PCIe support maximum 3 inbound memory regions ++ * This function helps to select a region based on size of region ++ */ ++static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size) ++{ ++ if ((size > 4) && (size < SZ_16M) && !(*ib_reg_mask & (1 << 1))) { ++ *ib_reg_mask |= (1 << 1); ++ return 1; ++ } ++ ++ if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) { ++ *ib_reg_mask |= (1 << 0); ++ return 0; ++ } ++ ++ if ((size > SZ_1M) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 2))) { ++ *ib_reg_mask |= (1 << 2); ++ return 2; ++ } ++ ++ return -EINVAL; ++} ++ ++static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port, ++ struct of_pci_range *range, u8 *ib_reg_mask) ++{ ++ void __iomem *csr_base = port->csr_base; ++ void __iomem *cfg_base = port->cfg_base; ++ void *bar_addr; ++ void *pim_addr; ++ u64 cpu_addr = range->cpu_addr; ++ u64 pci_addr = range->pci_addr; ++ u64 size = range->size; ++ u64 mask = ~(size - 1) | EN_REG; ++ u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64; ++ u32 bar_low; ++ int region; ++ ++ region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size); ++ if (region < 0) { ++ dev_warn(port->dev, "invalid pcie dma-range config\n"); ++ return; ++ } ++ ++ if (range->flags & IORESOURCE_PREFETCH) ++ flags |= PCI_BASE_ADDRESS_MEM_PREFETCH; ++ ++ bar_low = pcie_bar_low_val((u32)cpu_addr, flags); ++ switch (region) { ++ case 0: ++ xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size); ++ bar_addr = cfg_base + PCI_BASE_ADDRESS_0; ++ writel(bar_low, bar_addr); ++ writel(upper_32_bits(cpu_addr), bar_addr + 0x4); ++ pim_addr = csr_base + PIM1_1L; ++ break; ++ case 1: ++ bar_addr = csr_base + IBAR2; ++ writel(bar_low, bar_addr); ++ writel(lower_32_bits(mask), csr_base + IR2MSK); ++ pim_addr = csr_base + PIM2_1L; ++ break; ++ case 2: ++ bar_addr = csr_base + IBAR3L; ++ writel(bar_low, bar_addr); ++ writel(upper_32_bits(cpu_addr), bar_addr + 0x4); ++ writel(lower_32_bits(mask), csr_base + IR3MSKL); ++ writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4); ++ pim_addr = csr_base + PIM3_1L; ++ break; ++ } ++ ++ xgene_pcie_setup_pims(pim_addr, pci_addr, ~(size - 1)); ++} ++ ++static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, ++ struct device_node *node) ++{ ++ const int na = 3, ns = 2; ++ int rlen; ++ ++ parser->node = node; ++ parser->pna = of_n_addr_cells(node); ++ parser->np = parser->pna + na + ns; ++ ++ parser->range = of_get_property(node, "dma-ranges", &rlen); ++ if (!parser->range) ++ return -ENOENT; ++ parser->end = parser->range + rlen / sizeof(__be32); ++ ++ return 0; ++} ++ ++static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port) ++{ ++ struct device_node *np = port->node; ++ struct of_pci_range range; ++ struct of_pci_range_parser parser; ++ struct device *dev = port->dev; ++ u8 ib_reg_mask = 0; ++ ++ if (pci_dma_range_parser_init(&parser, np)) { ++ dev_err(dev, "missing dma-ranges property\n"); ++ return -EINVAL; ++ } ++ ++ /* Get the dma-ranges from DT */ ++ for_each_of_pci_range(&parser, &range) { ++ u64 end = range.cpu_addr + range.size - 1; ++ ++ dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n", ++ range.flags, range.cpu_addr, end, range.pci_addr); ++ xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask); ++ } ++ return 0; ++} ++ ++/* clear BAR configuration which was done by firmware */ ++static void xgene_pcie_clear_config(struct xgene_pcie_port *port) ++{ ++ int i; ++ ++ for (i = PIM1_1L; i <= CFGCTL; i += 4) ++ writel(0x0, port->csr_base + i); ++} ++ ++static int xgene_pcie_setup(struct xgene_pcie_port *port, ++ struct list_head *res, ++ resource_size_t io_base) ++{ ++ u32 val, lanes = 0, speed = 0; ++ int ret; ++ ++ xgene_pcie_clear_config(port); ++ ++ /* setup the vendor and device IDs correctly */ ++ val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID; ++ writel(val, port->csr_base + BRIDGE_CFG_0); ++ ++ ret = xgene_pcie_map_ranges(port, res, io_base); ++ if (ret) ++ return ret; ++ ++ ret = xgene_pcie_parse_map_dma_ranges(port); ++ if (ret) ++ return ret; ++ ++ xgene_pcie_linkup(port, &lanes, &speed); ++ if (!port->link_up) ++ dev_info(port->dev, "(rc) link down\n"); ++ else ++ dev_info(port->dev, "(rc) x%d gen-%d link up\n", ++ lanes, speed + 1); ++ return 0; ++} ++ ++static int xgene_pcie_probe_bridge(struct platform_device *pdev) ++{ ++ struct device_node *dn = pdev->dev.of_node; ++ struct xgene_pcie_port *port; ++ resource_size_t iobase = 0; ++ struct pci_bus *bus; ++ int ret; ++ LIST_HEAD(res); ++ ++ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); ++ if (!port) ++ return -ENOMEM; ++ port->node = of_node_get(pdev->dev.of_node); ++ port->dev = &pdev->dev; ++ ++ ret = xgene_pcie_map_reg(port, pdev); ++ if (ret) ++ return ret; ++ ++ ret = xgene_pcie_init_port(port); ++ if (ret) ++ return ret; ++ ++ ret = of_pci_get_host_bridge_resources(dn, 0, 0xff, &res, &iobase); ++ if (ret) ++ return ret; ++ ++ ret = xgene_pcie_setup(port, &res, iobase); ++ if (ret) ++ return ret; ++ ++ bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res); ++ if (!bus) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, port); ++ return 0; ++} ++ ++static const struct of_device_id xgene_pcie_match_table[] = { ++ {.compatible = "apm,xgene-pcie",}, ++ {}, ++}; ++ ++static struct platform_driver xgene_pcie_driver = { ++ .driver = { ++ .name = "xgene-pcie", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(xgene_pcie_match_table), ++ }, ++ .probe = xgene_pcie_probe_bridge, ++}; ++module_platform_driver(xgene_pcie_driver); ++ ++MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>"); ++MODULE_DESCRIPTION("APM X-Gene PCIe driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.1.0 + diff --git a/patches.arch/arm64-0036-arm64-Do-not-call-enable-PCI-resources-when-specify-.patch b/patches.arch/arm64-0036-arm64-Do-not-call-enable-PCI-resources-when-specify-.patch new file mode 100644 index 0000000..2d503c6 --- /dev/null +++ b/patches.arch/arm64-0036-arm64-Do-not-call-enable-PCI-resources-when-specify-.patch @@ -0,0 +1,45 @@ +From 6d89b22ee2b46b9105c33c3b3f38868a5c85299c Mon Sep 17 00:00:00 2001 +From: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Date: Sun, 28 Sep 2014 15:53:29 -0500 +Subject: [PATCH 36/38] arm64: Do not call enable PCI resources when specify + PCI_PROBE_ONLY +Patch-mainline: No +References: bnc#902632 + +When specify PCI_PROBE_ONLY, the resource parent does not get assigned. +Therefore, pci_enable_resources() return error saying that +"BAR x not claimed". + +Note: This same logic is also used in the arch/arm/kernel/bios32.c + +Cc: Liviu Dudau <Liviu.Dudau@arm.com> +Cc: Bjorn Helgaas <bhelgaas@google.com> +Cc: Will Deacon <will.deacon@arm.com> +Cc: Catalin Marinas <catalin.marinas@arm.com> +Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> +Signed-off-by: Alexander Graf <agraf@suse.de> +(cherry picked from commit ) + +--- + arch/arm64/kernel/pci.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c +index ce5836c..7fd4d2b 100644 +--- a/arch/arm64/kernel/pci.c ++++ b/arch/arm64/kernel/pci.c +@@ -68,3 +68,11 @@ void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) + bus->domain_nr = domain; + } + #endif ++ ++int pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ if (pci_has_flag(PCI_PROBE_ONLY)) ++ return 0; ++ ++ return pci_enable_resources(dev, mask); ++} +-- +2.1.0 + diff --git a/patches.arch/arm64-0037-drivers-net-fddi-skfp-h-skfbi.h-Remove-useless-PCI_B.patch b/patches.arch/arm64-0037-drivers-net-fddi-skfp-h-skfbi.h-Remove-useless-PCI_B.patch new file mode 100644 index 0000000..8824aca --- /dev/null +++ b/patches.arch/arm64-0037-drivers-net-fddi-skfp-h-skfbi.h-Remove-useless-PCI_B.patch @@ -0,0 +1,53 @@ +From ee54dd2bc5371cd0de61bed5286ec16d0bb28083 Mon Sep 17 00:00:00 2001 +From: Chen Gang <gang.chen.5i5j@gmail.com> +Date: Wed, 3 Sep 2014 23:26:26 +0800 +Subject: [PATCH 37/38] drivers/net/fddi/skfp/h/skfbi.h: Remove useless + PCI_BASE_2ND macros +Git-commit: 4357450af3422219d3f77bd54f7b9a8a40f193c9 +Patch-mainline: v3.17-rc5 +References: bnc#902632 + +They are use less, and may generate compiling warnings, so remove them +(microblaze, arc, arm64, and unicore32 have already defined PCI_IOBASE). + +The related warnings (with allmodconfig under microblaze): + + CC [M] drivers/net/fddi/skfp/skfddi.o + In file included from drivers/net/fddi/skfp/skfddi.c:95:0: + drivers/net/fddi/skfp/h/skfbi.h:151:0: warning: "PCI_IOBASE" redefined + #define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ + ^ + In file included from include/linux/io.h:22:0, + from include/linux/pci.h:31, + from drivers/net/fddi/skfp/skfddi.c:82: + ./arch/microblaze/include/asm/io.h:33:0: note: this is the location of the previous definition + #define PCI_IOBASE ((void __iomem *)_IO_BASE) + ^ + +Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + drivers/net/fddi/skfp/h/skfbi.h | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/net/fddi/skfp/h/skfbi.h b/drivers/net/fddi/skfp/h/skfbi.h +index c1ba26c..3de2f0d 100644 +--- a/drivers/net/fddi/skfp/h/skfbi.h ++++ b/drivers/net/fddi/skfp/h/skfbi.h +@@ -147,11 +147,6 @@ + #define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */ + #define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */ + +-/* PCI_BASE_2ND 32 bit 2nd Base address */ +-#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ +-#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ +-#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */ +- + /* PCI_SUB_VID 16 bit Subsystem Vendor ID */ + /* PCI_SUB_ID 16 bit Subsystem ID */ + +-- +2.1.0 + diff --git a/patches.arch/arm64-0038-arm64-mustang-Disable-sgenet-and-xgenet.patch b/patches.arch/arm64-0038-arm64-mustang-Disable-sgenet-and-xgenet.patch new file mode 100644 index 0000000..4b6a137 --- /dev/null +++ b/patches.arch/arm64-0038-arm64-mustang-Disable-sgenet-and-xgenet.patch @@ -0,0 +1,36 @@ +From 9e91c807c8800b22b066cca39d4f10fa1ad4d02b Mon Sep 17 00:00:00 2001 +From: Alexander Graf <agraf@suse.de> +Date: Mon, 27 Oct 2014 09:41:51 +0100 +Subject: [PATCH 38/38] arm64/mustang: Disable sgenet and xgenet +Patch-mainline: No +References: bnc#902632 + +The SGMII and XGMII ethernet interfaces oops on bootup. Disable them +for now. + +Signed-off-by: Alexander Graf <agraf@suse.de> + +--- + arch/arm64/boot/dts/apm-mustang.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts +index 2e25de0..40d2718 100644 +--- a/arch/arm64/boot/dts/apm-mustang.dts ++++ b/arch/arm64/boot/dts/apm-mustang.dts +@@ -41,6 +41,7 @@ + status = "ok"; + }; + ++/* + &sgenet0 { + status = "ok"; + }; +@@ -48,3 +49,4 @@ + &xgenet { + status = "ok"; + }; ++*/ +-- +2.1.0 + diff --git a/patches.xen/xen-x86-EFI b/patches.xen/xen-x86-EFI index d05c1c1..6446e0e 100644 --- a/patches.xen/xen-x86-EFI +++ b/patches.xen/xen-x86-EFI @@ -3,8 +3,10 @@ From: jbeulich@novell.com Patch-mainline: n/a References: fate#311376, fate#311529, bnc#578927, bnc#628554 ---- 13.2.orig/arch/x86/Kconfig 2014-01-07 17:30:52.000000000 +0100 -+++ 13.2/arch/x86/Kconfig 2014-09-19 11:19:05.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/arch/x86/Kconfig +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/Kconfig ++++ linux-3.16-openSUSE-13.2/arch/x86/Kconfig @@ -1571,7 +1571,7 @@ config X86_SMAP config EFI @@ -23,8 +25,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 select RELOCATABLE ---help--- This kernel feature allows a bzImage to be loaded directly ---- 13.2.orig/arch/x86/include/mach-xen/asm/setup.h 2011-02-01 14:54:13.000000000 +0100 -+++ 13.2/arch/x86/include/mach-xen/asm/setup.h 2011-07-04 12:32:43.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/arch/x86/include/mach-xen/asm/setup.h +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/include/mach-xen/asm/setup.h ++++ linux-3.16-openSUSE-13.2/arch/x86/include/mach-xen/asm/setup.h @@ -3,6 +3,12 @@ void xen_start_kernel(void); void xen_arch_setup(void); @@ -38,8 +42,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 #endif #include_next <asm/setup.h> ---- 13.2.orig/arch/x86/kernel/rtc.c 2013-12-02 17:19:30.000000000 +0100 -+++ 13.2/arch/x86/kernel/rtc.c 2013-08-12 17:57:09.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/arch/x86/kernel/rtc.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/kernel/rtc.c ++++ linux-3.16-openSUSE-13.2/arch/x86/kernel/rtc.c @@ -7,6 +7,7 @@ #include <linux/bcd.h> #include <linux/export.h> @@ -61,8 +67,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 /* Intel MID platforms don't have ioport rtc */ if (intel_mid_identify_cpu()) return -ENODEV; ---- 13.2.orig/arch/x86/kernel/setup-xen.c 2013-12-11 11:21:49.000000000 +0100 -+++ 13.2/arch/x86/kernel/setup-xen.c 2013-12-11 11:25:16.000000000 +0100 +Index: linux-3.16-openSUSE-13.2/arch/x86/kernel/setup-xen.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/kernel/setup-xen.c ++++ linux-3.16-openSUSE-13.2/arch/x86/kernel/setup-xen.c @@ -1105,6 +1105,8 @@ void __init setup_arch(char **cmdline_p) xen_start_info->console.dom0.info_size); xen_start_info->console.domU.mfn = 0; @@ -72,8 +80,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 } else screen_info.orig_video_isVGA = 0; copy_edid(); ---- 13.2.orig/arch/x86/kernel/time-xen.c 2014-01-28 16:22:52.000000000 +0100 -+++ 13.2/arch/x86/kernel/time-xen.c 2014-01-28 16:22:57.000000000 +0100 +Index: linux-3.16-openSUSE-13.2/arch/x86/kernel/time-xen.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/kernel/time-xen.c ++++ linux-3.16-openSUSE-13.2/arch/x86/kernel/time-xen.c @@ -19,6 +19,7 @@ #include <linux/posix-timers.h> #include <linux/cpufreq.h> @@ -92,16 +102,20 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 return mach_set_rtc_mmss(now); } ---- 13.2.orig/arch/x86/platform/efi/Makefile 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/arch/x86/platform/efi/Makefile 2014-05-02 16:30:28.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/arch/x86/platform/efi/Makefile +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/arch/x86/platform/efi/Makefile ++++ linux-3.16-openSUSE-13.2/arch/x86/platform/efi/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_EFI) += efi.o efi_$(BITS) obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o obj-$(CONFIG_EARLY_PRINTK_EFI) += early_printk.o obj-$(CONFIG_EFI_MIXED) += efi_thunk_$(BITS).o +ccflags-$(CONFIG_XEN) += -fshort-wchar +disabled-obj-$(CONFIG_XEN) := efi_%$(BITS).o ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ 13.2/arch/x86/platform/efi/efi-xen.c 2014-04-30 11:55:13.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/arch/x86/platform/efi/efi-xen.c +=================================================================== +--- /dev/null ++++ linux-3.16-openSUSE-13.2/arch/x86/platform/efi/efi-xen.c @@ -0,0 +1,602 @@ +/* + * Common EFI (Extensible Firmware Interface) support functions @@ -705,8 +719,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 + return EFI_SUCCESS; +} +EXPORT_SYMBOL_GPL(efi_query_variable_store); ---- 13.2.orig/drivers/firmware/efi/efi.c 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/drivers/firmware/efi/efi.c 2014-05-02 16:30:39.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/drivers/firmware/efi/efi.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/drivers/firmware/efi/efi.c ++++ linux-3.16-openSUSE-13.2/drivers/firmware/efi/efi.c @@ -202,6 +202,7 @@ subsys_initcall(efisubsys_init); */ void __iomem *efi_lookup_mapped_addr(u64 phys_addr) @@ -794,19 +810,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 set_bit(EFI_CONFIG_TABLES, &efi.flags); ---- 13.2.orig/drivers/rtc/Kconfig 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/drivers/rtc/Kconfig 2013-12-11 11:25:07.000000000 +0100 -@@ -789,7 +789,7 @@ config RTC_DRV_DA9063 - - config RTC_DRV_EFI - tristate "EFI RTC" -- depends on IA64 -+ depends on IA64 || (XEN && EFI) - help - If you say yes here you will get support for the EFI - Real Time Clock. ---- 13.2.orig/drivers/rtc/rtc-cmos.c 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/drivers/rtc/rtc-cmos.c 2014-02-20 15:49:55.000000000 +0100 +Index: linux-3.16-openSUSE-13.2/drivers/rtc/rtc-cmos.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/drivers/rtc/rtc-cmos.c ++++ linux-3.16-openSUSE-13.2/drivers/rtc/rtc-cmos.c @@ -36,6 +36,7 @@ #include <linux/platform_device.h> #include <linux/log2.h> @@ -827,8 +834,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 #ifdef CONFIG_PNP retval = pnp_register_driver(&cmos_pnp_driver); if (retval == 0) ---- 13.2.orig/drivers/rtc/rtc-efi.c 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/drivers/rtc/rtc-efi.c 2013-08-12 17:57:27.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/drivers/rtc/rtc-efi.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/drivers/rtc/rtc-efi.c ++++ linux-3.16-openSUSE-13.2/drivers/rtc/rtc-efi.c @@ -213,3 +213,6 @@ module_platform_driver_probe(efi_rtc_dri MODULE_AUTHOR("dann frazier <dannf@hp.com>"); MODULE_LICENSE("GPL"); @@ -836,9 +845,11 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 +#ifdef CONFIG_XEN +MODULE_ALIAS("platform:rtc-efi"); +#endif ---- 13.2.orig/drivers/xen/console/console.c 2012-03-22 14:31:13.000000000 +0100 -+++ 13.2/drivers/xen/console/console.c 2012-03-22 15:29:12.000000000 +0100 -@@ -313,6 +313,7 @@ void __init dom0_init_screen_info(const +Index: linux-3.16-openSUSE-13.2/drivers/xen/console/console.c +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/drivers/xen/console/console.c ++++ linux-3.16-openSUSE-13.2/drivers/xen/console/console.c +@@ -313,6 +313,7 @@ void __init dom0_init_screen_info(const break; case XEN_VGATYPE_VESA_LFB: @@ -846,7 +857,7 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 if (size < offsetof(struct dom0_vga_console_info, u.vesa_lfb.gbl_caps)) break; -@@ -331,6 +332,10 @@ void __init dom0_init_screen_info(const +@@ -331,6 +332,10 @@ void __init dom0_init_screen_info(const screen_info.blue_pos = info->u.vesa_lfb.blue_pos; screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size; screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos; @@ -857,8 +868,10 @@ References: fate#311376, fate#311529, bnc#578927, bnc#628554 if (size >= offsetof(struct dom0_vga_console_info, u.vesa_lfb.gbl_caps) + sizeof(info->u.vesa_lfb.gbl_caps)) ---- 13.2.orig/include/linux/efi.h 2014-10-16 11:41:00.000000000 +0200 -+++ 13.2/include/linux/efi.h 2014-05-02 16:30:29.000000000 +0200 +Index: linux-3.16-openSUSE-13.2/include/linux/efi.h +=================================================================== +--- linux-3.16-openSUSE-13.2.orig/include/linux/efi.h ++++ linux-3.16-openSUSE-13.2/include/linux/efi.h @@ -797,7 +797,9 @@ typedef struct _efi_file_io_interface { * All runtime access to EFI goes through this structure: */ diff --git a/series.conf b/series.conf index 671dbb9..5dba0be 100644 --- a/series.conf +++ b/series.conf @@ -168,7 +168,44 @@ patches.arch/arm-arndale-dma.patch patches.arch/arm-arndale-usb-phy.patch patches.arch/arm-exynos-dwmmc-modalias.patch - patches.arch/arm64-crypto-fix-makefile-rule.patch + patches.arch/arm64-0001-usb-Add-support-for-Synopsis-H20AHB-EHCI-host-contro.patch + patches.arch/arm64-0002-usb-fix-hcd-h20ahb-driver-depends.patch + patches.arch/arm64-0003-cpufreq-arm_big_little-fix-module-license-spec.patch + patches.arch/arm64-0004-ahci-Check-and-set-64-bit-DMA-mask-for-platform-AHCI.patch + patches.arch/arm64-0005-arm64-crypto-fix-makefile-rule-for-aes-glue-.o.patch + patches.arch/arm64-0006-rtc-ia64-allow-other-architectures-to-use-EFI-RTC.patch + patches.arch/arm64-0007-arm64-fix-VTTBR_BADDR_MASK.patch + patches.arch/arm64-0008-KVM-ARM-Add-arm-gic-400-compatible-support.patch + patches.arch/arm64-0009-net-xgbe-Add-A0-silicon-support.patch + patches.arch/arm64-0010-KVM-ARM-Hack-to-enable-VGIC-mapping-on-64k-PAGE_SIZE.patch + patches.arch/arm64-0011-ARM-Add-APM-Mustang-network-driver.patch + patches.arch/arm64-0012-ahci_xgene-Skip-the-PHY-and-clock-initialization-if-.patch + patches.arch/arm64-0013-arm64-adjust-el0_sync-so-that-a-function-can-be-call.patch + patches.arch/arm64-0014-arm-arm64-KVM-Fix-and-refactor-unmap_range.patch + patches.arch/arm64-0015-arm64-fpsimd-fix-a-typo-in-fpsimd_save_partial_state.patch + patches.arch/arm64-0016-arm64-fix-bug-for-reloading-FPSIMD-state-after-cpu-p.patch + patches.arch/arm64-0017-ahci-xgene-Remove-logic-to-set-64-bit-DMA-mask.patch + patches.arch/arm64-0018-arm64-dts-Add-X-Gene-reboot-driver-dts-node.patch + patches.arch/arm64-0019-power-reset-Add-generic-SYSCON-register-mapped-reset.patch + patches.arch/arm64-0020-arm64-Select-reboot-driver-for-X-Gene-platform.patch + patches.arch/arm64-0021-power-reset-Remove-X-Gene-reboot-driver.patch + patches.arch/arm64-0022-irqchip-gic-preserve-gic-V2-bypass-bits-in-cpu-ctrl-.patch + patches.arch/arm64-0023-arm64-efi-efistub-cover-entire-static-mem-footprint-.patch + patches.arch/arm64-0024-arm64-efi-efistub-don-t-abort-if-base-of-DRAM-is-occ.patch + patches.arch/arm64-0025-asm-generic-io.h-Fix-ioport_map-for-CONFIG_GENERIC_I.patch + patches.arch/arm64-0026-of-pci-Add-pci_register_io_range-and-pci_pio_to_addr.patch + patches.arch/arm64-0027-ARM-Define-PCI_IOBASE-as-the-base-of-virtual-PCI-IO-.patch + patches.arch/arm64-0028-of-pci-Move-of_pci_range_to_resource-to-of-address.c.patch + patches.arch/arm64-0029-of-pci-Fix-the-conversion-of-IO-ranges-into-IO-resou.patch + patches.arch/arm64-0030-PCI-Add-generic-domain-handling.patch + patches.arch/arm64-0031-of-pci-Add-pci_get_new_domain_nr-and-of_get_pci_doma.patch + patches.arch/arm64-0032-of-pci-Add-support-for-parsing-PCI-host-bridge-resou.patch + patches.arch/arm64-0033-PCI-Add-pci_remap_iospace-to-map-bus-I-O-resources.patch + patches.arch/arm64-0034-arm64-Add-architectural-support-for-PCI.patch + patches.arch/arm64-0035-PCI-xgene-Add-APM-X-Gene-PCIe-driver.patch + patches.arch/arm64-0036-arm64-Do-not-call-enable-PCI-resources-when-specify-.patch + patches.arch/arm64-0037-drivers-net-fddi-skfp-h-skfbi.h-Remove-useless-PCI_B.patch + patches.arch/arm64-0038-arm64-mustang-Disable-sgenet-and-xgenet.patch ######################################################## # S/390 -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Alexander Graf <agraf@suse.de> writes:
++ buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
You'll probably need to rename that. You'll probably also need to rename all public functions to avoid conflicts. Andreas. -- Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7 "And now for something completely different." -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On 28.10.14 09:54, Andreas Schwab wrote:
Alexander Graf <agraf@suse.de> writes:
++ buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
You'll probably need to rename that. You'll probably also need to rename all public functions to avoid conflicts.
As long as it gets built as a module public functions don't hurt. The above can also never conflict, as there's either A0 or B0 silicon in a SoC - never both at the same time. Alex -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Alexander Graf <agraf@suse.de> writes:
On 28.10.14 09:54, Andreas Schwab wrote:
Alexander Graf <agraf@suse.de> writes:
++ buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
You'll probably need to rename that. You'll probably also need to rename all public functions to avoid conflicts.
As long as it gets built as a module public functions don't hurt. The above can also never conflict, as there's either A0 or B0 silicon in a SoC - never both at the same time.
You can still load both modules, causing two modules providing the same symbols. Andreas. -- Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7 "And now for something completely different." -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On 28.10.14 10:11, Andreas Schwab wrote:
Alexander Graf <agraf@suse.de> writes:
On 28.10.14 09:54, Andreas Schwab wrote:
Alexander Graf <agraf@suse.de> writes:
++ buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
You'll probably need to rename that. You'll probably also need to rename all public functions to avoid conflicts.
As long as it gets built as a module public functions don't hurt. The above can also never conflict, as there's either A0 or B0 silicon in a SoC - never both at the same time.
You can still load both modules, causing two modules providing the same symbols.
True, I've changed the debugfs string above. Kernel module symbols only conflict when they're exported - and this driver doesn't export any symbols. So there shouldn't be a conflict on symbol names ever :). Alex -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 10/27/14, 9:39 PM, Alexander Graf wrote:
Hi kernel gurus,
There were quite a good number of bug fixes and necessary features in post-3.16 as well as some patches that are missing upstream to make arm64 a shiny out of the box experience.
I would like to shove the patches below into our openSUSE-13.2 branch. I have a properly trimmed down (and adjusted) version of the changes below based on 3.18 and an untested variant on top of 3.17.
What is the strategy with 13.2 going to be? Are we going to uprev the kernel for it? Is it going to jump to 3.17, so should I push the changes here into the 13.2 branch the stable branch and the master branch? Or would master and 13.2 suffice?
Also, if you think the changes below are too intrusive, please let me know. I've tried to double-check that they basically only touch arm64 specific code paths with a few shared ppc blocks. But the likelyhood for x86 breakage is low:
I suppose the first question is for the ARM folks: Do you have any need/intention of keeping the kABI stable? If so, then a lot of this patchset won't fly. - -Jeff - -- Jeff Mahoney SUSE Labs -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.19 (Darwin) iQIcBAEBAgAGBQJUUBN6AAoJEB57S2MheeWyjXoP/1CZuV0UzOkw1YgSNIXzuMfr y7cDiUbcoFL3rbVqtmVY9LVHGrlMy0UcXsNCDKx9VZzADSUn+ejyHSJkk67wpliY uZ9DprN9T2R79CHzVMJiMS8s2op5qBXbC3XsXkjtZmXhbroDYmWt2JbVzf50lHDl BWsTZlTGw52n1a669pY3WTkfHmqgK5xxfnEsROFfJ2Bxg3RpFeyFvQP0MSudAmxC QwJ97xSk2xe+wsA4NCa6Lfo3x6bJiD8hE0Mk6/N//0s3NYQ9GaIeUz6oDrCh186d oEg9+VQ2SozW4g9Zxt/DV+JK/8GWKCLhL/KvzMQnN7wrWS5fdLkGFTwRAZhjZoog tLXj2klfZYfG0z1MLnc+d89AX6SzUjS6YpmOi4AoBDUtyEkfXC/T5toaqHB2/JLq yjtkclYThnpysavj/WXtptMYUDqvJJu/T0Dnr3074kmr5TeoSJ6jOQ2Py/nfoyOd w8CR3BYZmjgVSPNdjMItmXq2IJ9pjOEWbdAyRmfzWswZBo07Jsz859DxHz2r9ARf ZAlEf8H0Eb+b2+M4a6xryMbAavk5k9QkK6XoWaE9d6G6x3oAFwVo14BbIGbCJwnh DzxCJ2P9YmyT4kbju4BrKgDZfkOlLVQE4BgSG3o/lFMtdYKiVu3EHVpF+6FX/VBC 69xjhNIb/UtF3T+yjvfg =Tg0e -----END PGP SIGNATURE----- -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Am 28.10.2014 um 23:06 schrieb Jeff Mahoney <jeffm@suse.com>:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 10/27/14, 9:39 PM, Alexander Graf wrote: Hi kernel gurus,
There were quite a good number of bug fixes and necessary features in post-3.16 as well as some patches that are missing upstream to make arm64 a shiny out of the box experience.
I would like to shove the patches below into our openSUSE-13.2 branch. I have a properly trimmed down (and adjusted) version of the changes below based on 3.18 and an untested variant on top of 3.17.
What is the strategy with 13.2 going to be? Are we going to uprev the kernel for it? Is it going to jump to 3.17, so should I push the changes here into the 13.2 branch the stable branch and the master branch? Or would master and 13.2 suffice?
Also, if you think the changes below are too intrusive, please let me know. I've tried to double-check that they basically only touch arm64 specific code paths with a few shared ppc blocks. But the likelyhood for x86 breakage is low:
I suppose the first question is for the ARM folks: Do you have any need/intention of keeping the kABI stable? If so, then a lot of this patchset won't fly.
I don't think it makes sense to have a stable kabi on something that runs on 0 platforms ;). People won't be able to tell the difference, because the unpatched kernel wouldn't run on anything and we'd have to make the patched one the minimum version people compile against. Alex -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Alexander Graf <agraf@suse.de> writes:
+diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile +index a38a2dc..2dd45df 100644 +--- a/drivers/net/ethernet/amd/Makefile ++++ b/drivers/net/ethernet/amd/Makefile +@@ -17,4 +17,4 @@ obj-$(CONFIG_NI65) += ni65.o + obj-$(CONFIG_PCNET32) += pcnet32.o + obj-$(CONFIG_SUN3LANCE) += sun3lance.o + obj-$(CONFIG_SUNLANCE) += sunlance.o +-obj-$(CONFIG_AMD_XGBE) += xgbe/ ++obj-$(CONFIG_AMD_XGBE) += xgbe/ xgbe-a0/
That should be selected by a separate config option. Andreas. -- Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7 "And now for something completely different." -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On 03.11.14 14:51, Andreas Schwab wrote:
Alexander Graf <agraf@suse.de> writes:
+diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile +index a38a2dc..2dd45df 100644 +--- a/drivers/net/ethernet/amd/Makefile ++++ b/drivers/net/ethernet/amd/Makefile +@@ -17,4 +17,4 @@ obj-$(CONFIG_NI65) += ni65.o + obj-$(CONFIG_PCNET32) += pcnet32.o + obj-$(CONFIG_SUN3LANCE) += sun3lance.o + obj-$(CONFIG_SUNLANCE) += sunlance.o +-obj-$(CONFIG_AMD_XGBE) += xgbe/ ++obj-$(CONFIG_AMD_XGBE) += xgbe/ xgbe-a0/
That should be selected by a separate config option.
I've constrained it as ifeq (CONFIG_ARM64, y) for now so that we don't break non-arm64 builds - and for arm64 we want it enabled anyway. I hope we won't need this out-of-tree driver for too long - it's really only necessary to enable early silicon. Once we're confident enough that nobody wants to use this early silicon any more, we can just remove it altogether again. Alex -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
participants (3)
-
Alexander Graf
-
Andreas Schwab
-
Jeff Mahoney