Merge remote-tracking branch 'mips/mips-for-linux-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 23:31:13 +0000 (10:31 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 4 Nov 2015 23:31:13 +0000 (10:31 +1100)
95 files changed:
arch/mips/Kbuild
arch/mips/Kconfig
arch/mips/Kconfig.debug
arch/mips/Makefile
arch/mips/bcm47xx/setup.c
arch/mips/bcm47xx/sprom.c
arch/mips/boot/dts/mti/malta.dts
arch/mips/configs/bigsur_defconfig
arch/mips/configs/capcella_defconfig
arch/mips/configs/e55_defconfig
arch/mips/configs/fuloong2e_defconfig
arch/mips/configs/lasat_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/malta_defconfig
arch/mips/configs/malta_kvm_defconfig
arch/mips/configs/malta_kvm_guest_defconfig
arch/mips/configs/malta_qemu_32r6_defconfig
arch/mips/configs/maltaaprp_defconfig
arch/mips/configs/maltasmvp_eva_defconfig
arch/mips/configs/maltaup_defconfig
arch/mips/configs/maltaup_xpa_defconfig
arch/mips/configs/mpc30x_defconfig
arch/mips/include/asm/abi.h
arch/mips/include/asm/atomic.h
arch/mips/include/asm/bcache.h
arch/mips/include/asm/clocksource.h [new file with mode: 0644]
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/debug.h [new file with mode: 0644]
arch/mips/include/asm/elf.h
arch/mips/include/asm/fw/fw.h
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
arch/mips/include/asm/mach-malta/malta-dtshim.h [new file with mode: 0644]
arch/mips/include/asm/mips-cm.h
arch/mips/include/asm/mips-cpc.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/vdso.h
arch/mips/include/uapi/asm/Kbuild
arch/mips/include/uapi/asm/auxvec.h [new file with mode: 0644]
arch/mips/jz4740/board-qi_lb60.c
arch/mips/kernel/Makefile
arch/mips/kernel/cps-vec-ns16550.S [new file with mode: 0644]
arch/mips/kernel/cps-vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/csrc-r4k.c
arch/mips/kernel/idle.c
arch/mips/kernel/mips-cm.c
arch/mips/kernel/mips-cpc.c
arch/mips/kernel/mips-r2-to-r6-emul.c
arch/mips/kernel/segment.c
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/signal_n32.c
arch/mips/kernel/smp-cps.c
arch/mips/kernel/smp-gic.c
arch/mips/kernel/spinlock_test.c
arch/mips/kernel/stacktrace.c
arch/mips/kernel/traps.c
arch/mips/kernel/unaligned.c
arch/mips/kernel/vdso.c
arch/mips/lantiq/clk.c
arch/mips/lantiq/clk.h
arch/mips/lantiq/irq.c
arch/mips/lantiq/xway/clk.c
arch/mips/lantiq/xway/prom.c
arch/mips/lantiq/xway/reset.c
arch/mips/lantiq/xway/sysctrl.c
arch/mips/lib/Makefile
arch/mips/lib/bswapdi.c [new file with mode: 0644]
arch/mips/lib/bswapsi.c [new file with mode: 0644]
arch/mips/math-emu/me-debugfs.c
arch/mips/mm/Makefile
arch/mips/mm/sc-debugfs.c [new file with mode: 0644]
arch/mips/mm/sc-mips.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/Makefile
arch/mips/mti-malta/malta-dtshim.c [new file with mode: 0644]
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-memory.c
arch/mips/mti-malta/malta-setup.c
arch/mips/pci/pci-rt3883.c
arch/mips/vdso/.gitignore [new file with mode: 0644]
arch/mips/vdso/Makefile [new file with mode: 0644]
arch/mips/vdso/elf.S [new file with mode: 0644]
arch/mips/vdso/genvdso.c [new file with mode: 0644]
arch/mips/vdso/genvdso.h [new file with mode: 0644]
arch/mips/vdso/gettimeofday.c [new file with mode: 0644]
arch/mips/vdso/sigreturn.S [new file with mode: 0644]
arch/mips/vdso/vdso.h [new file with mode: 0644]
arch/mips/vdso/vdso.lds.S [new file with mode: 0644]
drivers/clocksource/mips-gic-timer.c
drivers/irqchip/irq-mips-gic.c
include/linux/irqchip/mips-gic.h

index dd29533..5c3f688 100644 (file)
@@ -17,6 +17,7 @@ obj- := $(platform-)
 obj-y += kernel/
 obj-y += mm/
 obj-y += net/
+obj-y += vdso/
 
 ifdef CONFIG_KVM
 obj-y += kvm/
index e3aa5b0..10feb15 100644 (file)
@@ -5,6 +5,7 @@ config MIPS
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select ARCH_MIGHT_HAVE_PC_SERIO
        select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
+       select ARCH_USE_BUILTIN_BSWAP
        select HAVE_CONTEXT_TRACKING
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_IDE
@@ -60,6 +61,8 @@ config MIPS
        select SYSCTL_EXCEPTION_TRACE
        select HAVE_VIRT_CPU_ACCOUNTING_GEN
        select HAVE_IRQ_TIME_ACCOUNTING
+       select GENERIC_TIME_VSYSCALL
+       select ARCH_CLOCKSOURCE_DATA
 
 menu "Machine selection"
 
@@ -424,6 +427,7 @@ config MIPS_MALTA
        select MIPS_L1_CACHE_SHIFT_6
        select PCI_GT64XXX_PCI0
        select MIPS_MSC
+       select SMP_UP if SMP
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_MIPS32_R2
@@ -449,6 +453,8 @@ config MIPS_MALTA
        select SYS_SUPPORTS_ZBOOT
        select USE_OF
        select ZONE_DMA32 if 64BIT
+       select BUILTIN_DTB
+       select LIBFDT
        help
          This enables support for the MIPS Technologies Malta evaluation
          board.
@@ -1036,6 +1042,9 @@ config CSRC_R4K
 config CSRC_SB1250
        bool
 
+config MIPS_CLOCK_VSYSCALL
+       def_bool CSRC_R4K || CLKSRC_MIPS_GIC
+
 config GPIO_TXX9
        select ARCH_REQUIRE_GPIOLIB
        bool
@@ -2529,6 +2538,9 @@ choice
        help
         Allows the configuration of the timer frequency.
 
+       config HZ_24
+               bool "24 HZ" if SYS_SUPPORTS_24HZ || SYS_SUPPORTS_ARBIT_HZ
+
        config HZ_48
                bool "48 HZ" if SYS_SUPPORTS_48HZ || SYS_SUPPORTS_ARBIT_HZ
 
@@ -2552,6 +2564,9 @@ choice
 
 endchoice
 
+config SYS_SUPPORTS_24HZ
+       bool
+
 config SYS_SUPPORTS_48HZ
        bool
 
@@ -2575,13 +2590,18 @@ config SYS_SUPPORTS_1024HZ
 
 config SYS_SUPPORTS_ARBIT_HZ
        bool
-       default y if !SYS_SUPPORTS_48HZ && !SYS_SUPPORTS_100HZ && \
-                    !SYS_SUPPORTS_128HZ && !SYS_SUPPORTS_250HZ && \
-                    !SYS_SUPPORTS_256HZ && !SYS_SUPPORTS_1000HZ && \
+       default y if !SYS_SUPPORTS_24HZ && \
+                    !SYS_SUPPORTS_48HZ && \
+                    !SYS_SUPPORTS_100HZ && \
+                    !SYS_SUPPORTS_128HZ && \
+                    !SYS_SUPPORTS_250HZ && \
+                    !SYS_SUPPORTS_256HZ && \
+                    !SYS_SUPPORTS_1000HZ && \
                     !SYS_SUPPORTS_1024HZ
 
 config HZ
        int
+       default 24 if HZ_24
        default 48 if HZ_48
        default 100 if HZ_100
        default 128 if HZ_128
@@ -2739,6 +2759,10 @@ config STACKTRACE_SUPPORT
        bool
        default y
 
+config HAVE_LATENCYTOP_SUPPORT
+       bool
+       default y
+
 config PGTABLE_LEVELS
        int
        default 3 if 64BIT && !PAGE_SIZE_64KB
index e250524..f0e314c 100644 (file)
@@ -113,4 +113,76 @@ config SPINLOCK_TEST
        help
          Add several files to the debugfs to test spinlock speed.
 
+if CPU_MIPSR6
+
+choice
+       prompt "Compact branch policy"
+       default MIPS_COMPACT_BRANCHES_OPTIMAL
+
+config MIPS_COMPACT_BRANCHES_NEVER
+       bool "Never (force delay slot branches)"
+       help
+         Pass the -mcompact-branches=never flag to the compiler in order to
+         force it to always emit branches with delay slots, and make no use
+         of the compact branch instructions introduced by MIPSr6. This is
+         useful if you suspect there may be an issue with compact branches in
+         either the compiler or the CPU.
+
+config MIPS_COMPACT_BRANCHES_OPTIMAL
+       bool "Optimal (use where beneficial)"
+       help
+         Pass the -mcompact-branches=optimal flag to the compiler in order for
+         it to make use of compact branch instructions where it deems them
+         beneficial, and use branches with delay slots elsewhere. This is the
+         default compiler behaviour, and should be used unless you have a
+         reason to choose otherwise.
+
+config MIPS_COMPACT_BRANCHES_ALWAYS
+       bool "Always (force compact branches)"
+       help
+         Pass the -mcompact-branches=always flag to the compiler in order to
+         force it to always emit compact branches, making no use of branch
+         instructions with delay slots. This can result in more compact code
+         which may be beneficial in some scenarios.
+
+endchoice
+
+endif # CPU_MIPSR6
+
+config SCACHE_DEBUGFS
+       bool "L2 cache debugfs entries"
+       depends on DEBUG_FS
+       help
+         Enable this to allow parts of the L2 cache configuration, such as
+         whether or not prefetching is enabled, to be exposed to userland
+         via debugfs.
+
+         If unsure, say N.
+
+menuconfig MIPS_CPS_NS16550
+       bool "CPS SMP NS16550 UART output"
+       depends on MIPS_CPS
+       help
+         Output debug information via an ns16550 compatible UART if exceptions
+         occur early in the boot process of a secondary core.
+
+if MIPS_CPS_NS16550
+
+config MIPS_CPS_NS16550_BASE
+       hex "UART Base Address"
+       default 0x1b0003f8 if MIPS_MALTA
+       help
+         The base address of the ns16550 compatible UART on which to output
+         debug information from the early stages of core startup.
+
+config MIPS_CPS_NS16550_SHIFT
+       int "UART Register Shift"
+       default 0 if MIPS_MALTA
+       help
+         The number of bits to shift ns16550 register indices by in order to
+         form their addresses. That is, log base 2 of the span between
+         adjacent ns16550 registers in the system.
+
+endif # MIPS_CPS_NS16550
+
 endmenu
index 252e347..3f70ba5 100644 (file)
@@ -204,6 +204,10 @@ toolchain-msa                              := $(call cc-option-yn,$(mips-cflags) -mhard-float -mfp64 -Wa$(
 cflags-$(toolchain-msa)                        += -DTOOLCHAIN_SUPPORTS_MSA
 endif
 
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER)   += -mcompact-branches=never
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL) += -mcompact-branches=optimal
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_ALWAYS)  += -mcompact-branches=always
+
 #
 # Firmware support
 #
index 17503a0..6d38948 100644 (file)
@@ -105,11 +105,28 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
                                  struct ssb_init_invariants *iv)
 {
        char buf[20];
+       int len, err;
 
        /* Fill boardinfo structure */
        memset(&iv->boardinfo, 0 , sizeof(struct ssb_boardinfo));
 
-       bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
+       len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf));
+       if (len > 0) {
+               err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor);
+               if (err)
+                       pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n",
+                               buf);
+       }
+       if (!iv->boardinfo.vendor)
+               iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
+
+       len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+       if (len > 0) {
+               err = kstrtou16(strim(buf), 0, &iv->boardinfo.type);
+               if (err)
+                       pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n",
+                               buf);
+       }
 
        memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
        bcm47xx_fill_sprom(&iv->sprom, NULL, false);
index 2d5c7a7..a7e569c 100644 (file)
@@ -60,9 +60,9 @@ static int get_nvram_var(const char *prefix, const char *postfix,
 }
 
 #define NVRAM_READ_VAL(type)                                           \
-static void nvram_read_ ## type (const char *prefix,                   \
-                                const char *postfix, const char *name, \
-                                type *val, type allset, bool fallback) \
+static void nvram_read_ ## type(const char *prefix,                    \
+                               const char *postfix, const char *name,  \
+                               type *val, type allset, bool fallback)  \
 {                                                                      \
        char buf[100];                                                  \
        int err;                                                        \
@@ -422,7 +422,10 @@ static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom,
        int i;
 
        for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
-               struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+               struct ssb_sprom_core_pwr_info *pwr_info;
+
+               pwr_info = &sprom->core_pwr_info[i];
+
                snprintf(postfix, sizeof(postfix), "%i", i);
                nvram_read_u8(prefix, postfix, "maxp2ga",
                              &pwr_info->maxpwr_2g, 0, fallback);
@@ -470,7 +473,10 @@ static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
        int i;
 
        for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
-               struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+               struct ssb_sprom_core_pwr_info *pwr_info;
+
+               pwr_info = &sprom->core_pwr_info[i];
+
                snprintf(postfix, sizeof(postfix), "%i", i);
                nvram_read_u16(prefix, postfix, "pa2gw3a",
                               &pwr_info->pa_2g[3], 0, fallback);
@@ -535,10 +541,11 @@ static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,
        nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);
 
        /* The address prefix 00:90:4C is used by Broadcom in their initial
-          configuration. When a mac address with the prefix 00:90:4C is used
-          all devices from the same series are sharing the same mac address.
-          To prevent mac address collisions we replace them with a mac address
-          based on the base address. */
+        * configuration. When a mac address with the prefix 00:90:4C is used
+        * all devices from the same series are sharing the same mac address.
+        * To prevent mac address collisions we replace them with a mac address
+        * based on the base address.
+        */
        if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
                u8 mac[6];
 
@@ -592,32 +599,23 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
        bcm47xx_sprom_fill_auto(sprom, prefix, fallback);
 }
 
-#ifdef CONFIG_BCM47XX_SSB
-void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
-                               const char *prefix)
-{
-       nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0,
-                      true);
-       if (!boardinfo->vendor)
-               boardinfo->vendor = SSB_BOARDVENDOR_BCM;
-
-       nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0, true);
-}
-#endif
-
 #if defined(CONFIG_BCM47XX_SSB)
 static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
 {
        char prefix[10];
 
-       if (bus->bustype == SSB_BUSTYPE_PCI) {
+       switch (bus->bustype) {
+       case SSB_BUSTYPE_SSB:
+               bcm47xx_fill_sprom(out, NULL, false);
+               return 0;
+       case SSB_BUSTYPE_PCI:
                memset(out, 0, sizeof(struct ssb_sprom));
                snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
                         bus->host_pci->bus->number + 1,
                         PCI_SLOT(bus->host_pci->devfn));
                bcm47xx_fill_sprom(out, prefix, false);
                return 0;
-       } else {
+       default:
                pr_warn("Unable to fill SPROM for given bustype.\n");
                return -EINVAL;
        }
index c678115..b18c466 100644 (file)
@@ -1,5 +1,9 @@
 /dts-v1/;
 
+/memreserve/ 0x00000000 0x00001000;    /* YAMON exception vectors */
+/memreserve/ 0x00001000 0x000ef000;    /* YAMON */
+/memreserve/ 0x000f0000 0x00010000;    /* PIIX4 ISA memory */
+
 / {
        #address-cells = <1>;
        #size-cells = <1>;
index 1cdff6b..b3e7a1b 100644 (file)
@@ -122,20 +122,20 @@ CONFIG_EEPROM_MAX6875=y
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_IT8213=m
 CONFIG_BLK_DEV_TC86C001=m
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_CHR_DEV_SCH=m
 CONFIG_ATA=y
 CONFIG_SATA_SIL24=y
+CONFIG_PATA_CMD64X=y
+CONFIG_PATA_IT8213=m
 CONFIG_PATA_SIL680=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
index 5135dc0..2924ba3 100644 (file)
@@ -31,9 +31,9 @@ CONFIG_NETWORK_SECMARK=y
 CONFIG_IP_SCTP=m
 CONFIG_FW_LOADER=m
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 CONFIG_PHYLIB=m
 CONFIG_MARVELL_PHY=m
index 0126e66..e94d266 100644 (file)
@@ -14,9 +14,9 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
 # CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
index a75c65d..8743589 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_MIPS32_N32=y
 CONFIG_PM=y
 # CONFIG_SUSPEND is not set
 CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION="/dev/hda3"
+CONFIG_PM_STD_PARTITION="/dev/sda3"
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -114,20 +114,16 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_RAM=m
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_TASK_IOCTL=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
-CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_PATA_VIA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 CONFIG_MACVLAN=m
 CONFIG_VETH=m
index 0179c7f..e620a2c 100644 (file)
@@ -35,11 +35,11 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_CMD64X=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_NET_PCI=y
index 54cc385..004cf52 100644 (file)
@@ -108,16 +108,11 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=m
-CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_PATA_AMD=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
index 61a4460..5afb484 100644 (file)
@@ -241,14 +241,11 @@ CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
 CONFIG_RAID_ATTRS=m
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
@@ -265,6 +262,7 @@ CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
 CONFIG_ATA=y
 CONFIG_ATA_PIIX=y
+CONFIG_PATA_LEGACY=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
index d41742d..98f1387 100644 (file)
@@ -248,17 +248,12 @@ CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
 CONFIG_BLK_DEV_TC86C001=m
 CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_MULTI_LUN=y
@@ -274,6 +269,13 @@ CONFIG_SCSI_AACRAID=m
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
index a7806e8..3b5d591 100644 (file)
@@ -248,17 +248,12 @@ CONFIG_ATA_OVER_ETH=m
 CONFIG_VIRTIO_BLK=y
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
 CONFIG_BLK_DEV_TC86C001=m
 CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_MULTI_LUN=y
@@ -274,6 +269,13 @@ CONFIG_SCSI_AACRAID=m
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
index 4bce1f8..7f50dd6 100644 (file)
@@ -80,15 +80,14 @@ CONFIG_NET_CLS_IND=y
 CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_ADAPTEC is not set
index fb042ce..a9d433a 100644 (file)
@@ -81,15 +81,14 @@ CONFIG_NET_CLS_IND=y
 CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_ADAPTEC is not set
index c83338a..2774ef0 100644 (file)
@@ -85,15 +85,14 @@ CONFIG_NET_CLS_IND=y
 CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_ADAPTEC is not set
index 6234464..9bbd221 100644 (file)
@@ -80,15 +80,14 @@ CONFIG_NET_CLS_IND=y
 CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_SG=y
 # CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_NET_VENDOR_ADAPTEC is not set
index c388bff..7322157 100644 (file)
@@ -244,17 +244,12 @@ CONFIG_CDROM_PKTCDVD=m
 CONFIG_ATA_OVER_ETH=m
 CONFIG_IDE=y
 CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
 CONFIG_BLK_DEV_TC86C001=m
 CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_CONSTANTS=y
@@ -269,6 +264,13 @@ CONFIG_SCSI_AACRAID=m
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
index 7a34660..a2c045f 100644 (file)
@@ -27,9 +27,9 @@ CONFIG_INET_XFRM_MODE_BEET=m
 CONFIG_NETWORK_SECMARK=y
 CONFIG_CONNECTOR=m
 CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
index 37f8407..9407608 100644 (file)
 
 #include <asm/signal.h>
 #include <asm/siginfo.h>
+#include <asm/vdso.h>
 
 struct mips_abi {
        int (* const setup_frame)(void *sig_return, struct ksignal *ksig,
                                  struct pt_regs *regs, sigset_t *set);
-       const unsigned long     signal_return_offset;
        int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig,
                                     struct pt_regs *regs, sigset_t *set);
-       const unsigned long     rt_signal_return_offset;
        const unsigned long     restart;
 
        unsigned        off_sc_fpregs;
        unsigned        off_sc_fpc_csr;
        unsigned        off_sc_used_math;
+
+       struct mips_vdso_image *vdso;
 };
 
 #endif /* _ASM_ABI_H */
index f82d3af..835b402 100644 (file)
@@ -507,7 +507,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
  * @u: ...unless v is equal to u.
  *
  * Atomically adds @a to @v, so long as it was not @u.
- * Returns the old value of @v.
+ * Returns true iff @v was not @u.
  */
 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 {
index 8c34484..a00857b 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef _ASM_BCACHE_H
 #define _ASM_BCACHE_H
 
+#include <linux/types.h>
 
 /* Some R4000 / R4400 / R4600 / R5000 machines may have a non-dma-coherent,
    chipset implemented caches. On machines with other CPUs the CPU does the
@@ -18,6 +19,9 @@ struct bcache_ops {
        void (*bc_disable)(void);
        void (*bc_wback_inv)(unsigned long page, unsigned long size);
        void (*bc_inv)(unsigned long page, unsigned long size);
+       void (*bc_prefetch_enable)(void);
+       void (*bc_prefetch_disable)(void);
+       bool (*bc_prefetch_is_enabled)(void);
 };
 
 extern void indy_sc_init(void);
@@ -46,6 +50,26 @@ static inline void bc_inv(unsigned long page, unsigned long size)
        bcops->bc_inv(page, size);
 }
 
+static inline void bc_prefetch_enable(void)
+{
+       if (bcops->bc_prefetch_enable)
+               bcops->bc_prefetch_enable();
+}
+
+static inline void bc_prefetch_disable(void)
+{
+       if (bcops->bc_prefetch_disable)
+               bcops->bc_prefetch_disable();
+}
+
+static inline bool bc_prefetch_is_enabled(void)
+{
+       if (bcops->bc_prefetch_is_enabled)
+               return bcops->bc_prefetch_is_enabled();
+
+       return false;
+}
+
 #else /* !defined(CONFIG_BOARD_SCACHE) */
 
 /* Not R4000 / R4400 / R4600 / R5000.  */
@@ -54,6 +78,9 @@ static inline void bc_inv(unsigned long page, unsigned long size)
 #define bc_disable() do { } while (0)
 #define bc_wback_inv(page, size) do { } while (0)
 #define bc_inv(page, size) do { } while (0)
+#define bc_prefetch_enable() do { } while (0)
+#define bc_prefetch_disable() do { } while (0)
+#define bc_prefetch_is_enabled() 0
 
 #endif /* !defined(CONFIG_BOARD_SCACHE) */
 
diff --git a/arch/mips/include/asm/clocksource.h b/arch/mips/include/asm/clocksource.h
new file mode 100644 (file)
index 0000000..3deb1d0
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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.
+ */
+
+#ifndef __ASM_CLOCKSOURCE_H
+#define __ASM_CLOCKSOURCE_H
+
+#include <linux/types.h>
+
+/* VDSO clocksources. */
+#define VDSO_CLOCK_NONE                0       /* No suitable clocksource. */
+#define VDSO_CLOCK_R4K         1       /* Use the coprocessor 0 count. */
+#define VDSO_CLOCK_GIC         2       /* Use the GIC. */
+
+/**
+ * struct arch_clocksource_data - Architecture-specific clocksource information.
+ * @vdso_clock_mode: Method the VDSO should use to access the clocksource.
+ */
+struct arch_clocksource_data {
+       u8 vdso_clock_mode;
+};
+
+#endif /* __ASM_CLOCKSOURCE_H */
index fe67f12..d1e04c9 100644 (file)
 #endif
 
 #ifndef cpu_has_rixi
-# ifdef CONFIG_64BIT
-# define cpu_has_rixi          (cpu_data[0].options & MIPS_CPU_RIXI)
-# else /* CONFIG_32BIT */
-# define cpu_has_rixi          ((cpu_data[0].options & MIPS_CPU_RIXI) && !cpu_has_64bits)
-# endif
+#define cpu_has_rixi           (cpu_data[0].options & MIPS_CPU_RIXI)
 #endif
 
 #ifndef cpu_has_mmips
diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h
new file mode 100644 (file)
index 0000000..254f00d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_DEBUG_H__
+#define __MIPS_ASM_DEBUG_H__
+
+#include <linux/dcache.h>
+
+/*
+ * mips_debugfs_dir corresponds to the "mips" directory at the top level
+ * of the DebugFS hierarchy. MIPS-specific DebugFS entires should be
+ * placed beneath this directory.
+ */
+extern struct dentry *mips_debugfs_dir;
+
+#endif /* __MIPS_ASM_DEBUG_H__ */
index 53b2693..b01a6ff 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef _ASM_ELF_H
 #define _ASM_ELF_H
 
+#include <linux/auxvec.h>
 #include <linux/fs.h>
 #include <uapi/linux/elf.h>
 
@@ -419,6 +420,12 @@ extern const char *__elf_platform;
 #define ELF_ET_DYN_BASE                (TASK_SIZE / 3 * 2)
 #endif
 
+#define ARCH_DLINFO                                                    \
+do {                                                                   \
+       NEW_AUX_ENT(AT_SYSINFO_EHDR,                                    \
+                   (unsigned long)current->mm->context.vdso);          \
+} while (0)
+
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 struct linux_binprm;
 extern int arch_setup_additional_pages(struct linux_binprm *bprm,
index f3e6978..d0ef8b4 100644 (file)
 
 #include <asm/bootinfo.h>      /* For cleaner code... */
 
-enum fw_memtypes {
-       fw_dontuse,
-       fw_code,
-       fw_free,
-};
-
-typedef struct {
-       unsigned long base;     /* Within KSEG0 */
-       unsigned int size;      /* bytes */
-       enum fw_memtypes type;  /* fw_memtypes */
-} fw_memblock_t;
-
-/* Maximum number of memory block descriptors. */
-#define FW_MAX_MEMBLOCKS       32
-
 extern int fw_argc;
 extern int *_fw_argv;
 extern int *_fw_envp;
@@ -38,7 +23,6 @@ extern int *_fw_envp;
 
 extern void fw_init_cmdline(void);
 extern char *fw_getcmdline(void);
-extern fw_memblock_t *fw_getmdesc(int);
 extern void fw_meminit(void);
 extern char *fw_getenv(char *name);
 extern unsigned long fw_getenvl(char *name);
index 1461c10..71e4096 100644 (file)
@@ -48,11 +48,6 @@ extern enum bcm47xx_bus_type bcm47xx_bus_type;
 void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
                        bool fallback);
 
-#ifdef CONFIG_BCM47XX_SSB
-void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
-                               const char *prefix);
-#endif
-
 void bcm47xx_set_system_type(u16 chip_id);
 
 #endif /* __ASM_BCM47XX_H */
index 133336b..dd6005b 100644 (file)
 #define SOC_ID_VRX268_2                0x00C /* v1.2 */
 #define SOC_ID_GRX288_2                0x00D /* v1.2 */
 #define SOC_ID_GRX282_2                0x00E /* v1.2 */
+#define SOC_ID_VRX220          0x000
+
+#define SOC_ID_ARX362          0x004
+#define SOC_ID_ARX368          0x005
+#define SOC_ID_ARX382          0x007
+#define SOC_ID_ARX388          0x008
+#define SOC_ID_URX388          0x009
+#define SOC_ID_GRX383          0x010
+#define SOC_ID_GRX369          0x011
+#define SOC_ID_GRX387          0x00F
+#define SOC_ID_GRX389          0x012
 
  /* SoC Types */
 #define SOC_TYPE_DANUBE                0x01
@@ -43,6 +54,9 @@
 #define SOC_TYPE_VR9           0x04 /* v1.1 */
 #define SOC_TYPE_VR9_2         0x05 /* v1.2 */
 #define SOC_TYPE_AMAZON_SE     0x06
+#define SOC_TYPE_AR10          0x07
+#define SOC_TYPE_GRX390                0x08
+#define SOC_TYPE_VRX220                0x09
 
 /* BOOT_SEL - find what boot media we have */
 #define BS_EXT_ROM             0x0
diff --git a/arch/mips/include/asm/mach-malta/malta-dtshim.h b/arch/mips/include/asm/mach-malta/malta-dtshim.h
new file mode 100644 (file)
index 0000000..cfd7776
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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.
+ */
+
+#ifndef __MIPS_MALTA_DTSHIM_H__
+#define __MIPS_MALTA_DTSHIM_H__
+
+#include <linux/init.h>
+
+#ifdef CONFIG_MIPS_MALTA
+
+extern void __init *malta_dt_shim(void *fdt);
+
+#else /* !CONFIG_MIPS_MALTA */
+
+static inline void *malta_dt_shim(void *fdt)
+{
+       return fdt;
+}
+
+#endif /* !CONFIG_MIPS_MALTA */
+
+#endif /* __MIPS_MALTA_DTSHIM_H__ */
index 1f1927a..6516e9d 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __MIPS_ASM_MIPS_CM_H__
 #define __MIPS_ASM_MIPS_CM_H__
 
+#include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/types.h>
@@ -36,12 +37,12 @@ extern phys_addr_t __mips_cm_phys_base(void);
 /*
  * mips_cm_is64 - determine CM register width
  *
- * The CM register width is processor and CM specific. A 64-bit processor
- * usually has a 64-bit CM and a 32-bit one has a 32-bit CM but a 64-bit
- * processor could come with a 32-bit CM. Moreover, accesses on 64-bit CMs
- * can be done either using regular 64-bit load/store instructions, or 32-bit
- * load/store instruction on 32-bit register pairs. We opt for using 64-bit
- * accesses on 64-bit CMs and kernels and 32-bit in any other case.
+ * The CM register width is determined by the version of the CM, with CM3
+ * introducing 64 bit GCRs and all prior CM versions having 32 bit GCRs.
+ * However we may run a kernel built for MIPS32 on a system with 64 bit GCRs,
+ * or vice-versa. This variable indicates the width of the memory accesses
+ * that the kernel will perform to GCRs, which may differ from the actual
+ * width of the GCRs.
  *
  * It's set to 0 for 32-bit accesses and 1 for 64-bit accesses.
  */
@@ -125,7 +126,17 @@ static inline u32 read32_gcr_##name(void)                  \
                                                                \
 static inline u64 read64_gcr_##name(void)                      \
 {                                                              \
-       return __raw_readq(addr_gcr_##name());                  \
+       void __iomem *addr = addr_gcr_##name();                 \
+       u64 ret;                                                \
+                                                               \
+       if (mips_cm_is64) {                                     \
+               ret = __raw_readq(addr);                        \
+       } else {                                                \
+               ret = __raw_readl(addr);                        \
+               ret |= (u64)__raw_readl(addr + 0x4) << 32;      \
+       }                                                       \
+                                                               \
+       return ret;                                             \
 }                                                              \
                                                                \
 static inline unsigned long read_gcr_##name(void)              \
@@ -195,6 +206,8 @@ BUILD_CM_R_(gic_status,             MIPS_CM_GCB_OFS + 0xd0)
 BUILD_CM_R_(cpc_status,                MIPS_CM_GCB_OFS + 0xf0)
 BUILD_CM_RW(l2_config,         MIPS_CM_GCB_OFS + 0x130)
 BUILD_CM_RW(sys_config2,       MIPS_CM_GCB_OFS + 0x150)
+BUILD_CM_RW(l2_pft_control,    MIPS_CM_GCB_OFS + 0x300)
+BUILD_CM_RW(l2_pft_control_b,  MIPS_CM_GCB_OFS + 0x308)
 
 /* Core Local & Core Other register accessor functions */
 BUILD_CM_Cx_RW(reset_release,  0x00)
@@ -245,11 +258,14 @@ BUILD_CM_Cx_R_(tcid_8_priority,   0x80)
                 ((minor) << CM_GCR_REV_MINOR_SHF))
 
 #define CM_REV_CM2                             CM_ENCODE_REV(6, 0)
+#define CM_REV_CM2_5                           CM_ENCODE_REV(7, 0)
 #define CM_REV_CM3                             CM_ENCODE_REV(8, 0)
 
 /* GCR_ERROR_CAUSE register fields */
 #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF         27
 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK         (_ULCAST_(0x1f) << 27)
+#define CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF                58
+#define CM3_GCR_ERROR_CAUSE_ERRTYPE_MSK                GENMASK_ULL(63, 58)
 #define CM_GCR_ERROR_CAUSE_ERRINFO_SHF         0
 #define CM_GCR_ERROR_CAUSE_ERRINGO_MSK         (_ULCAST_(0x7ffffff) << 0)
 
@@ -321,6 +337,20 @@ BUILD_CM_Cx_R_(tcid_8_priority,    0x80)
 #define CM_GCR_SYS_CONFIG2_MAXVPW_SHF          0
 #define CM_GCR_SYS_CONFIG2_MAXVPW_MSK          (_ULCAST_(0xf) << 0)
 
+/* GCR_L2_PFT_CONTROL register fields */
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_SHF     12
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK     (_ULCAST_(0xfffff) << 12)
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_SHF                8
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_MSK                (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_NPFT_SHF         0
+#define CM_GCR_L2_PFT_CONTROL_NPFT_MSK         (_ULCAST_(0xff) << 0)
+
+/* GCR_L2_PFT_CONTROL_B register fields */
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_SHF                8
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_MSK                (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_SHF     0
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK     (_ULCAST_(0xff) << 0)
+
 /* GCR_Cx_COHERENCE register fields */
 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF    0
 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK    (_ULCAST_(0xff) << 0)
@@ -329,11 +359,15 @@ BUILD_CM_Cx_R_(tcid_8_priority,   0x80)
 #define CM_GCR_Cx_CONFIG_IOCUTYPE_SHF          10
 #define CM_GCR_Cx_CONFIG_IOCUTYPE_MSK          (_ULCAST_(0x3) << 10)
 #define CM_GCR_Cx_CONFIG_PVPE_SHF              0
-#define CM_GCR_Cx_CONFIG_PVPE_MSK              (_ULCAST_(0x1ff) << 0)
+#define CM_GCR_Cx_CONFIG_PVPE_MSK              (_ULCAST_(0x3ff) << 0)
 
 /* GCR_Cx_OTHER register fields */
 #define CM_GCR_Cx_OTHER_CORENUM_SHF            16
 #define CM_GCR_Cx_OTHER_CORENUM_MSK            (_ULCAST_(0xffff) << 16)
+#define CM3_GCR_Cx_OTHER_CORE_SHF              8
+#define CM3_GCR_Cx_OTHER_CORE_MSK              (_ULCAST_(0x3f) << 8)
+#define CM3_GCR_Cx_OTHER_VP_SHF                        0
+#define CM3_GCR_Cx_OTHER_VP_MSK                        (_ULCAST_(0x7) << 0)
 
 /* GCR_Cx_RESET_BASE register fields */
 #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_SHF    12
@@ -444,4 +478,32 @@ static inline unsigned int mips_cm_vp_id(unsigned int cpu)
        return (core * mips_cm_max_vp_width()) + vp;
 }
 
+#ifdef CONFIG_MIPS_CM
+
+/**
+ * mips_cm_lock_other - lock access to another core
+ * @core: the other core to be accessed
+ * @vp: the VP within the other core to be accessed
+ *
+ * Call before operating upon a core via the 'other' register region in
+ * order to prevent the region being moved during access. Must be followed
+ * by a call to mips_cm_unlock_other.
+ */
+extern void mips_cm_lock_other(unsigned int core, unsigned int vp);
+
+/**
+ * mips_cm_unlock_other - unlock access to another core
+ *
+ * Call after operating upon another core via the 'other' register region.
+ * Must be called after mips_cm_lock_other.
+ */
+extern void mips_cm_unlock_other(void);
+
+#else /* !CONFIG_MIPS_CM */
+
+static inline void mips_cm_lock_other(unsigned int core) { }
+static inline void mips_cm_unlock_other(void) { }
+
+#endif /* !CONFIG_MIPS_CM */
+
 #endif /* __MIPS_ASM_MIPS_CM_H__ */
index f386f32..e090352 100644 (file)
@@ -149,7 +149,8 @@ BUILD_CPC_Cx_RW(other,              0x10)
  * core: the other core to be accessed
  *
  * Call before operating upon a core via the 'other' register region in
- * order to prevent the region being moved during access. Must be followed
+ * order to prevent the region being moved during access. Must be called
+ * within the bounds of a mips_cm_{lock,unlock}_other pair, and followed
  * by a call to mips_cpc_unlock_other.
  */
 extern void mips_cpc_lock_other(unsigned int core);
index c64781c..e7c1e28 100644 (file)
@@ -51,6 +51,7 @@
 #define CP0_WIRED $6
 #define CP0_INFO $7
 #define CP0_BADVADDR $8
+#define CP0_BADINSTR $8, 1
 #define CP0_COUNT $9
 #define CP0_ENTRYHI $10
 #define CP0_COMPARE $11
@@ -58,6 +59,8 @@
 #define CP0_CAUSE $13
 #define CP0_EPC $14
 #define CP0_PRID $15
+#define CP0_EBASE $15, 1
+#define CP0_CMGCRBASE $15, 3
 #define CP0_CONFIG $16
 #define CP0_LLADDR $17
 #define CP0_WATCHLO $18
 #define R3K_ENTRYLO_N          (_ULCAST_(1) << 11)
 
 /* MIPS32/64 EntryLo bit definitions */
-#ifdef CONFIG_64BIT
-/* as read by dmfc0 */
-#define MIPS_ENTRYLO_XI                (_ULCAST_(1) << 62)
-#define MIPS_ENTRYLO_RI                (_ULCAST_(1) << 63)
-#else
-/* as read by mfc0 */
-#define MIPS_ENTRYLO_XI                (_ULCAST_(1) << 30)
-#define MIPS_ENTRYLO_RI                (_ULCAST_(1) << 31)
-#endif
+#define MIPS_ENTRYLO_PFN_SHIFT 6
+#define MIPS_ENTRYLO_XI                (_ULCAST_(1) << (BITS_PER_LONG - 2))
+#define MIPS_ENTRYLO_RI                (_ULCAST_(1) << (BITS_PER_LONG - 1))
 
 /*
  * Values for PageMask register
index 59ee6dc..3f832c3 100644 (file)
@@ -36,12 +36,6 @@ extern unsigned int vced_count, vcei_count;
  */
 #define HAVE_ARCH_PICK_MMAP_LAYOUT 1
 
-/*
- * A special page (the vdso) is mapped into all processes at the very
- * top of the virtual memory space.
- */
-#define SPECIAL_PAGES_SIZE PAGE_SIZE
-
 #ifdef CONFIG_32BIT
 #ifdef CONFIG_KVM_GUEST
 /* User space process size is limited to 1GB in KVM Guest Mode */
@@ -80,7 +74,7 @@ extern unsigned int vced_count, vcei_count;
 
 #endif
 
-#define STACK_TOP      ((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE)
+#define STACK_TOP      (TASK_SIZE & PAGE_MASK)
 
 /*
  * This decides where the kernel will search for a free chunk of vm
index cca56aa..8f4ca5d 100644 (file)
 /*
- * 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.
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
  *
- * Copyright (C) 2009 Cavium Networks
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #ifndef __ASM_VDSO_H
 #define __ASM_VDSO_H
 
-#include <linux/types.h>
+#include <linux/mm_types.h>
 
+#include <asm/barrier.h>
 
-#ifdef CONFIG_32BIT
-struct mips_vdso {
-       u32 signal_trampoline[2];
-       u32 rt_signal_trampoline[2];
+/**
+ * struct mips_vdso_image - Details of a VDSO image.
+ * @data: Pointer to VDSO image data (page-aligned).
+ * @size: Size of the VDSO image data (page-aligned).
+ * @off_sigreturn: Offset of the sigreturn() trampoline.
+ * @off_rt_sigreturn: Offset of the rt_sigreturn() trampoline.
+ * @mapping: Special mapping structure.
+ *
+ * This structure contains details of a VDSO image, including the image data
+ * and offsets of certain symbols required by the kernel. It is generated as
+ * part of the VDSO build process, aside from the mapping page array, which is
+ * populated at runtime.
+ */
+struct mips_vdso_image {
+       void *data;
+       unsigned long size;
+
+       unsigned long off_sigreturn;
+       unsigned long off_rt_sigreturn;
+
+       struct vm_special_mapping mapping;
 };
-#else  /* !CONFIG_32BIT */
-struct mips_vdso {
-       u32 o32_signal_trampoline[2];
-       u32 o32_rt_signal_trampoline[2];
-       u32 rt_signal_trampoline[2];
-       u32 n32_rt_signal_trampoline[2];
+
+/*
+ * The following structures are auto-generated as part of the build for each
+ * ABI by genvdso, see arch/mips/vdso/Makefile.
+ */
+
+extern struct mips_vdso_image vdso_image;
+
+#ifdef CONFIG_MIPS32_O32
+extern struct mips_vdso_image vdso_image_o32;
+#endif
+
+#ifdef CONFIG_MIPS32_N32
+extern struct mips_vdso_image vdso_image_n32;
+#endif
+
+/**
+ * union mips_vdso_data - Data provided by the kernel for the VDSO.
+ * @xtime_sec:         Current real time (seconds part).
+ * @xtime_nsec:                Current real time (nanoseconds part, shifted).
+ * @wall_to_mono_sec:  Wall-to-monotonic offset (seconds part).
+ * @wall_to_mono_nsec: Wall-to-monotonic offset (nanoseconds part).
+ * @seq_count:         Counter to synchronise updates (odd = updating).
+ * @cs_shift:          Clocksource shift value.
+ * @clock_mode:                Clocksource to use for time functions.
+ * @cs_mult:           Clocksource multiplier value.
+ * @cs_cycle_last:     Clock cycle value at last update.
+ * @cs_mask:           Clocksource mask value.
+ * @tz_minuteswest:    Minutes west of Greenwich (from timezone).
+ * @tz_dsttime:                Type of DST correction (from timezone).
+ *
+ * This structure contains data needed by functions within the VDSO. It is
+ * populated by the kernel and mapped read-only into user memory. The time
+ * fields are mirrors of internal data from the timekeeping infrastructure.
+ *
+ * Note: Care should be taken when modifying as the layout must remain the same
+ * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel).
+ */
+union mips_vdso_data {
+       struct {
+               u64 xtime_sec;
+               u64 xtime_nsec;
+               u32 wall_to_mono_sec;
+               u32 wall_to_mono_nsec;
+               u32 seq_count;
+               u32 cs_shift;
+               u8 clock_mode;
+               u32 cs_mult;
+               u64 cs_cycle_last;
+               u64 cs_mask;
+               s32 tz_minuteswest;
+               s32 tz_dsttime;
+       };
+
+       u8 page[PAGE_SIZE];
 };
-#endif /* CONFIG_32BIT */
+
+static inline u32 vdso_data_read_begin(const union mips_vdso_data *data)
+{
+       u32 seq;
+
+       while (true) {
+               seq = ACCESS_ONCE(data->seq_count);
+               if (likely(!(seq & 1))) {
+                       /* Paired with smp_wmb() in vdso_data_write_*(). */
+                       smp_rmb();
+                       return seq;
+               }
+
+               cpu_relax();
+       }
+}
+
+static inline bool vdso_data_read_retry(const union mips_vdso_data *data,
+                                       u32 start_seq)
+{
+       /* Paired with smp_wmb() in vdso_data_write_*(). */
+       smp_rmb();
+       return unlikely(data->seq_count != start_seq);
+}
+
+static inline void vdso_data_write_begin(union mips_vdso_data *data)
+{
+       ++data->seq_count;
+
+       /* Ensure sequence update is written before other data page values. */
+       smp_wmb();
+}
+
+static inline void vdso_data_write_end(union mips_vdso_data *data)
+{
+       /* Ensure data values are written before updating sequence again. */
+       smp_wmb();
+       ++data->seq_count;
+}
 
 #endif /* __ASM_VDSO_H */
index 96fe739..f2cf414 100644 (file)
@@ -1,9 +1,9 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-generic-y += auxvec.h
 generic-y += ipcbuf.h
 
+header-y += auxvec.h
 header-y += bitfield.h
 header-y += bitsperlong.h
 header-y += break.h
diff --git a/arch/mips/include/uapi/asm/auxvec.h b/arch/mips/include/uapi/asm/auxvec.h
new file mode 100644 (file)
index 0000000..c9c7195
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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.
+ */
+
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* Location of VDSO image. */
+#define AT_SYSINFO_EHDR                33
+
+#endif /* __ASM_AUXVEC_H */
index 459cb01..934b15b 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
+#include <linux/pwm.h>
 
 #include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_fb.h>
@@ -34,8 +35,6 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 
-#include <linux/leds_pwm.h>
-
 #include <asm/mach-jz4740/platform.h>
 
 #include "clock.h"
@@ -399,13 +398,15 @@ static struct platform_device avt2_usb_regulator_device = {
        }
 };
 
+static struct pwm_lookup qi_lb60_pwm_lookup[] = {
+       PWM_LOOKUP("jz4740-pwm", 4, "pwm-beeper", NULL, 0,
+                  PWM_POLARITY_NORMAL),
+};
+
 /* beeper */
 static struct platform_device qi_lb60_pwm_beeper = {
        .name = "pwm-beeper",
        .id = -1,
-       .dev = {
-               .platform_data = (void *)4,
-       },
 };
 
 /* charger */
@@ -491,6 +492,8 @@ static int __init qi_lb60_init_platform_devices(void)
                platform_device_register(&jz4740_usb_ohci_device);
        }
 
+       pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+
        return platform_add_devices(jz_platform_devices,
                                        ARRAY_SIZE(jz_platform_devices));
 
index d982be1..68e2b7d 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_MIPS_MT_FPAFF)   += mips-mt-fpaff.o
 obj-$(CONFIG_MIPS_MT_SMP)      += smp-mt.o
 obj-$(CONFIG_MIPS_CMP)         += smp-cmp.o
 obj-$(CONFIG_MIPS_CPS)         += smp-cps.o cps-vec.o
+obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o
 obj-$(CONFIG_MIPS_GIC_IPI)     += smp-gic.o
 obj-$(CONFIG_MIPS_SPRAM)       += spram.o
 
diff --git a/arch/mips/kernel/cps-vec-ns16550.S b/arch/mips/kernel/cps-vec-ns16550.S
new file mode 100644 (file)
index 0000000..6d246ad
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <linux/serial_reg.h>
+
+#define UART_TX_OFS    (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT)
+#define UART_LSR_OFS   (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT)
+
+/**
+ * _mips_cps_putc() - write a character to the UART
+ * @a0: ASCII character to write
+ * @t9: UART base address
+ */
+LEAF(_mips_cps_putc)
+1:     lw              t0, UART_LSR_OFS(t9)
+       andi            t0, t0, UART_LSR_TEMT
+       beqz            t0, 1b
+       sb              a0, UART_TX_OFS(t9)
+       jr              ra
+       END(_mips_cps_putc)
+
+/**
+ * _mips_cps_puts() - write a string to the UART
+ * @a0: pointer to NULL-terminated ASCII string
+ * @t9: UART base address
+ *
+ * Write a null-terminated ASCII string to the UART.
+ */
+NESTED(_mips_cps_puts, 0, ra)
+       move            s7, ra
+       move            s6, a0
+
+1:     lb              a0, 0(s6)
+       beqz            a0, 2f
+       jal             _mips_cps_putc
+       PTR_ADDIU       s6, s6, 1
+       b               1b
+
+2:     jr              s7
+       END(_mips_cps_puts)
+
+/**
+ * _mips_cps_putx4 - write a 4b hex value to the UART
+ * @a0: the 4b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a single hexadecimal character to the UART.
+ */
+NESTED(_mips_cps_putx4, 0, ra)
+       andi            a0, a0, 0xf
+       li              t0, '0'
+       blt             a0, 10, 1f
+       li              t0, 'a'
+       addiu           a0, a0, -10
+1:     addu            a0, a0, t0
+       b               _mips_cps_putc
+       END(_mips_cps_putx4)
+
+/**
+ * _mips_cps_putx8 - write an 8b hex value to the UART
+ * @a0: the 8b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx8, 0, ra)
+       move            s3, ra
+       move            s2, a0
+       srl             a0, a0, 4
+       jal             _mips_cps_putx4
+       move            a0, s2
+       move            ra, s3
+       b               _mips_cps_putx4
+       END(_mips_cps_putx8)
+
+/**
+ * _mips_cps_putx16 - write a 16b hex value to the UART
+ * @a0: the 16b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx16, 0, ra)
+       move            s5, ra
+       move            s4, a0
+       srl             a0, a0, 8
+       jal             _mips_cps_putx8
+       move            a0, s4
+       move            ra, s5
+       b               _mips_cps_putx8
+       END(_mips_cps_putx16)
+
+/**
+ * _mips_cps_putx32 - write a 32b hex value to the UART
+ * @a0: the 32b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx32, 0, ra)
+       move            s7, ra
+       move            s6, a0
+       srl             a0, a0, 16
+       jal             _mips_cps_putx16
+       move            a0, s6
+       move            ra, s7
+       b               _mips_cps_putx16
+       END(_mips_cps_putx32)
+
+#ifdef CONFIG_64BIT
+
+/**
+ * _mips_cps_putx64 - write a 64b hex value to the UART
+ * @a0: the 64b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx64, 0, ra)
+       move            sp, ra
+       move            s8, a0
+       dsrl32          a0, a0, 0
+       jal             _mips_cps_putx32
+       move            a0, s8
+       move            ra, sp
+       b               _mips_cps_putx32
+       END(_mips_cps_putx64)
+
+#define _mips_cps_putxlong _mips_cps_putx64
+
+#else /* !CONFIG_64BIT */
+
+#define _mips_cps_putxlong _mips_cps_putx32
+
+#endif /* !CONFIG_64BIT */
+
+/**
+ * mips_cps_bev_dump() - dump relevant exception state to UART
+ * @a0: pointer to NULL-terminated ASCII string naming the exception
+ *
+ * Write information that may be useful in debugging an exception to the
+ * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception
+ * will only be run if something goes horribly wrong very early during
+ * the bringup of a core and it is very likely to be unsafe to perform
+ * memory accesses at that point (cache state indeterminate, EVA may not
+ * be configured, coherence may be disabled) let alone have a stack,
+ * this is all written in assembly using only registers & unmapped
+ * uncached access to the UART registers.
+ */
+LEAF(mips_cps_bev_dump)
+       move            s0, ra
+       move            s1, a0
+
+       li              t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE)
+
+       PTR_LA          a0, str_newline
+       jal             _mips_cps_puts
+       PTR_LA          a0, str_bev
+       jal             _mips_cps_puts
+       move            a0, s1
+       jal             _mips_cps_puts
+       PTR_LA          a0, str_newline
+       jal             _mips_cps_puts
+       PTR_LA          a0, str_newline
+       jal             _mips_cps_puts
+
+#define DUMP_COP0_REG(reg, name, sz, _mfc0)            \
+       PTR_LA          a0, 8f;                         \
+       jal             _mips_cps_puts;                 \
+       _mfc0           a0, reg;                        \
+       jal             _mips_cps_putx##sz;             \
+       PTR_LA          a0, str_newline;                \
+       jal             _mips_cps_puts;                 \
+       TEXT(name)
+
+       DUMP_COP0_REG(CP0_CAUSE,    "Cause:    0x", 32, mfc0)
+       DUMP_COP0_REG(CP0_STATUS,   "Status:   0x", 32, mfc0)
+       DUMP_COP0_REG(CP0_EBASE,    "EBase:    0x", long, MFC0)
+       DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0)
+       DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0)
+
+       PTR_LA          a0, str_newline
+       jal             _mips_cps_puts
+       jr              s0
+       END(mips_cps_bev_dump)
+
+.pushsection   .data
+str_bev: .asciiz "BEV Exception: "
+str_newline: .asciiz "\r\n"
+.popsection
index 209ded1..8fd5a27 100644 (file)
 
 .set noreorder
 
+#ifdef CONFIG_64BIT
+# define STATUS_BITDEPS                ST0_KX
+#else
+# define STATUS_BITDEPS                0
+#endif
+
+#ifdef CONFIG_MIPS_CPS_NS16550
+
+#define DUMP_EXCEP(name)               \
+       PTR_LA  a0, 8f;                 \
+       jal     mips_cps_bev_dump;      \
+        nop;                           \
+       TEXT(name)
+
+#else /* !CONFIG_MIPS_CPS_NS16550 */
+
+#define DUMP_EXCEP(name)
+
+#endif /* !CONFIG_MIPS_CPS_NS16550 */
+
        /*
         * Set dest to non-zero if the core supports the MT ASE, else zero. If
         * MT is not supported then branch to nomt.
         */
        .macro  has_mt  dest, nomt
-       mfc0    \dest, CP0_CONFIG
-       bgez    \dest, \nomt
-        mfc0   \dest, CP0_CONFIG, 1
+       mfc0    \dest, CP0_CONFIG, 1
        bgez    \dest, \nomt
         mfc0   \dest, CP0_CONFIG, 2
        bgez    \dest, \nomt
 
 LEAF(mips_cps_core_entry)
        /*
-        * These first 12 bytes will be patched by cps_smp_setup to load the
-        * base address of the CM GCRs into register v1 and the CCA to use into
-        * register s0.
+        * These first 4 bytes will be patched by cps_smp_setup to load the
+        * CCA to use into register s0.
         */
-       .quad   0
        .word   0
 
        /* Check whether we're here due to an NMI */
@@ -71,7 +87,7 @@ not_nmi:
        mtc0    t0, CP0_CAUSE
 
        /* Setup Status */
-       li      t0, ST0_CU1 | ST0_CU0
+       li      t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS
        mtc0    t0, CP0_STATUS
 
        /*
@@ -151,6 +167,12 @@ dcache_done:
        mtc0    t0, CP0_CONFIG
        ehb
 
+       /* Calculate an uncached address for the CM GCRs */
+       MFC0    v1, CP0_CMGCRBASE
+       PTR_SLL v1, v1, 4
+       PTR_LI  t0, UNCAC_BASE
+       PTR_ADDU v1, v1, t0
+
        /* Enter the coherent domain */
        li      t0, 0xff
        sw      t0, GCR_CL_COHERENCE_OFS(v1)
@@ -188,36 +210,42 @@ dcache_done:
 
 .org 0x200
 LEAF(excep_tlbfill)
+       DUMP_EXCEP("TLB Fill")
        b       .
         nop
        END(excep_tlbfill)
 
 .org 0x280
 LEAF(excep_xtlbfill)
+       DUMP_EXCEP("XTLB Fill")
        b       .
         nop
        END(excep_xtlbfill)
 
 .org 0x300
 LEAF(excep_cache)
+       DUMP_EXCEP("Cache")
        b       .
         nop
        END(excep_cache)
 
 .org 0x380
 LEAF(excep_genex)
+       DUMP_EXCEP("General")
        b       .
         nop
        END(excep_genex)
 
 .org 0x400
 LEAF(excep_intex)
+       DUMP_EXCEP("Interrupt")
        b       .
         nop
        END(excep_intex)
 
 .org 0x480
 LEAF(excep_ejtag)
+       DUMP_EXCEP("EJTAG")
        PTR_LA  k0, ejtag_debug_handler
        jr      k0
         nop
index 09a51d0..6b90644 100644 (file)
@@ -536,8 +536,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
                c->options |= MIPS_CPU_SEGMENTS;
        if (config3 & MIPS_CONF3_MSA)
                c->ases |= MIPS_ASE_MSA;
-       /* Only tested on 32-bit cores */
-       if ((config3 & MIPS_CONF3_PW) && config_enabled(CONFIG_32BIT)) {
+       if (config3 & MIPS_CONF3_PW) {
                c->htw_seq = 0;
                c->options |= MIPS_CPU_HTW;
        }
index e5ed7ad..1f91056 100644 (file)
@@ -28,6 +28,43 @@ static u64 notrace r4k_read_sched_clock(void)
        return read_c0_count();
 }
 
+static inline unsigned int rdhwr_count(void)
+{
+       unsigned int count;
+
+       __asm__ __volatile__(
+       "       .set push\n"
+       "       .set mips32r2\n"
+       "       rdhwr   %0, $2\n"
+       "       .set pop\n"
+       : "=r" (count));
+
+       return count;
+}
+
+static bool rdhwr_count_usable(void)
+{
+       unsigned int prev, curr, i;
+
+       /*
+        * Older QEMUs have a broken implementation of RDHWR for the CP0 count
+        * which always returns a constant value. Try to identify this and don't
+        * use it in the VDSO if it is broken. This workaround can be removed
+        * once the fix has been in QEMU stable for a reasonable amount of time.
+        */
+       for (i = 0, prev = rdhwr_count(); i < 100; i++) {
+               curr = rdhwr_count();
+
+               if (curr != prev)
+                       return true;
+
+               prev = curr;
+       }
+
+       pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n");
+       return false;
+}
+
 int __init init_r4k_clocksource(void)
 {
        if (!cpu_has_counter || !mips_hpt_frequency)
@@ -36,6 +73,13 @@ int __init init_r4k_clocksource(void)
        /* Calculate a somewhat reasonable rating value */
        clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
 
+       /*
+        * R2 onwards makes the count accessible to user mode so it can be used
+        * by the VDSO (HWREna is configured by configure_hwrena()).
+        */
+       if (cpu_has_mips_r2_r6 && rdhwr_count_usable())
+               clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K;
+
        clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
        sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
index ab1478d..3e2b0b6 100644 (file)
@@ -134,6 +134,16 @@ void __init check_wait(void)
                return;
        }
 
+       /*
+        * MIPSr6 specifies that masked interrupts should unblock an executing
+        * wait instruction, and thus that it is safe for us to use
+        * r4k_wait_irqoff. Yippee!
+        */
+       if (cpu_has_mips_r6) {
+               cpu_wait = r4k_wait_irqoff;
+               return;
+       }
+
        switch (current_cpu_type()) {
        case CPU_R3081:
        case CPU_R3081E:
@@ -196,7 +206,6 @@ void __init check_wait(void)
        case CPU_INTERAPTIV:
        case CPU_M5150:
        case CPU_QEMU_GENERIC:
-       case CPU_I6400:
                cpu_wait = r4k_wait;
                if (read_c0_config7() & MIPS_CONF7_WII)
                        cpu_wait = r4k_wait_irqoff;
index b8ceee5..1448c1f 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 #include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
 
 #include <asm/mips-cm.h>
 #include <asm/mipsregs.h>
@@ -136,6 +138,9 @@ static char *cm3_causes[32] = {
        "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f"
 };
 
+static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock);
+static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags);
+
 phys_addr_t __mips_cm_phys_base(void)
 {
        u32 config3 = read_c0_config3();
@@ -200,6 +205,7 @@ int mips_cm_probe(void)
 {
        phys_addr_t addr;
        u32 base_reg;
+       unsigned cpu;
 
        /*
         * No need to probe again if we have already been
@@ -247,38 +253,70 @@ int mips_cm_probe(void)
        /* determine register width for this CM */
        mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3);
 
+       for_each_possible_cpu(cpu)
+               spin_lock_init(&per_cpu(cm_core_lock, cpu));
+
        return 0;
 }
 
-void mips_cm_error_report(void)
+void mips_cm_lock_other(unsigned int core, unsigned int vp)
 {
-       unsigned long revision = mips_cm_revision();
+       unsigned curr_core;
+       u32 val;
+
+       preempt_disable();
+       curr_core = current_cpu_data.core;
+       spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
+                         per_cpu(cm_core_lock_flags, curr_core));
+
+       if (mips_cm_revision() >= CM_REV_CM3) {
+               val = core << CM3_GCR_Cx_OTHER_CORE_SHF;
+               val |= vp << CM3_GCR_Cx_OTHER_VP_SHF;
+       } else {
+               BUG_ON(vp != 0);
+               val = core << CM_GCR_Cx_OTHER_CORENUM_SHF;
+       }
+
+       write_gcr_cl_other(val);
+
        /*
-        * CM3 has a 64-bit Error cause register with 0:57 containing the error
-        * info and 63:58 the error type. For old CMs, everything is contained
-        * in a single 32-bit register (0:26 and 31:27 respectively). Even
-        * though the cm_error is u64, we will simply ignore the upper word
-        * for CM2.
+        * Ensure the core-other region reflects the appropriate core &
+        * VP before any accesses to it occur.
         */
-       u64 cm_error = read_gcr_error_cause();
-       int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF +
-                                ((revision >= CM_REV_CM3) ? 31 : 0);
-       unsigned long cm_addr = read_gcr_error_addr();
-       unsigned long cm_other = read_gcr_error_mult();
+       mb();
+}
+
+void mips_cm_unlock_other(void)
+{
+       unsigned curr_core = current_cpu_data.core;
+
+       spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
+                              per_cpu(cm_core_lock_flags, curr_core));
+       preempt_enable();
+}
+
+void mips_cm_error_report(void)
+{
+       u64 cm_error, cm_addr, cm_other;
+       unsigned long revision;
        int ocause, cause;
        char buf[256];
 
        if (!mips_cm_present())
                return;
 
-       cause = cm_error >> cm_error_cause_sft;
+       revision = mips_cm_revision();
 
-       if (!cause)
-               /* All good */
-               return;
-
-       ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
        if (revision < CM_REV_CM3) { /* CM2 */
+               cm_error = read_gcr_error_cause();
+               cm_addr = read_gcr_error_addr();
+               cm_other = read_gcr_error_mult();
+               cause = cm_error >> CM_GCR_ERROR_CAUSE_ERRTYPE_SHF;
+               ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
+
+               if (!cause)
+                       return;
+
                if (cause < 16) {
                        unsigned long cca_bits = (cm_error >> 15) & 7;
                        unsigned long tr_bits = (cm_error >> 12) & 7;
@@ -310,18 +348,30 @@ void mips_cm_error_report(void)
                }
                        pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error,
                               cm2_causes[cause], buf);
-               pr_err("CM_ADDR =%08lx\n", cm_addr);
-               pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]);
+               pr_err("CM_ADDR =%08llx\n", cm_addr);
+               pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]);
        } else { /* CM3 */
-       /* Used by cause == {1,2,3} */
-               unsigned long core_id_bits = (cm_error >> 22) & 0xf;
-               unsigned long vp_id_bits = (cm_error >> 18) & 0xf;
-               unsigned long cmd_bits = (cm_error >> 14) & 0xf;
-               unsigned long cmd_group_bits = (cm_error >> 11) & 0xf;
-               unsigned long cm3_cca_bits = (cm_error >> 8) & 7;
-               unsigned long mcp_bits = (cm_error >> 5) & 0xf;
-               unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf;
-               unsigned long sched_bit = cm_error & 0x1;
+               ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits;
+               ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit;
+
+               cm_error = read64_gcr_error_cause();
+               cm_addr = read64_gcr_error_addr();
+               cm_other = read64_gcr_error_mult();
+               cause = cm_error >> CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF;
+               ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
+
+               if (!cause)
+                       return;
+
+               /* Used by cause == {1,2,3} */
+               core_id_bits = (cm_error >> 22) & 0xf;
+               vp_id_bits = (cm_error >> 18) & 0xf;
+               cmd_bits = (cm_error >> 14) & 0xf;
+               cmd_group_bits = (cm_error >> 11) & 0xf;
+               cm3_cca_bits = (cm_error >> 8) & 7;
+               mcp_bits = (cm_error >> 5) & 0xf;
+               cm3_tr_bits = (cm_error >> 1) & 0xf;
+               sched_bit = cm_error & 0x1;
 
                if (cause == 1 || cause == 3) { /* Tag ECC */
                        unsigned long tag_ecc = (cm_error >> 57) & 0x1;
@@ -363,12 +413,14 @@ void mips_cm_error_report(void)
                                 cm3_cmd_group[cmd_group_bits],
                                 cm3_cca_bits, 1 << mcp_bits,
                                 cm3_tr[cm3_tr_bits], sched_bit);
+               } else {
+                       buf[0] = 0;
                }
 
                pr_err("CM_ERROR=%llx %s <%s>\n", cm_error,
                       cm3_causes[cause], buf);
-               pr_err("CM_ADDR =%lx\n", cm_addr);
-               pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]);
+               pr_err("CM_ADDR =%llx\n", cm_addr);
+               pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]);
        }
 
        /* reprime cause register */
index 8af4d62..566b8d2 100644 (file)
@@ -76,6 +76,12 @@ void mips_cpc_lock_other(unsigned int core)
        spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core),
                          per_cpu(cpc_core_lock_flags, curr_core));
        write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF);
+
+       /*
+        * Ensure the core-other region reflects the appropriate core &
+        * VP before any accesses to it occur.
+        */
+       mb();
 }
 
 void mips_cpc_unlock_other(void)
index f2977f0..1f5aac7 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/asm.h>
 #include <asm/branch.h>
 #include <asm/break.h>
+#include <asm/debug.h>
 #include <asm/fpu.h>
 #include <asm/fpu_emulator.h>
 #include <asm/inst.h>
@@ -2363,7 +2364,6 @@ static const struct file_operations mipsr2_clear_fops = {
 
 static int __init mipsr2_init_debugfs(void)
 {
-       extern struct dentry    *mips_debugfs_dir;
        struct dentry           *mipsr2_emul;
 
        if (!mips_debugfs_dir)
index 076ead2..87bc74a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <asm/cpu.h>
+#include <asm/debug.h>
 #include <asm/mipsregs.h>
 
 static void build_segment_config(char *str, unsigned int cfg)
@@ -91,7 +92,6 @@ static const struct file_operations segments_fops = {
 
 static int __init segments_info(void)
 {
-       extern struct dentry *mips_debugfs_dir;
        struct dentry *segments;
 
        if (cpu_has_segments) {
index 4795151..5b46b67 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/cache.h>
 #include <asm/cdmm.h>
 #include <asm/cpu.h>
+#include <asm/debug.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/smp-ops.h>
index 2fec67b..bf792e2 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/ucontext.h>
 #include <asm/cpu-features.h>
 #include <asm/war.h>
-#include <asm/vdso.h>
 #include <asm/dsp.h>
 #include <asm/inst.h>
 #include <asm/msa.h>
@@ -752,16 +751,15 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig,
 struct mips_abi mips_abi = {
 #ifdef CONFIG_TRAD_SIGNALS
        .setup_frame    = setup_frame,
-       .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
 #endif
        .setup_rt_frame = setup_rt_frame,
-       .rt_signal_return_offset =
-               offsetof(struct mips_vdso, rt_signal_trampoline),
        .restart        = __NR_restart_syscall,
 
        .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
        .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
        .off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
+
+       .vdso           = &vdso_image,
 };
 
 static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
@@ -801,11 +799,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
        }
 
        if (sig_uses_siginfo(&ksig->ka))
-               ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
+               ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn,
                                          ksig, regs, oldset);
        else
-               ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig,
-                                      regs, oldset);
+               ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn,
+                                      ksig, regs, oldset);
 
        signal_setup_done(ret, ksig, 0);
 }
index f7e8952..4909639 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/ucontext.h>
 #include <asm/fpu.h>
 #include <asm/war.h>
-#include <asm/vdso.h>
 #include <asm/dsp.h>
 
 #include "signal-common.h"
@@ -406,14 +405,12 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
  */
 struct mips_abi mips_abi_32 = {
        .setup_frame    = setup_frame_32,
-       .signal_return_offset =
-               offsetof(struct mips_vdso, o32_signal_trampoline),
        .setup_rt_frame = setup_rt_frame_32,
-       .rt_signal_return_offset =
-               offsetof(struct mips_vdso, o32_rt_signal_trampoline),
        .restart        = __NR_O32_restart_syscall,
 
        .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
        .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
        .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
+
+       .vdso           = &vdso_image_o32,
 };
index 0d017fd..a7bc384 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/fpu.h>
 #include <asm/cpu-features.h>
 #include <asm/war.h>
-#include <asm/vdso.h>
 
 #include "signal-common.h"
 
@@ -151,11 +150,11 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig,
 
 struct mips_abi mips_abi_n32 = {
        .setup_rt_frame = setup_rt_frame_n32,
-       .rt_signal_return_offset =
-               offsetof(struct mips_vdso, n32_rt_signal_trampoline),
        .restart        = __NR_N32_restart_syscall,
 
        .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
        .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
        .off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
+
+       .vdso           = &vdso_image_n32,
 };
index c889377..e04c805 100644 (file)
@@ -8,6 +8,7 @@
  * option) any later version.
  */
 
+#include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/irqchip/mips-gic.h>
 #include <linux/sched.h>
@@ -37,8 +38,9 @@ static unsigned core_vpe_count(unsigned core)
        if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
                return 1;
 
-       write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+       mips_cm_lock_other(core, 0);
        cfg = read_gcr_co_config() & CM_GCR_Cx_CONFIG_PVPE_MSK;
+       mips_cm_unlock_other();
        return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
 }
 
@@ -133,11 +135,9 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
        /*
         * Patch the start of mips_cps_core_entry to provide:
         *
-        * v1 = CM base address
         * s0 = kseg0 CCA
         */
        entry_code = (u32 *)&mips_cps_core_entry;
-       UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
        uasm_i_addiu(&entry_code, 16, 0, cca);
        blast_dcache_range((unsigned long)&mips_cps_core_entry,
                           (unsigned long)entry_code);
@@ -190,10 +190,11 @@ err_out:
 
 static void boot_core(unsigned core)
 {
-       u32 access;
+       u32 access, stat, seq_state;
+       unsigned timeout;
 
        /* Select the appropriate core */
-       write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+       mips_cm_lock_other(core, 0);
 
        /* Set its reset vector */
        write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
@@ -210,12 +211,36 @@ static void boot_core(unsigned core)
                /* Reset the core */
                mips_cpc_lock_other(core);
                write_cpc_co_cmd(CPC_Cx_CMD_RESET);
+
+               timeout = 100;
+               while (true) {
+                       stat = read_cpc_co_stat_conf();
+                       seq_state = stat & CPC_Cx_STAT_CONF_SEQSTATE_MSK;
+
+                       /* U6 == coherent execution, ie. the core is up */
+                       if (seq_state == CPC_Cx_STAT_CONF_SEQSTATE_U6)
+                               break;
+
+                       /* Delay a little while before we start warning */
+                       if (timeout) {
+                               timeout--;
+                               mdelay(10);
+                               continue;
+                       }
+
+                       pr_warn("Waiting for core %u to start... STAT_CONF=0x%x\n",
+                               core, stat);
+                       mdelay(1000);
+               }
+
                mips_cpc_unlock_other();
        } else {
                /* Take the core out of reset */
                write_gcr_co_reset_release(0);
        }
 
+       mips_cm_unlock_other();
+
        /* The core is now powered up */
        bitmap_set(core_power, core, 1);
 }
index 5f0ab5b..9b63829 100644 (file)
@@ -46,9 +46,11 @@ void gic_send_ipi_single(int cpu, unsigned int action)
 
        if (mips_cpc_present() && (core != current_cpu_data.core)) {
                while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) {
+                       mips_cm_lock_other(core, 0);
                        mips_cpc_lock_other(core);
                        write_cpc_co_cmd(CPC_Cx_CMD_PWRUP);
                        mips_cpc_unlock_other();
+                       mips_cm_unlock_other();
                }
        }
 
index 39f7ab7..f7d8695 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/debugfs.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
-
+#include <asm/debug.h>
 
 static int ss_get(void *data, u64 *val)
 {
@@ -115,8 +115,6 @@ static int multi_get(void *data, u64 *val)
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n");
 
-
-extern struct dentry *mips_debugfs_dir;
 static int __init spinlock_test(void)
 {
        struct dentry *d;
index 1ba775d..506021f 100644 (file)
  * Save stack-backtrace addresses into a stack_trace buffer:
  */
 static void save_raw_context_stack(struct stack_trace *trace,
-       unsigned long reg29)
+       unsigned long reg29, int savesched)
 {
        unsigned long *sp = (unsigned long *)reg29;
        unsigned long addr;
 
        while (!kstack_end(sp)) {
                addr = *sp++;
-               if (__kernel_text_address(addr)) {
+               if (__kernel_text_address(addr) &&
+                   (savesched || !in_sched_functions(addr))) {
                        if (trace->skip > 0)
                                trace->skip--;
                        else
@@ -31,7 +32,7 @@ static void save_raw_context_stack(struct stack_trace *trace,
 }
 
 static void save_context_stack(struct stack_trace *trace,
-       struct task_struct *tsk, struct pt_regs *regs)
+       struct task_struct *tsk, struct pt_regs *regs, int savesched)
 {
        unsigned long sp = regs->regs[29];
 #ifdef CONFIG_KALLSYMS
@@ -43,20 +44,22 @@ static void save_context_stack(struct stack_trace *trace,
                        (unsigned long)task_stack_page(tsk);
                if (stack_page && sp >= stack_page &&
                    sp <= stack_page + THREAD_SIZE - 32)
-                       save_raw_context_stack(trace, sp);
+                       save_raw_context_stack(trace, sp, savesched);
                return;
        }
        do {
-               if (trace->skip > 0)
-                       trace->skip--;
-               else
-                       trace->entries[trace->nr_entries++] = pc;
-               if (trace->nr_entries >= trace->max_entries)
-                       break;
+               if (savesched || !in_sched_functions(pc)) {
+                       if (trace->skip > 0)
+                               trace->skip--;
+                       else
+                               trace->entries[trace->nr_entries++] = pc;
+                       if (trace->nr_entries >= trace->max_entries)
+                               break;
+               }
                pc = unwind_stack(tsk, &sp, pc, &ra);
        } while (pc);
 #else
-       save_raw_context_stack(trace, sp);
+       save_raw_context_stack(trace, sp, savesched);
 #endif
 }
 
@@ -82,6 +85,6 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
                regs->cp0_epc = tsk->thread.reg31;
        } else
                prepare_frametrace(regs);
-       save_context_stack(trace, tsk, regs);
+       save_context_stack(trace, tsk, regs, tsk == current);
 }
 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
index fdb392b..4e106d5 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/irq.h>
 #include <linux/perf_event.h>
 
+#include <asm/addrspace.h>
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
 #include <asm/break.h>
@@ -2204,12 +2205,8 @@ void __init trap_init(void)
                ebase = (unsigned long)
                        __alloc_bootmem(size, 1 << fls(size), 0);
        } else {
-#ifdef CONFIG_KVM_GUEST
-#define KVM_GUEST_KSEG0     0x40000000
-        ebase = KVM_GUEST_KSEG0;
-#else
-        ebase = CKSEG0;
-#endif
+               ebase = CAC_BASE;
+
                if (cpu_has_mips_r2_r6)
                        ebase += (read_c0_ebase() & 0x3ffff000);
        }
index 990354d..490cea5 100644 (file)
@@ -85,6 +85,7 @@
 #include <asm/branch.h>
 #include <asm/byteorder.h>
 #include <asm/cop2.h>
+#include <asm/debug.h>
 #include <asm/fpu.h>
 #include <asm/fpu_emulator.h>
 #include <asm/inst.h>
@@ -2295,7 +2296,6 @@ sigbus:
 }
 
 #ifdef CONFIG_DEBUG_FS
-extern struct dentry *mips_debugfs_dir;
 static int __init debugfs_unaligned(void)
 {
        struct dentry *d;
index ed2a278..975e997 100644 (file)
 /*
- * 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.
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
  *
- * Copyright (C) 2009, 2010 Cavium Networks, Inc.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/binfmts.h>
 #include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/unistd.h>
-#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
 
+#include <asm/abi.h>
 #include <asm/vdso.h>
-#include <asm/uasm.h>
-#include <asm/processor.h>
+
+/* Kernel-provided data used by the VDSO. */
+static union mips_vdso_data vdso_data __page_aligned_data;
 
 /*
- * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as
+ * what we map and where within the area they are mapped is determined at
+ * runtime.
  */
-#define __NR_O32_sigreturn             4119
-#define __NR_O32_rt_sigreturn          4193
-#define __NR_N32_rt_sigreturn          6211
+static struct page *no_pages[] = { NULL };
+static struct vm_special_mapping vdso_vvar_mapping = {
+       .name = "[vvar]",
+       .pages = no_pages,
+};
 
-static struct page *vdso_page;
-
-static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
+static void __init init_vdso_image(struct mips_vdso_image *image)
 {
-       uasm_i_addiu(&tramp, 2, 0, sigreturn);  /* li v0, sigreturn */
-       uasm_i_syscall(&tramp, 0);
+       unsigned long num_pages, i;
+
+       BUG_ON(!PAGE_ALIGNED(image->data));
+       BUG_ON(!PAGE_ALIGNED(image->size));
+
+       num_pages = image->size / PAGE_SIZE;
+
+       for (i = 0; i < num_pages; i++) {
+               image->mapping.pages[i] =
+                       virt_to_page(image->data + (i * PAGE_SIZE));
+       }
 }
 
 static int __init init_vdso(void)
 {
-       struct mips_vdso *vdso;
-
-       vdso_page = alloc_page(GFP_KERNEL);
-       if (!vdso_page)
-               panic("Cannot allocate vdso");
-
-       vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
-       if (!vdso)
-               panic("Cannot map vdso");
-       clear_page(vdso);
-
-       install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
-#ifdef CONFIG_32BIT
-       install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
-#else
-       install_trampoline(vdso->n32_rt_signal_trampoline,
-                          __NR_N32_rt_sigreturn);
-       install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
-       install_trampoline(vdso->o32_rt_signal_trampoline,
-                          __NR_O32_rt_sigreturn);
+       init_vdso_image(&vdso_image);
+
+#ifdef CONFIG_MIPS32_O32
+       init_vdso_image(&vdso_image_o32);
 #endif
 
-       vunmap(vdso);
+#ifdef CONFIG_MIPS32_N32
+       init_vdso_image(&vdso_image_n32);
+#endif
 
        return 0;
 }
 subsys_initcall(init_vdso);
 
-static unsigned long vdso_addr(unsigned long start)
+void update_vsyscall(struct timekeeper *tk)
 {
-       unsigned long offset = 0UL;
-
-       if (current->flags & PF_RANDOMIZE) {
-               offset = get_random_int();
-               offset <<= PAGE_SHIFT;
-               if (TASK_IS_32BIT_ADDR)
-                       offset &= 0xfffffful;
-               else
-                       offset &= 0xffffffful;
+       vdso_data_write_begin(&vdso_data);
+
+       vdso_data.xtime_sec = tk->xtime_sec;
+       vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec;
+       vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec;
+       vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec;
+       vdso_data.cs_shift = tk->tkr_mono.shift;
+
+       vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode;
+       if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+               vdso_data.cs_mult = tk->tkr_mono.mult;
+               vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last;
+               vdso_data.cs_mask = tk->tkr_mono.mask;
        }
 
-       return STACK_TOP + offset;
+       vdso_data_write_end(&vdso_data);
+}
+
+void update_vsyscall_tz(void)
+{
+       if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+               vdso_data.tz_minuteswest = sys_tz.tz_minuteswest;
+               vdso_data.tz_dsttime = sys_tz.tz_dsttime;
+       }
 }
 
 int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
-       int ret;
-       unsigned long addr;
+       struct mips_vdso_image *image = current->thread.abi->vdso;
        struct mm_struct *mm = current->mm;
+       unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr;
+       struct vm_area_struct *vma;
+       struct resource gic_res;
+       int ret;
 
        down_write(&mm->mmap_sem);
 
-       addr = vdso_addr(mm->start_stack);
+       /*
+        * Determine total area size. This includes the VDSO data itself, the
+        * data page, and the GIC user page if present. Always create a mapping
+        * for the GIC user area if the GIC is present regardless of whether it
+        * is the current clocksource, in case it comes into use later on. We
+        * only map a page even though the total area is 64K, as we only need
+        * the counter registers at the start.
+        */
+       gic_size = gic_present ? PAGE_SIZE : 0;
+       vvar_size = gic_size + PAGE_SIZE;
+       size = vvar_size + image->size;
+
+       base = get_unmapped_area(NULL, 0, size, 0, 0);
+       if (IS_ERR_VALUE(base)) {
+               ret = base;
+               goto out;
+       }
+
+       data_addr = base + gic_size;
+       vdso_addr = data_addr + PAGE_SIZE;
 
-       addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
-       if (IS_ERR_VALUE(addr)) {
-               ret = addr;
-               goto up_fail;
+       vma = _install_special_mapping(mm, base, vvar_size,
+                                      VM_READ | VM_MAYREAD,
+                                      &vdso_vvar_mapping);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto out;
        }
 
-       ret = install_special_mapping(mm, addr, PAGE_SIZE,
-                                     VM_READ|VM_EXEC|
-                                     VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-                                     &vdso_page);
+       /* Map GIC user page. */
+       if (gic_size) {
+               ret = gic_get_usm_range(&gic_res);
+               if (ret)
+                       goto out;
+
+               ret = io_remap_pfn_range(vma, base,
+                                        gic_res.start >> PAGE_SHIFT,
+                                        gic_size,
+                                        pgprot_noncached(PAGE_READONLY));
+               if (ret)
+                       goto out;
+       }
 
+       /* Map data page. */
+       ret = remap_pfn_range(vma, data_addr,
+                             virt_to_phys(&vdso_data) >> PAGE_SHIFT,
+                             PAGE_SIZE, PAGE_READONLY);
        if (ret)
-               goto up_fail;
+               goto out;
+
+       /* Map VDSO image. */
+       vma = _install_special_mapping(mm, vdso_addr, image->size,
+                                      VM_READ | VM_EXEC |
+                                      VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+                                      &image->mapping);
+       if (IS_ERR(vma)) {
+               ret = PTR_ERR(vma);
+               goto out;
+       }
 
-       mm->context.vdso = (void *)addr;
+       mm->context.vdso = (void *)vdso_addr;
+       ret = 0;
 
-up_fail:
+out:
        up_write(&mm->mmap_sem);
        return ret;
 }
-
-const char *arch_vma_name(struct vm_area_struct *vma)
-{
-       if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
-               return "[vdso]";
-       return NULL;
-}
index 3fc2e6d..a0706fd 100644 (file)
@@ -99,6 +99,23 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL(clk_set_rate);
 
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (unlikely(!clk_good(clk)))
+               return 0;
+       if (clk->rates && *clk->rates) {
+               unsigned long *r = clk->rates;
+
+               while (*r && (*r != rate))
+                       r++;
+               if (!*r) {
+                       return clk->rate;
+               }
+       }
+       return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
 int clk_enable(struct clk *clk)
 {
        if (unlikely(!clk_good(clk)))
index 77e4bdb..7376ce8 100644 (file)
 #define CLOCK_240M     240000000
 #define CLOCK_250M     250000000
 #define CLOCK_266M     266666666
+#define CLOCK_288M     288888888
 #define CLOCK_300M     300000000
 #define CLOCK_333M     333333333
+#define CLOCK_360M     360000000
 #define CLOCK_393M     393215332
 #define CLOCK_400M     400000000
+#define CLOCK_432M     432000000
 #define CLOCK_450M     450000000
 #define CLOCK_500M     500000000
 #define CLOCK_600M     600000000
+#define CLOCK_666M     666666666
+#define CLOCK_720M     720000000
 
 /* clock out speeds */
 #define CLOCK_32_768K  32768
@@ -80,4 +85,12 @@ extern unsigned long ltq_vr9_cpu_hz(void);
 extern unsigned long ltq_vr9_fpi_hz(void);
 extern unsigned long ltq_vr9_pp32_hz(void);
 
+extern unsigned long ltq_ar10_cpu_hz(void);
+extern unsigned long ltq_ar10_fpi_hz(void);
+extern unsigned long ltq_ar10_pp32_hz(void);
+
+extern unsigned long ltq_grx390_cpu_hz(void);
+extern unsigned long ltq_grx390_fpi_hz(void);
+extern unsigned long ltq_grx390_pp32_hz(void);
+
 #endif
index 2c218c3..2e7f60c 100644 (file)
@@ -369,8 +369,8 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
                if (of_address_to_resource(node, i, &res))
                        panic("Failed to get icu memory range");
 
-               if (request_mem_region(res.start, resource_size(&res),
-                                       res.name) < 0)
+               if (!request_mem_region(res.start, resource_size(&res),
+                                       res.name))
                        pr_err("Failed to request icu memory");
 
                ltq_icu_membase[i] = ioremap_nocache(res.start,
@@ -449,8 +449,8 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
                if (ret != exin_avail)
                        panic("failed to load external irq resources");
 
-               if (request_mem_region(res.start, resource_size(&res),
-                                                       res.name) < 0)
+               if (!request_mem_region(res.start, resource_size(&res),
+                                                       res.name))
                        pr_err("Failed to request eiu memory");
 
                ltq_eiu_membase = ioremap_nocache(res.start,
index 8750dc0..80aad30 100644 (file)
@@ -4,6 +4,7 @@
  *  by the Free Software Foundation.
  *
  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
  */
 
 #include <linux/io.h>
@@ -25,9 +26,9 @@ static unsigned int ram_clocks[] = {
 /* legacy xway clock */
 #define CGU_SYS                        0x10
 
-/* vr9 clock */
-#define CGU_SYS_VR9            0x0c
-#define CGU_IF_CLK_VR9         0x24
+/* vr9, ar10/grx390 clock */
+#define CGU_SYS_XRX            0x0c
+#define CGU_IF_CLK_AR10                0x24
 
 unsigned long ltq_danube_fpi_hz(void)
 {
@@ -104,7 +105,7 @@ unsigned long ltq_vr9_cpu_hz(void)
        unsigned int cpu_sel;
        unsigned long clk;
 
-       cpu_sel = (ltq_cgu_r32(CGU_SYS_VR9) >> 4) & 0xf;
+       cpu_sel = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0xf;
 
        switch (cpu_sel) {
        case 0:
@@ -145,7 +146,7 @@ unsigned long ltq_vr9_fpi_hz(void)
        unsigned long clk;
 
        cpu_clk = ltq_vr9_cpu_hz();
-       ocp_sel = ltq_cgu_r32(CGU_SYS_VR9) & 0x3;
+       ocp_sel = ltq_cgu_r32(CGU_SYS_XRX) & 0x3;
 
        switch (ocp_sel) {
        case 0:
@@ -174,15 +175,18 @@ unsigned long ltq_vr9_fpi_hz(void)
 
 unsigned long ltq_vr9_pp32_hz(void)
 {
-       unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 3;
+       unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
        unsigned long clk;
 
        switch (clksys) {
+       case 0:
+               clk = CLOCK_500M;
+               break;
        case 1:
-               clk = CLOCK_450M;
+               clk = CLOCK_432M;
                break;
        case 2:
-               clk = CLOCK_300M;
+               clk = CLOCK_288M;
                break;
        default:
                clk = CLOCK_500M;
@@ -191,3 +195,158 @@ unsigned long ltq_vr9_pp32_hz(void)
 
        return clk;
 }
+
+unsigned long ltq_ar10_cpu_hz(void)
+{
+       unsigned int clksys;
+       int cpu_fs = (ltq_cgu_r32(CGU_SYS_XRX) >> 8) & 0x1;
+       int freq_div = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7;
+
+       switch (cpu_fs) {
+       case 0:
+               clksys = CLOCK_500M;
+               break;
+       case 1:
+               clksys = CLOCK_600M;
+               break;
+       default:
+               clksys = CLOCK_500M;
+               break;
+       }
+
+       switch (freq_div) {
+       case 0:
+               return clksys;
+       case 1:
+               return clksys >> 1;
+       case 2:
+               return clksys >> 2;
+       default:
+               return clksys;
+       }
+}
+
+unsigned long ltq_ar10_fpi_hz(void)
+{
+       int freq_fpi = (ltq_cgu_r32(CGU_IF_CLK_AR10) >> 25) & 0xf;
+
+       switch (freq_fpi) {
+       case 1:
+               return CLOCK_300M;
+       case 5:
+               return CLOCK_250M;
+       case 2:
+               return CLOCK_150M;
+       case 6:
+               return CLOCK_125M;
+
+       default:
+               return CLOCK_125M;
+       }
+}
+
+unsigned long ltq_ar10_pp32_hz(void)
+{
+       unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
+       unsigned long clk;
+
+       switch (clksys) {
+       case 1:
+               clk = CLOCK_250M;
+               break;
+       case 4:
+               clk = CLOCK_400M;
+               break;
+       default:
+               clk = CLOCK_250M;
+               break;
+       }
+
+       return clk;
+}
+
+unsigned long ltq_grx390_cpu_hz(void)
+{
+       unsigned int clksys;
+       int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3);
+       int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7);
+
+       switch (cpu_fs) {
+       case 0:
+               clksys = CLOCK_600M;
+               break;
+       case 1:
+               clksys = CLOCK_666M;
+               break;
+       case 2:
+               clksys = CLOCK_720M;
+               break;
+       default:
+               clksys = CLOCK_600M;
+               break;
+       }
+
+       switch (freq_div) {
+       case 0:
+               return clksys;
+       case 1:
+               return clksys >> 1;
+       case 2:
+               return clksys >> 2;
+       default:
+               return clksys;
+       }
+}
+
+unsigned long ltq_grx390_fpi_hz(void)
+{
+       /* fpi clock is derived from ddr_clk */
+       unsigned int clksys;
+       int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3);
+       int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX)) & 0x7);
+       switch (cpu_fs) {
+       case 0:
+               clksys = CLOCK_600M;
+               break;
+       case 1:
+               clksys = CLOCK_666M;
+               break;
+       case 2:
+               clksys = CLOCK_720M;
+               break;
+       default:
+               clksys = CLOCK_600M;
+               break;
+       }
+
+       switch (freq_div) {
+       case 1:
+               return clksys >> 1;
+       case 2:
+               return clksys >> 2;
+       default:
+               return clksys >> 1;
+       }
+}
+
+unsigned long ltq_grx390_pp32_hz(void)
+{
+       unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
+       unsigned long clk;
+
+       switch (clksys) {
+       case 1:
+               clk = CLOCK_250M;
+               break;
+       case 2:
+               clk = CLOCK_432M;
+               break;
+       case 4:
+               clk = CLOCK_400M;
+               break;
+       default:
+               clk = CLOCK_250M;
+               break;
+       }
+       return clk;
+}
index 248429a..8f6e02f 100644 (file)
@@ -4,6 +4,7 @@
  *  by the Free Software Foundation.
  *
  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
  */
 
 #include <linux/export.h>
 #define SOC_TWINPASS   "Twinpass"
 #define SOC_AMAZON_SE  "Amazon_SE"
 #define SOC_AR9                "AR9"
-#define SOC_GR9                "GR9"
-#define SOC_VR9                "VR9"
+#define SOC_GR9                "GRX200"
+#define SOC_VR9                "xRX200"
+#define SOC_VRX220     "xRX220"
+#define SOC_AR10       "xRX300"
+#define SOC_GRX390     "xRX330"
 
 #define COMP_DANUBE    "lantiq,danube"
 #define COMP_TWINPASS  "lantiq,twinpass"
@@ -28,6 +32,8 @@
 #define COMP_AR9       "lantiq,ar9"
 #define COMP_GR9       "lantiq,gr9"
 #define COMP_VR9       "lantiq,vr9"
+#define COMP_AR10      "lantiq,ar10"
+#define COMP_GRX390    "lantiq,grx390"
 
 #define PART_SHIFT     12
 #define PART_MASK      0x0FFFFFFF
@@ -101,6 +107,12 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
                i->compatible = COMP_VR9;
                break;
 
+       case SOC_ID_VRX220:
+               i->name = SOC_VRX220;
+               i->type = SOC_TYPE_VRX220;
+               i->compatible = COMP_VR9;
+               break;
+
        case SOC_ID_GRX282_2:
        case SOC_ID_GRX288_2:
                i->name = SOC_GR9;
@@ -108,6 +120,25 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
                i->compatible = COMP_GR9;
                break;
 
+       case SOC_ID_ARX362:
+       case SOC_ID_ARX368:
+       case SOC_ID_ARX382:
+       case SOC_ID_ARX388:
+       case SOC_ID_URX388:
+               i->name = SOC_AR10;
+               i->type = SOC_TYPE_AR10;
+               i->compatible = COMP_AR10;
+               break;
+
+       case SOC_ID_GRX383:
+       case SOC_ID_GRX369:
+       case SOC_ID_GRX387:
+       case SOC_ID_GRX389:
+               i->name = SOC_GRX390;
+               i->type = SOC_TYPE_GRX390;
+               i->compatible = COMP_GRX390;
+               break;
+
        default:
                unreachable();
                break;
index fe68f9a..dd1aaaf 100644 (file)
@@ -4,6 +4,7 @@
  *  by the Free Software Foundation.
  *
  *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
  */
 
 #include <linux/init.h>
@@ -22,9 +23,6 @@
 
 #include "../prom.h"
 
-#define ltq_rcu_w32(x, y)      ltq_w32((x), ltq_rcu_membase + (y))
-#define ltq_rcu_r32(x)         ltq_r32(ltq_rcu_membase + (x))
-
 /* reset request register */
 #define RCU_RST_REQ            0x0010
 /* reset status register */
 /* vr9 gphy registers */
 #define RCU_GFS_ADD0_XRX200    0x0020
 #define RCU_GFS_ADD1_XRX200    0x0068
+/* xRX300 gphy registers */
+#define RCU_GFS_ADD0_XRX300    0x0020
+#define RCU_GFS_ADD1_XRX300    0x0058
+#define RCU_GFS_ADD2_XRX300    0x00AC
+/* xRX330 gphy registers */
+#define RCU_GFS_ADD0_XRX330    0x0020
+#define RCU_GFS_ADD1_XRX330    0x0058
+#define RCU_GFS_ADD2_XRX330    0x00AC
+#define RCU_GFS_ADD3_XRX330    0x0264
 
 /* reboot bit */
 #define RCU_RD_GPHY0_XRX200    BIT(31)
 #define RCU_RD_SRST            BIT(30)
 #define RCU_RD_GPHY1_XRX200    BIT(29)
+/* xRX300 bits */
+#define RCU_RD_GPHY0_XRX300    BIT(31)
+#define RCU_RD_GPHY1_XRX300    BIT(29)
+#define RCU_RD_GPHY2_XRX300    BIT(28)
+/* xRX330 bits */
+#define RCU_RD_GPHY0_XRX330    BIT(31)
+#define RCU_RD_GPHY1_XRX330    BIT(29)
+#define RCU_RD_GPHY2_XRX330    BIT(28)
+#define RCU_RD_GPHY3_XRX330    BIT(10)
 
 /* reset cause */
 #define RCU_STAT_SHIFT         26
 /* remapped base addr of the reset control unit */
 static void __iomem *ltq_rcu_membase;
 static struct device_node *ltq_rcu_np;
+static DEFINE_SPINLOCK(ltq_rcu_lock);
+
+static void ltq_rcu_w32(uint32_t val, uint32_t reg_off)
+{
+       ltq_w32(val, ltq_rcu_membase + reg_off);
+}
+
+static uint32_t ltq_rcu_r32(uint32_t reg_off)
+{
+       return ltq_r32(ltq_rcu_membase + reg_off);
+}
+
+static void ltq_rcu_w32_mask(uint32_t clr, uint32_t set, uint32_t reg_off)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ltq_rcu_lock, flags);
+       ltq_rcu_w32((ltq_rcu_r32(reg_off) & ~(clr)) | (set), reg_off);
+       spin_unlock_irqrestore(&ltq_rcu_lock, flags);
+}
 
 /* This function is used by the watchdog driver */
 int ltq_reset_cause(void)
@@ -67,15 +103,40 @@ unsigned char ltq_boot_select(void)
        return RCU_BOOT_SEL(val);
 }
 
-/* reset / boot a gphy */
-static struct ltq_xrx200_gphy_reset {
+struct ltq_gphy_reset {
        u32 rd;
        u32 addr;
-} xrx200_gphy[] = {
+};
+
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx200_gphy[] = {
        {RCU_RD_GPHY0_XRX200, RCU_GFS_ADD0_XRX200},
        {RCU_RD_GPHY1_XRX200, RCU_GFS_ADD1_XRX200},
 };
 
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx300_gphy[] = {
+       {RCU_RD_GPHY0_XRX300, RCU_GFS_ADD0_XRX300},
+       {RCU_RD_GPHY1_XRX300, RCU_GFS_ADD1_XRX300},
+       {RCU_RD_GPHY2_XRX300, RCU_GFS_ADD2_XRX300},
+};
+
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx330_gphy[] = {
+       {RCU_RD_GPHY0_XRX330, RCU_GFS_ADD0_XRX330},
+       {RCU_RD_GPHY1_XRX330, RCU_GFS_ADD1_XRX330},
+       {RCU_RD_GPHY2_XRX330, RCU_GFS_ADD2_XRX330},
+       {RCU_RD_GPHY3_XRX330, RCU_GFS_ADD3_XRX330},
+};
+
+static void xrx200_gphy_boot_addr(struct ltq_gphy_reset *phy_regs,
+                                 dma_addr_t dev_addr)
+{
+       ltq_rcu_w32_mask(0, phy_regs->rd, RCU_RST_REQ);
+       ltq_rcu_w32(dev_addr, phy_regs->addr);
+       ltq_rcu_w32_mask(phy_regs->rd, 0,  RCU_RST_REQ);
+}
+
 /* reset and boot a gphy. these phys only exist on xrx200 SoC */
 int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
 {
@@ -86,23 +147,34 @@ int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
                return -EINVAL;
        }
 
-       clk = clk_get_sys("1f203000.rcu", "gphy");
-       if (IS_ERR(clk))
-               return PTR_ERR(clk);
-
-       clk_enable(clk);
-
-       if (id > 1) {
-               dev_err(dev, "%u is an invalid gphy id\n", id);
-               return -EINVAL;
+       if (of_machine_is_compatible("lantiq,vr9")) {
+               clk = clk_get_sys("1f203000.rcu", "gphy");
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+               clk_enable(clk);
        }
+
        dev_info(dev, "booting GPHY%u firmware at %X\n", id, dev_addr);
 
-       ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | xrx200_gphy[id].rd,
-                       RCU_RST_REQ);
-       ltq_rcu_w32(dev_addr, xrx200_gphy[id].addr);
-       ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~xrx200_gphy[id].rd,
-                       RCU_RST_REQ);
+       if (of_machine_is_compatible("lantiq,vr9")) {
+               if (id >= ARRAY_SIZE(xrx200_gphy)) {
+                       dev_err(dev, "%u is an invalid gphy id\n", id);
+                       return -EINVAL;
+               }
+               xrx200_gphy_boot_addr(&xrx200_gphy[id], dev_addr);
+       } else if (of_machine_is_compatible("lantiq,ar10")) {
+               if (id >= ARRAY_SIZE(xrx300_gphy)) {
+                       dev_err(dev, "%u is an invalid gphy id\n", id);
+                       return -EINVAL;
+               }
+               xrx200_gphy_boot_addr(&xrx300_gphy[id], dev_addr);
+       } else if (of_machine_is_compatible("lantiq,grx390")) {
+               if (id >= ARRAY_SIZE(xrx330_gphy)) {
+                       dev_err(dev, "%u is an invalid gphy id\n", id);
+                       return -EINVAL;
+               }
+               xrx200_gphy_boot_addr(&xrx330_gphy[id], dev_addr);
+       }
        return 0;
 }
 
@@ -216,7 +288,7 @@ static int __init mips_reboot_setup(void)
        if (of_address_to_resource(ltq_rcu_np, 0, &res))
                panic("Failed to get rcu memory range");
 
-       if (request_mem_region(res.start, resource_size(&res), res.name) < 0)
+       if (!request_mem_region(res.start, resource_size(&res), res.name))
                pr_err("Failed to request rcu memory");
 
        ltq_rcu_membase = ioremap_nocache(res.start, resource_size(&res));
index 2b15491..7b3a014 100644 (file)
@@ -4,11 +4,13 @@
  *  by the Free Software Foundation.
  *
  *  Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
  */
 
 #include <linux/ioport.h>
 #include <linux/export.h>
 #include <linux/clkdev.h>
+#include <linux/spinlock.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include "../clk.h"
 #include "../prom.h"
 
-/* clock control register */
+/* clock control register for legacy */
 #define CGU_IFCCR      0x0018
 #define CGU_IFCCR_VR9  0x0024
-/* system clock register */
+/* system clock register for legacy */
 #define CGU_SYS                0x0010
 /* pci control register */
 #define CGU_PCICR      0x0034
 #define CGU_PCICR_VR9  0x0038
 /* ephy configuration register */
 #define CGU_EPHY       0x10
+
+/* Legacy PMU register for ar9, ase, danube */
 /* power control register */
 #define PMU_PWDCR      0x1C
 /* power status register */
 /* power status register */
 #define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
 
+
+/* PMU register for ar10 and grx390 */
+
+/* First register set */
+#define PMU_CLK_SR     0x20 /* status */
+#define PMU_CLK_CR_A   0x24 /* Enable */
+#define PMU_CLK_CR_B   0x28 /* Disable */
+/* Second register set */
+#define PMU_CLK_SR1    0x30 /* status */
+#define PMU_CLK_CR1_A  0x34 /* Enable */
+#define PMU_CLK_CR1_B  0x38 /* Disable */
+/* Third register set */
+#define PMU_ANA_SR     0x40 /* status */
+#define PMU_ANA_CR_A   0x44 /* Enable */
+#define PMU_ANA_CR_B   0x48 /* Disable */
+
+/* Status */
+static u32 pmu_clk_sr[] = {
+       PMU_CLK_SR,
+       PMU_CLK_SR1,
+       PMU_ANA_SR,
+};
+
+/* Enable */
+static u32 pmu_clk_cr_a[] = {
+       PMU_CLK_CR_A,
+       PMU_CLK_CR1_A,
+       PMU_ANA_CR_A,
+};
+
+/* Disable */
+static u32 pmu_clk_cr_b[] = {
+       PMU_CLK_CR_B,
+       PMU_CLK_CR1_B,
+       PMU_ANA_CR_B,
+};
+
+#define PWDCR_EN_XRX(x)                (pmu_clk_cr_a[(x)])
+#define PWDCR_DIS_XRX(x)       (pmu_clk_cr_b[(x)])
+#define PWDSR_XRX(x)           (pmu_clk_sr[(x)])
+
 /* clock gates that we can en/disable */
 #define PMU_USB0_P     BIT(0)
+#define PMU_ASE_SDIO   BIT(2) /* ASE special */
 #define PMU_PCI                BIT(4)
 #define PMU_DMA                BIT(5)
 #define PMU_USB0       BIT(6)
 #define PMU_ASC0       BIT(7)
 #define PMU_EPHY       BIT(7)  /* ase */
+#define PMU_USIF       BIT(7) /* from vr9 until grx390 */
 #define PMU_SPI                BIT(8)
 #define PMU_DFE                BIT(9)
 #define PMU_EBU                BIT(10)
 #define PMU_AHBS       BIT(13) /* vr9 */
 #define PMU_FPI                BIT(14)
 #define PMU_AHBM       BIT(15)
+#define PMU_SDIO       BIT(16) /* danube, ar9, vr9 */
 #define PMU_ASC1       BIT(17)
 #define PMU_PPE_QSB    BIT(18)
 #define PMU_PPE_SLL01  BIT(19)
+#define PMU_DEU                BIT(20)
 #define PMU_PPE_TC     BIT(21)
 #define PMU_PPE_EMA    BIT(22)
 #define PMU_PPE_DPLUM  BIT(23)
+#define PMU_PPE_DP     BIT(23)
 #define PMU_PPE_DPLUS  BIT(24)
 #define PMU_USB1_P     BIT(26)
 #define PMU_USB1       BIT(27)
 #define PMU_GPHY       BIT(30)
 #define PMU_PCIE_CLK   BIT(31)
 
-#define PMU1_PCIE_PHY  BIT(0)
+#define PMU1_PCIE_PHY  BIT(0)  /* vr9-specific,moved in ar10/grx390 */
 #define PMU1_PCIE_CTL  BIT(1)
 #define PMU1_PCIE_PDI  BIT(4)
 #define PMU1_PCIE_MSI  BIT(5)
+#define PMU1_CKE       BIT(6)
+#define PMU1_PCIE1_CTL BIT(17)
+#define PMU1_PCIE1_PDI BIT(20)
+#define PMU1_PCIE1_MSI BIT(21)
+#define PMU1_PCIE2_CTL BIT(25)
+#define PMU1_PCIE2_PDI BIT(26)
+#define PMU1_PCIE2_MSI BIT(27)
+
+#define PMU_ANALOG_USB0_P      BIT(0)
+#define PMU_ANALOG_USB1_P      BIT(1)
+#define PMU_ANALOG_PCIE0_P     BIT(8)
+#define PMU_ANALOG_PCIE1_P     BIT(9)
+#define PMU_ANALOG_PCIE2_P     BIT(10)
+#define PMU_ANALOG_DSL_AFE     BIT(16)
+#define PMU_ANALOG_DCDC_2V5    BIT(17)
+#define PMU_ANALOG_DCDC_1VX    BIT(18)
+#define PMU_ANALOG_DCDC_1V0    BIT(19)
 
 #define pmu_w32(x, y)  ltq_w32((x), pmu_membase + (y))
 #define pmu_r32(x)     ltq_r32(pmu_membase + (x))
@@ -85,15 +152,19 @@ void __iomem *ltq_ebu_membase;
 static u32 ifccr = CGU_IFCCR;
 static u32 pcicr = CGU_PCICR;
 
+static DEFINE_SPINLOCK(g_pmu_lock);
+
 /* legacy function kept alive to ease clkdev transition */
 void ltq_pmu_enable(unsigned int module)
 {
-       int err = 1000000;
+       int retry = 1000000;
 
+       spin_lock(&g_pmu_lock);
        pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR);
-       do {} while (--err && (pmu_r32(PMU_PWDSR) & module));
+       do {} while (--retry && (pmu_r32(PMU_PWDSR) & module));
+       spin_unlock(&g_pmu_lock);
 
-       if (!err)
+       if (!retry)
                panic("activating PMU module failed!");
 }
 EXPORT_SYMBOL(ltq_pmu_enable);
@@ -101,7 +172,15 @@ EXPORT_SYMBOL(ltq_pmu_enable);
 /* legacy function kept alive to ease clkdev transition */
 void ltq_pmu_disable(unsigned int module)
 {
+       int retry = 1000000;
+
+       spin_lock(&g_pmu_lock);
        pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR);
+       do {} while (--retry && (!(pmu_r32(PMU_PWDSR) & module)));
+       spin_unlock(&g_pmu_lock);
+
+       if (!retry)
+               pr_warn("deactivating PMU module failed!");
 }
 EXPORT_SYMBOL(ltq_pmu_disable);
 
@@ -123,9 +202,20 @@ static int pmu_enable(struct clk *clk)
 {
        int retry = 1000000;
 
-       pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits,
-               PWDCR(clk->module));
-       do {} while (--retry && (pmu_r32(PWDSR(clk->module)) & clk->bits));
+       if (of_machine_is_compatible("lantiq,ar10")
+           || of_machine_is_compatible("lantiq,grx390")) {
+               pmu_w32(clk->bits, PWDCR_EN_XRX(clk->module));
+               do {} while (--retry &&
+                            (!(pmu_r32(PWDSR_XRX(clk->module)) & clk->bits)));
+
+       } else {
+               spin_lock(&g_pmu_lock);
+               pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits,
+                               PWDCR(clk->module));
+               do {} while (--retry &&
+                            (pmu_r32(PWDSR(clk->module)) & clk->bits));
+               spin_unlock(&g_pmu_lock);
+       }
 
        if (!retry)
                panic("activating PMU module failed!");
@@ -136,8 +226,24 @@ static int pmu_enable(struct clk *clk)
 /* disable a clock gate */
 static void pmu_disable(struct clk *clk)
 {
-       pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits,
-               PWDCR(clk->module));
+       int retry = 1000000;
+
+       if (of_machine_is_compatible("lantiq,ar10")
+           || of_machine_is_compatible("lantiq,grx390")) {
+               pmu_w32(clk->bits, PWDCR_DIS_XRX(clk->module));
+               do {} while (--retry &&
+                            (pmu_r32(PWDSR_XRX(clk->module)) & clk->bits));
+       } else {
+               spin_lock(&g_pmu_lock);
+               pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits,
+                               PWDCR(clk->module));
+               do {} while (--retry &&
+                            (!(pmu_r32(PWDSR(clk->module)) & clk->bits)));
+               spin_unlock(&g_pmu_lock);
+       }
+
+       if (!retry)
+               pr_warn("deactivating PMU module failed!");
 }
 
 /* the pci enable helper */
@@ -202,8 +308,8 @@ static int clkout_enable(struct clk *clk)
 }
 
 /* manage the clock gates via PMU */
-static void clkdev_add_pmu(const char *dev, const char *con,
-                                       unsigned int module, unsigned int bits)
+static void clkdev_add_pmu(const char *dev, const char *con, bool deactivate,
+                          unsigned int module, unsigned int bits)
 {
        struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
 
@@ -214,6 +320,13 @@ static void clkdev_add_pmu(const char *dev, const char *con,
        clk->disable = pmu_disable;
        clk->module = module;
        clk->bits = bits;
+       if (deactivate) {
+               /*
+                * Disable it during the initialization. Module should enable
+                * when used
+                */
+               pmu_disable(clk);
+       }
        clkdev_add(&clk->cl);
 }
 
@@ -312,12 +425,12 @@ void __init ltq_soc_init(void)
                        of_address_to_resource(np_ebu, 0, &res_ebu))
                panic("Failed to get core resources");
 
-       if ((request_mem_region(res_pmu.start, resource_size(&res_pmu),
-                               res_pmu.name) < 0) ||
-               (request_mem_region(res_cgu.start, resource_size(&res_cgu),
-                               res_cgu.name) < 0) ||
-               (request_mem_region(res_ebu.start, resource_size(&res_ebu),
-                               res_ebu.name) < 0))
+       if (!request_mem_region(res_pmu.start, resource_size(&res_pmu),
+                               res_pmu.name) ||
+               !request_mem_region(res_cgu.start, resource_size(&res_cgu),
+                               res_cgu.name) ||
+               !request_mem_region(res_ebu.start, resource_size(&res_ebu),
+                               res_ebu.name))
                pr_err("Failed to request core resources");
 
        pmu_membase = ioremap_nocache(res_pmu.start, resource_size(&res_pmu));
@@ -332,13 +445,13 @@ void __init ltq_soc_init(void)
        ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
 
        /* add our generic xway clocks */
-       clkdev_add_pmu("10000000.fpi", NULL, 0, PMU_FPI);
-       clkdev_add_pmu("1e100400.serial", NULL, 0, PMU_ASC0);
-       clkdev_add_pmu("1e100a00.gptu", NULL, 0, PMU_GPT);
-       clkdev_add_pmu("1e100bb0.stp", NULL, 0, PMU_STP);
-       clkdev_add_pmu("1e104100.dma", NULL, 0, PMU_DMA);
-       clkdev_add_pmu("1e100800.spi", NULL, 0, PMU_SPI);
-       clkdev_add_pmu("1e105300.ebu", NULL, 0, PMU_EBU);
+       clkdev_add_pmu("10000000.fpi", NULL, 0, 0, PMU_FPI);
+       clkdev_add_pmu("1e100400.serial", NULL, 0, 0, PMU_ASC0);
+       clkdev_add_pmu("1e100a00.gptu", NULL, 1, 0, PMU_GPT);
+       clkdev_add_pmu("1e100bb0.stp", NULL, 1, 0, PMU_STP);
+       clkdev_add_pmu("1e104100.dma", NULL, 1, 0, PMU_DMA);
+       clkdev_add_pmu("1e100800.spi", NULL, 1, 0, PMU_SPI);
+       clkdev_add_pmu("1e105300.ebu", NULL, 0, 0, PMU_EBU);
        clkdev_add_clkout();
 
        /* add the soc dependent clocks */
@@ -346,14 +459,30 @@ void __init ltq_soc_init(void)
                ifccr = CGU_IFCCR_VR9;
                pcicr = CGU_PCICR_VR9;
        } else {
-               clkdev_add_pmu("1e180000.etop", NULL, 0, PMU_PPE);
+               clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE);
        }
 
        if (!of_machine_is_compatible("lantiq,ase")) {
-               clkdev_add_pmu("1e100c00.serial", NULL, 0, PMU_ASC1);
+               clkdev_add_pmu("1e100c00.serial", NULL, 0, 0, PMU_ASC1);
                clkdev_add_pci();
        }
 
+       if (of_machine_is_compatible("lantiq,grx390") ||
+           of_machine_is_compatible("lantiq,ar10")) {
+               clkdev_add_pmu("1e101000.usb", "phy", 1, 2, PMU_ANALOG_USB0_P);
+               clkdev_add_pmu("1e106000.usb", "phy", 1, 2, PMU_ANALOG_USB1_P);
+               /* rc 0 */
+               clkdev_add_pmu("1d900000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE0_P);
+               clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI);
+               clkdev_add_pmu("1d900000.pcie", "pdi", 1, 1, PMU1_PCIE_PDI);
+               clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL);
+               /* rc 1 */
+               clkdev_add_pmu("19000000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE1_P);
+               clkdev_add_pmu("19000000.pcie", "msi", 1, 1, PMU1_PCIE1_MSI);
+               clkdev_add_pmu("19000000.pcie", "pdi", 1, 1, PMU1_PCIE1_PDI);
+               clkdev_add_pmu("19000000.pcie", "ctl", 1, 1, PMU1_PCIE1_CTL);
+       }
+
        if (of_machine_is_compatible("lantiq,ase")) {
                if (ltq_cgu_r32(CGU_SYS) & (1 << 5))
                        clkdev_add_static(CLOCK_266M, CLOCK_133M,
@@ -361,28 +490,81 @@ void __init ltq_soc_init(void)
                else
                        clkdev_add_static(CLOCK_133M, CLOCK_133M,
                                                CLOCK_133M, CLOCK_133M);
-               clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY),
-               clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY);
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+               clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE);
+               clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY);
+               clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY);
+               clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO);
+               clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+       } else if (of_machine_is_compatible("lantiq,grx390")) {
+               clkdev_add_static(ltq_grx390_cpu_hz(), ltq_grx390_fpi_hz(),
+                                 ltq_grx390_fpi_hz(), ltq_grx390_pp32_hz());
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+               /* rc 2 */
+               clkdev_add_pmu("1a800000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE2_P);
+               clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
+               clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
+               clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
+               clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
+               clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+               clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+       } else if (of_machine_is_compatible("lantiq,ar10")) {
+               clkdev_add_static(ltq_ar10_cpu_hz(), ltq_ar10_fpi_hz(),
+                                 ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+               clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
+                              PMU_PPE_DP | PMU_PPE_TC);
+               clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+               clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+               clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+               clkdev_add_pmu("1e116000.mei", "afe", 1, 2, PMU_ANALOG_DSL_AFE);
+               clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
        } else if (of_machine_is_compatible("lantiq,vr9")) {
                clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(),
                                ltq_vr9_fpi_hz(), ltq_vr9_pp32_hz());
-               clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY);
-               clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK);
-               clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI);
-               clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI);
-               clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL);
-               clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
-               clkdev_add_pmu("1e108000.eth", NULL, 0,
+               clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0 | PMU_AHBM);
+               clkdev_add_pmu("1e106000.usb", "phy", 1, 0, PMU_USB1_P);
+               clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1 | PMU_AHBM);
+               clkdev_add_pmu("1d900000.pcie", "phy", 1, 1, PMU1_PCIE_PHY);
+               clkdev_add_pmu("1d900000.pcie", "bus", 1, 0, PMU_PCIE_CLK);
+               clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI);
+               clkdev_add_pmu("1d900000.pcie", "pdi", 1, 1, PMU1_PCIE_PDI);
+               clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL);
+               clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
+
+               clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+               clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
                                PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
                                PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
                                PMU_PPE_QSB | PMU_PPE_TOP);
-               clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY);
+               clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+               clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+               clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+               clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
        } else if (of_machine_is_compatible("lantiq,ar9")) {
                clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
                                ltq_ar9_fpi_hz(), CLOCK_250M);
-               clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH);
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+               clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+               clkdev_add_pmu("1e106000.usb", "phy", 1, 0, PMU_USB1_P);
+               clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH);
+               clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+               clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+               clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+               clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0);
        } else {
                clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
                                ltq_danube_fpi_hz(), ltq_danube_pp32_hz());
+               clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+               clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+               clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+               clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+               clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0);
        }
 }
index 1e9e900..0344e57 100644 (file)
@@ -15,4 +15,4 @@ obj-$(CONFIG_CPU_R3000)               += r3k_dump_tlb.o
 obj-$(CONFIG_CPU_TX39XX)       += r3k_dump_tlb.o
 
 # libgcc-style stuff needed in the kernel
-obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
+obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o ucmpdi2.o
diff --git a/arch/mips/lib/bswapdi.c b/arch/mips/lib/bswapdi.c
new file mode 100644 (file)
index 0000000..77e5f9c
--- /dev/null
@@ -0,0 +1,15 @@
+#include <linux/module.h>
+
+unsigned long long __bswapdi2(unsigned long long u)
+{
+       return (((u) & 0xff00000000000000ull) >> 56) |
+              (((u) & 0x00ff000000000000ull) >> 40) |
+              (((u) & 0x0000ff0000000000ull) >> 24) |
+              (((u) & 0x000000ff00000000ull) >>  8) |
+              (((u) & 0x00000000ff000000ull) <<  8) |
+              (((u) & 0x0000000000ff0000ull) << 24) |
+              (((u) & 0x000000000000ff00ull) << 40) |
+              (((u) & 0x00000000000000ffull) << 56);
+}
+
+EXPORT_SYMBOL(__bswapdi2);
diff --git a/arch/mips/lib/bswapsi.c b/arch/mips/lib/bswapsi.c
new file mode 100644 (file)
index 0000000..2b302ff
--- /dev/null
@@ -0,0 +1,11 @@
+#include <linux/module.h>
+
+unsigned int __bswapsi2(unsigned int u)
+{
+       return (((u) & 0xff000000) >> 24) |
+              (((u) & 0x00ff0000) >>  8) |
+              (((u) & 0x0000ff00) <<  8) |
+              (((u) & 0x000000ff) << 24);
+}
+
+EXPORT_SYMBOL(__bswapsi2);
index 506a67a..be650ed 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
+#include <asm/debug.h>
 #include <asm/fpu_emulator.h>
 #include <asm/local.h>
 
@@ -27,7 +28,6 @@ static int fpuemu_stat_get(void *data, u64 *val)
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
 
-extern struct dentry *mips_debugfs_dir;
 static int __init debugfs_fpuemu(void)
 {
        struct dentry *d, *dir;
index 67ede4e..b4c64bd 100644 (file)
@@ -28,3 +28,4 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
 obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
 obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
 obj-$(CONFIG_MIPS_CPU_SCACHE)  += sc-mips.o
+obj-$(CONFIG_SCACHE_DEBUGFS)   += sc-debugfs.o
diff --git a/arch/mips/mm/sc-debugfs.c b/arch/mips/mm/sc-debugfs.c
new file mode 100644 (file)
index 0000000..5eefe32
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/bcache.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+
+static ssize_t sc_prefetch_read(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       bool enabled = bc_prefetch_is_enabled();
+       char buf[3];
+
+       buf[0] = enabled ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = 0;
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t sc_prefetch_write(struct file *file,
+                                const char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       char buf[32];
+       ssize_t buf_size;
+       bool enabled;
+       int err;
+
+       buf_size = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       err = strtobool(buf, &enabled);
+       if (err)
+               return err;
+
+       if (enabled)
+               bc_prefetch_enable();
+       else
+               bc_prefetch_disable();
+
+       return count;
+}
+
+static const struct file_operations sc_prefetch_fops = {
+       .open = simple_open,
+       .llseek = default_llseek,
+       .read = sc_prefetch_read,
+       .write = sc_prefetch_write,
+};
+
+static int __init sc_debugfs_init(void)
+{
+       struct dentry *dir, *file;
+
+       if (!mips_debugfs_dir)
+               return -ENODEV;
+
+       dir = debugfs_create_dir("l2cache", mips_debugfs_dir);
+       if (IS_ERR(dir))
+               return PTR_ERR(dir);
+
+       file = debugfs_create_file("prefetch", S_IRUGO | S_IWUSR, dir,
+                                  NULL, &sc_prefetch_fops);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       return 0;
+}
+late_initcall(sc_debugfs_init);
index 53ea839..3bd0597 100644 (file)
@@ -51,11 +51,69 @@ static void mips_sc_disable(void)
        /* L2 cache is permanently enabled */
 }
 
+static void mips_sc_prefetch_enable(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return;
+
+       /*
+        * If there is one or more L2 prefetch unit present then enable
+        * prefetching for both code & data, for all ports.
+        */
+       pftctl = read_gcr_l2_pft_control();
+       if (pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK) {
+               pftctl &= ~CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+               pftctl |= PAGE_MASK & CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+               pftctl |= CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+               write_gcr_l2_pft_control(pftctl);
+
+               pftctl = read_gcr_l2_pft_control_b();
+               pftctl |= CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+               pftctl |= CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+               write_gcr_l2_pft_control_b(pftctl);
+       }
+}
+
+static void mips_sc_prefetch_disable(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return;
+
+       pftctl = read_gcr_l2_pft_control();
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+       write_gcr_l2_pft_control(pftctl);
+
+       pftctl = read_gcr_l2_pft_control_b();
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+       pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+       write_gcr_l2_pft_control_b(pftctl);
+}
+
+static bool mips_sc_prefetch_is_enabled(void)
+{
+       unsigned long pftctl;
+
+       if (mips_cm_revision() < CM_REV_CM2_5)
+               return false;
+
+       pftctl = read_gcr_l2_pft_control();
+       if (!(pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK))
+               return false;
+       return !!(pftctl & CM_GCR_L2_PFT_CONTROL_PFTEN_MSK);
+}
+
 static struct bcache_ops mips_sc_ops = {
        .bc_enable = mips_sc_enable,
        .bc_disable = mips_sc_disable,
        .bc_wback_inv = mips_sc_wback_inv,
-       .bc_inv = mips_sc_inv
+       .bc_inv = mips_sc_inv,
+       .bc_prefetch_enable = mips_sc_prefetch_enable,
+       .bc_prefetch_disable = mips_sc_prefetch_disable,
+       .bc_prefetch_is_enabled = mips_sc_prefetch_is_enabled,
 };
 
 /*
@@ -162,13 +220,13 @@ static inline int __init mips_sc_probe(void)
                return 0;
 
        tmp = (config2 >> 8) & 0x0f;
-       if (0 <= tmp && tmp <= 7)
+       if (tmp <= 7)
                c->scache.sets = 64 << tmp;
        else
                return 0;
 
        tmp = (config2 >> 0) & 0x0f;
-       if (0 <= tmp && tmp <= 7)
+       if (tmp <= 7)
                c->scache.ways = tmp + 1;
        else
                return 0;
@@ -186,6 +244,7 @@ int mips_sc_init(void)
        int found = mips_sc_probe();
        if (found) {
                mips_sc_enable();
+               mips_sc_prefetch_enable();
                bcops = &mips_sc_ops;
        }
        return found;
index 323d1d3..32e0be2 100644 (file)
@@ -311,6 +311,7 @@ static struct uasm_label labels[128];
 static struct uasm_reloc relocs[128];
 
 static int check_for_high_segbits;
+static bool fill_includes_sw_bits;
 
 static unsigned int kscratch_used_mask;
 
@@ -630,8 +631,14 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
 static __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
                                                        unsigned int reg)
 {
-       if (cpu_has_rixi) {
-               UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+       if (cpu_has_rixi && _PAGE_NO_EXEC) {
+               if (fill_includes_sw_bits) {
+                       UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+               } else {
+                       UASM_i_SRL(p, reg, reg, ilog2(_PAGE_NO_EXEC));
+                       UASM_i_ROTR(p, reg, reg,
+                                   ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+               }
        } else {
 #ifdef CONFIG_PHYS_ADDR_T_64BIT
                uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL));
@@ -1005,21 +1012,7 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
         * 64bit address support (36bit on a 32bit CPU) in a 32bit
         * Kernel is a special case. Only a few CPUs use it.
         */
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
-       if (cpu_has_64bits) {
-               uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
-               uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
-               if (cpu_has_rixi) {
-                       UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
-                       UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-                       UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
-               } else {
-                       uasm_i_dsrl_safe(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
-                       UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-                       uasm_i_dsrl_safe(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */
-               }
-               UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
-       } else {
+       if (config_enabled(CONFIG_PHYS_ADDR_T_64BIT) && !cpu_has_64bits) {
                int pte_off_even = sizeof(pte_t) / 2;
                int pte_off_odd = pte_off_even + sizeof(pte_t);
 #ifdef CONFIG_XPA
@@ -1043,31 +1036,23 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
                uasm_i_mthc0(p, tmp, C0_ENTRYLO0);
                uasm_i_mthc0(p, ptep, C0_ENTRYLO1);
 #endif
+               return;
        }
-#else
+
        UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
        UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
        if (r45k_bvahwbug())
                build_tlb_probe_entry(p);
-       if (cpu_has_rixi) {
-               UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
-               if (r4k_250MHZhwbug())
-                       UASM_i_MTC0(p, 0, C0_ENTRYLO0);
-               UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-               UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
-       } else {
-               UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
-               if (r4k_250MHZhwbug())
-                       UASM_i_MTC0(p, 0, C0_ENTRYLO0);
-               UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
-               UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */
-               if (r45k_bvahwbug())
-                       uasm_i_mfc0(p, tmp, C0_INDEX);
-       }
+       build_convert_pte_to_entrylo(p, tmp);
+       if (r4k_250MHZhwbug())
+               UASM_i_MTC0(p, 0, C0_ENTRYLO0);
+       UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
+       build_convert_pte_to_entrylo(p, ptep);
+       if (r45k_bvahwbug())
+               uasm_i_mfc0(p, tmp, C0_INDEX);
        if (r4k_250MHZhwbug())
                UASM_i_MTC0(p, 0, C0_ENTRYLO1);
        UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
-#endif
 }
 
 struct mips_huge_tlb_info {
@@ -2299,6 +2284,10 @@ static void config_htw_params(void)
        /* re-initialize the PTI field including the even/odd bit */
        pwfield &= ~MIPS_PWFIELD_PTI_MASK;
        pwfield |= PAGE_SHIFT << MIPS_PWFIELD_PTI_SHIFT;
+       if (CONFIG_PGTABLE_LEVELS >= 3) {
+               pwfield &= ~MIPS_PWFIELD_MDI_MASK;
+               pwfield |= PMD_SHIFT << MIPS_PWFIELD_MDI_SHIFT;
+       }
        /* Set the PTEI right shift */
        ptei = _PAGE_GLOBAL_SHIFT << MIPS_PWFIELD_PTEI_SHIFT;
        pwfield |= ptei;
@@ -2320,9 +2309,11 @@ static void config_htw_params(void)
 
        pwsize = ilog2(PTRS_PER_PGD) << MIPS_PWSIZE_GDW_SHIFT;
        pwsize |= ilog2(PTRS_PER_PTE) << MIPS_PWSIZE_PTW_SHIFT;
+       if (CONFIG_PGTABLE_LEVELS >= 3)
+               pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT;
 
        /* If XPA has been enabled, PTEs are 64-bit in size. */
-       if (read_c0_pagegrain() & PG_ELPA)
+       if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA))
                pwsize |= 1;
 
        write_c0_pwsize(pwsize);
@@ -2360,6 +2351,41 @@ static void config_xpa_params(void)
 #endif
 }
 
+static void check_pabits(void)
+{
+       unsigned long entry;
+       unsigned pabits, fillbits;
+
+       if (!cpu_has_rixi || !_PAGE_NO_EXEC) {
+               /*
+                * We'll only be making use of the fact that we can rotate bits
+                * into the fill if the CPU supports RIXI, so don't bother
+                * probing this for CPUs which don't.
+                */
+               return;
+       }
+
+       write_c0_entrylo0(~0ul);
+       back_to_back_c0_hazard();
+       entry = read_c0_entrylo0();
+
+       /* clear all non-PFN bits */
+       entry &= ~((1 << MIPS_ENTRYLO_PFN_SHIFT) - 1);
+       entry &= ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
+
+       /* find a lower bound on PABITS, and upper bound on fill bits */
+       pabits = fls_long(entry) + 6;
+       fillbits = max_t(int, (int)BITS_PER_LONG - pabits, 0);
+
+       /* minus the RI & XI bits */
+       fillbits -= min_t(unsigned, fillbits, 2);
+
+       if (fillbits >= ilog2(_PAGE_NO_EXEC))
+               fill_includes_sw_bits = true;
+
+       pr_debug("Entry* registers contain %u fill bits\n", fillbits);
+}
+
 void build_tlb_refill_handler(void)
 {
        /*
@@ -2370,6 +2396,7 @@ void build_tlb_refill_handler(void)
        static int run_once = 0;
 
        output_pgtable_bits_defines();
+       check_pabits();
 
 #ifdef CONFIG_64BIT
        check_for_high_segbits = current_cpu_data.vmbits > (PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
index ea35587..5827af7 100644 (file)
@@ -5,9 +5,18 @@
 # Copyright (C) 2008 Wind River Systems, Inc.
 #   written by Ralf Baechle <ralf@linux-mips.org>
 #
-obj-y                          := malta-display.o malta-dt.o malta-init.o \
-                                  malta-int.o malta-memory.o malta-platform.o \
-                                  malta-reset.o malta-setup.o malta-time.o
+obj-y                          += malta-display.o
+obj-y                          += malta-dt.o
+obj-y                          += malta-dtshim.o
+obj-y                          += malta-init.o
+obj-y                          += malta-int.o
+obj-y                          += malta-memory.o
+obj-y                          += malta-platform.o
+obj-y                          += malta-reset.o
+obj-y                          += malta-setup.o
+obj-y                          += malta-time.o
 
 obj-$(CONFIG_MIPS_CMP)         += malta-amon.o
 obj-$(CONFIG_MIPS_MALTA_PM)    += malta-pm.o
+
+CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt
diff --git a/arch/mips/mti-malta/malta-dtshim.c b/arch/mips/mti-malta/malta-dtshim.c
new file mode 100644 (file)
index 0000000..f7133ef
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/sizes.h>
+#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
+#include <asm/page.h>
+
+static unsigned char fdt_buf[16 << 10] __initdata;
+
+/* determined physical memory size, not overridden by command line args         */
+extern unsigned long physical_memsize;
+
+#define MAX_MEM_ARRAY_ENTRIES 1
+
+static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size)
+{
+       unsigned long size_preio;
+       unsigned entries;
+
+       entries = 1;
+       mem_array[0] = cpu_to_be32(PHYS_OFFSET);
+       if (config_enabled(CONFIG_EVA)) {
+               /*
+                * The current Malta EVA configuration is "special" in that it
+                * always makes use of addresses in the upper half of the 32 bit
+                * physical address map, which gives it a contiguous region of
+                * DDR but limits it to 2GB.
+                */
+               mem_array[1] = cpu_to_be32(size);
+       } else {
+               size_preio = min_t(unsigned long, size, SZ_256M);
+               mem_array[1] = cpu_to_be32(size_preio);
+       }
+
+       BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
+       return entries;
+}
+
+static void __init append_memory(void *fdt, int root_off)
+{
+       __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
+       unsigned long memsize;
+       unsigned mem_entries;
+       int i, err, mem_off;
+       char *var, param_name[10], *var_names[] = {
+               "ememsize", "memsize",
+       };
+
+       /* if a memory node already exists, leave it alone */
+       mem_off = fdt_path_offset(fdt, "/memory");
+       if (mem_off >= 0)
+               return;
+
+       /* find memory size from the bootloader environment */
+       for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+               var = fw_getenv(var_names[i]);
+               if (!var)
+                       continue;
+
+               err = kstrtoul(var, 0, &physical_memsize);
+               if (!err)
+                       break;
+
+               pr_warn("Failed to read the '%s' env variable '%s'\n",
+                       var_names[i], var);
+       }
+
+       if (!physical_memsize) {
+               pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
+               physical_memsize = 32 << 20;
+       }
+
+       if (config_enabled(CONFIG_CPU_BIG_ENDIAN)) {
+               /*
+                * SOC-it swaps, or perhaps doesn't swap, when DMA'ing
+                * the last word of physical memory.
+                */
+               physical_memsize -= PAGE_SIZE;
+       }
+
+       /* default to using all available RAM */
+       memsize = physical_memsize;
+
+       /* allow the user to override the usable memory */
+       for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+               snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
+               var = strstr(arcs_cmdline, param_name);
+               if (!var)
+                       continue;
+
+               memsize = memparse(var + strlen(param_name), NULL);
+       }
+
+       /* if the user says there's more RAM than we thought, believe them */
+       physical_memsize = max_t(unsigned long, physical_memsize, memsize);
+
+       /* append memory to the DT */
+       mem_off = fdt_add_subnode(fdt, root_off, "memory");
+       if (mem_off < 0)
+               panic("Unable to add memory node to DT: %d", mem_off);
+
+       err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
+       if (err)
+               panic("Unable to set memory node device_type: %d", err);
+
+       mem_entries = gen_fdt_mem_array(mem_array, physical_memsize);
+       err = fdt_setprop(fdt, mem_off, "reg", mem_array,
+                         mem_entries * 2 * sizeof(mem_array[0]));
+       if (err)
+               panic("Unable to set memory regs property: %d", err);
+
+       mem_entries = gen_fdt_mem_array(mem_array, memsize);
+       err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array,
+                         mem_entries * 2 * sizeof(mem_array[0]));
+       if (err)
+               panic("Unable to set linux,usable-memory property: %d", err);
+}
+
+void __init *malta_dt_shim(void *fdt)
+{
+       int root_off, len, err;
+       const char *compat;
+
+       if (fdt_check_header(fdt))
+               panic("Corrupt DT");
+
+       err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
+       if (err)
+               panic("Unable to open FDT: %d", err);
+
+       root_off = fdt_path_offset(fdt_buf, "/");
+       if (root_off < 0)
+               panic("No / node in DT");
+
+       compat = fdt_getprop(fdt_buf, root_off, "compatible", &len);
+       if (!compat)
+               panic("No root compatible property in DT: %d", len);
+
+       /* if this isn't Malta, leave the DT alone */
+       if (strncmp(compat, "mti,malta", len))
+               return fdt;
+
+       append_memory(fdt_buf, root_off);
+
+       err = fdt_pack(fdt_buf);
+       if (err)
+               panic("Unable to pack FDT: %d\n", err);
+
+       return fdt_buf;
+}
index 53c2478..571148c 100644 (file)
@@ -302,6 +302,7 @@ mips_pci_controller:
                return;
        if (!register_vsmp_smp_ops())
                return;
+       register_up_smp_ops();
 }
 
 void platform_early_l2_init(void)
index dadeb83..d5f8dae 100644 (file)
 #include <asm/sections.h>
 #include <asm/fw/fw.h>
 
-static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
-
 /* determined physical memory size, not overridden by command line args         */
 unsigned long physical_memsize = 0L;
 
-fw_memblock_t * __init fw_getmdesc(int eva)
-{
-       char *memsize_str, *ememsize_str = NULL, *ptr;
-       unsigned long memsize = 0, ememsize = 0;
-       static char cmdline[COMMAND_LINE_SIZE] __initdata;
-       int tmp;
-
-       /* otherwise look in the environment */
-
-       memsize_str = fw_getenv("memsize");
-       if (memsize_str) {
-               tmp = kstrtoul(memsize_str, 0, &memsize);
-               if (tmp)
-                       pr_warn("Failed to read the 'memsize' env variable.\n");
-       }
-       if (eva) {
-       /* Look for ememsize for EVA */
-               ememsize_str = fw_getenv("ememsize");
-               if (ememsize_str) {
-                       tmp = kstrtoul(ememsize_str, 0, &ememsize);
-                       if (tmp)
-                               pr_warn("Failed to read the 'ememsize' env variable.\n");
-               }
-       }
-       if (!memsize && !ememsize) {
-               pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
-               physical_memsize = 0x02000000;
-       } else {
-               if (memsize > (256 << 20)) { /* memsize should be capped to 256M */
-                       pr_warn("Unsupported memsize value (0x%lx) detected! "
-                               "Using 0x10000000 (256M) instead\n",
-                               memsize);
-                       memsize = 256 << 20;
-               }
-               /* If ememsize is set, then set physical_memsize to that */
-               physical_memsize = ememsize ? : memsize;
-       }
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
-       /* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last
-          word of physical memory */
-       physical_memsize -= PAGE_SIZE;
-#endif
-
-       /* Check the command line for a memsize directive that overrides
-          the physical/default amount */
-       strcpy(cmdline, arcs_cmdline);
-       ptr = strstr(cmdline, "memsize=");
-       if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
-               ptr = strstr(ptr, " memsize=");
-       /* And now look for ememsize */
-       if (eva) {
-               ptr = strstr(cmdline, "ememsize=");
-               if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
-                       ptr = strstr(ptr, " ememsize=");
-       }
-
-       if (ptr)
-               memsize = memparse(ptr + 8 + (eva ? 1 : 0), &ptr);
-       else
-               memsize = physical_memsize;
-
-       /* Last 64K for HIGHMEM arithmetics */
-       if (memsize > 0x7fff0000)
-               memsize = 0x7fff0000;
-
-       memset(mdesc, 0, sizeof(mdesc));
-
-       mdesc[0].type = fw_dontuse;
-       mdesc[0].base = PHYS_OFFSET;
-       mdesc[0].size = 0x00001000;
-
-       mdesc[1].type = fw_code;
-       mdesc[1].base = mdesc[0].base + 0x00001000UL;
-       mdesc[1].size = 0x000ef000;
-
-       /*
-        * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
-        * south bridge and PCI access always forwarded to the ISA Bus and
-        * BIOSCS# is always generated.
-        * This mean that this area can't be used as DMA memory for PCI
-        * devices.
-        */
-       mdesc[2].type = fw_dontuse;
-       mdesc[2].base = mdesc[0].base + 0x000f0000UL;
-       mdesc[2].size = 0x00010000;
-
-       mdesc[3].type = fw_dontuse;
-       mdesc[3].base = mdesc[0].base + 0x00100000UL;
-       mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
-               0x00100000UL;
-
-       mdesc[4].type = fw_free;
-       mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
-       mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base);
-
-       return &mdesc[0];
-}
-
 static void free_init_pages_eva_malta(void *begin, void *end)
 {
        free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
                        __pa_symbol((unsigned long *)end));
 }
 
-static int __init fw_memtype_classify(unsigned int type)
-{
-       switch (type) {
-       case fw_free:
-               return BOOT_MEM_RAM;
-       case fw_code:
-               return BOOT_MEM_ROM_DATA;
-       default:
-               return BOOT_MEM_RESERVED;
-       }
-}
-
 void __init fw_meminit(void)
 {
-       fw_memblock_t *p;
-
-       p = fw_getmdesc(config_enabled(CONFIG_EVA));
-       free_init_pages_eva = (config_enabled(CONFIG_EVA) ?
-                              free_init_pages_eva_malta : NULL);
+       bool eva = config_enabled(CONFIG_EVA);
 
-       while (p->size) {
-               long type;
-               unsigned long base, size;
-
-               type = fw_memtype_classify(p->type);
-               base = p->base;
-               size = p->size;
-
-               add_memory_region(base, size, type);
-               p++;
-       }
+       free_init_pages_eva = eva ? free_init_pages_eva_malta : NULL;
 }
 
 void __init prom_free_prom_memory(void)
index 9d1e7f5..4740c82 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/time.h>
 
 #include <asm/fw/fw.h>
+#include <asm/mach-malta/malta-dtshim.h>
 #include <asm/mips-cm.h>
 #include <asm/mips-boards/generic.h>
 #include <asm/mips-boards/malta.h>
@@ -250,8 +251,10 @@ static void __init bonito_quirks_setup(void)
 void __init plat_mem_setup(void)
 {
        unsigned int i;
+       void *fdt = __dtb_start;
 
-       __dt_setup_arch(__dtb_start);
+       fdt = malta_dt_shim(fdt);
+       __dt_setup_arch(fdt);
 
        if (config_enabled(CONFIG_EVA))
                /* EVA has already been configured in mach-malta/kernel-init.h */
index ed6732f..53a42b0 100644 (file)
@@ -432,8 +432,7 @@ static int rt3883_pci_probe(struct platform_device *pdev)
 
        /* find the interrupt controller child node */
        for_each_child_of_node(np, child) {
-               if (of_get_property(child, "interrupt-controller", NULL) &&
-                   of_node_get(child)) {
+               if (of_get_property(child, "interrupt-controller", NULL)) {
                        rpc->intc_of_node = child;
                        break;
                }
@@ -449,8 +448,7 @@ static int rt3883_pci_probe(struct platform_device *pdev)
        /* find the PCI host bridge child node */
        for_each_child_of_node(np, child) {
                if (child->type &&
-                   of_node_cmp(child->type, "pci") == 0 &&
-                   of_node_get(child)) {
+                   of_node_cmp(child->type, "pci") == 0) {
                        rpc->pci_controller.of_node = child;
                        break;
                }
diff --git a/arch/mips/vdso/.gitignore b/arch/mips/vdso/.gitignore
new file mode 100644 (file)
index 0000000..5286a7d
--- /dev/null
@@ -0,0 +1,4 @@
+*.so*
+vdso-*image.c
+genvdso
+vdso*.lds
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
new file mode 100644 (file)
index 0000000..ef5f348
--- /dev/null
@@ -0,0 +1,160 @@
+# Objects to go into the VDSO.
+obj-vdso-y := elf.o gettimeofday.o sigreturn.o
+
+# Common compiler flags between ABIs.
+ccflags-vdso := \
+       $(filter -I%,$(KBUILD_CFLAGS)) \
+       $(filter -E%,$(KBUILD_CFLAGS)) \
+       $(filter -march=%,$(KBUILD_CFLAGS))
+cflags-vdso := $(ccflags-vdso) \
+       $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
+       -O2 -g -fPIC -fno-common -fno-builtin -G 0 -DDISABLE_BRANCH_PROFILING \
+       $(call cc-option, -fno-stack-protector)
+aflags-vdso := $(ccflags-vdso) \
+       $(filter -I%,$(KBUILD_CFLAGS)) \
+       $(filter -E%,$(KBUILD_CFLAGS)) \
+       -D__ASSEMBLY__ -Wa,-gdwarf-2
+
+#
+# For the pre-R6 code in arch/mips/vdso/vdso.h for locating
+# the base address of VDSO, the linker will emit a R_MIPS_PC32
+# relocation in binutils > 2.25 but it will fail with older versions
+# because that relocation is not supported for that symbol. As a result
+# of which we are forced to disable the VDSO symbols when building
+# with < 2.25 binutils on pre-R6 kernels. For more references on why we
+# can't use other methods to get the base address of VDSO please refer to
+# the comments on that file.
+#
+ifndef CONFIG_CPU_MIPSR6
+  ifeq ($(call ld-ifversion, -gt, 22400000, y),)
+    $(warning MIPS VDSO requires binutils > 2.24)
+    obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
+    ccflags-vdso += -DDISABLE_MIPS_VDSO
+  endif
+endif
+
+# VDSO linker flags.
+VDSO_LDFLAGS := \
+       -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 \
+       -nostdlib -shared \
+       $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
+       $(call cc-ldoption, -Wl$(comma)--build-id)
+
+GCOV_PROFILE := n
+
+#
+# Shared build commands.
+#
+
+quiet_cmd_vdsold = VDSO    $@
+      cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
+                   -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+
+hostprogs-y := genvdso
+
+quiet_cmd_genvdso = GENVDSO $@
+define cmd_genvdso
+       cp $< $(<:%.dbg=%) && \
+       $(OBJCOPY) -S $< $(<:%.dbg=%) && \
+       $(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME)
+endef
+
+#
+# Build native VDSO.
+#
+
+native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS))
+
+targets += $(obj-vdso-y)
+targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c
+
+obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o)
+
+$(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
+$(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
+
+$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
+       $(call if_changed,vdsold)
+
+$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE
+       $(call if_changed,genvdso)
+
+obj-y += vdso-image.o
+
+#
+# Build O32 VDSO.
+#
+
+# Define these outside the ifdef to ensure they are picked up by clean.
+targets += $(obj-vdso-y:%.o=%-o32.o)
+targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c
+
+ifdef CONFIG_MIPS32_O32
+
+obj-vdso-o32 := $(obj-vdso-y:%.o=$(obj)/%-o32.o)
+
+$(obj-vdso-o32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=32
+$(obj-vdso-o32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=32
+
+$(obj)/%-o32.o: $(src)/%.S FORCE
+       $(call if_changed_dep,as_o_S)
+
+$(obj)/%-o32.o: $(src)/%.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+
+$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
+$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
+       $(call if_changed,vdsold)
+
+$(obj)/vdso-o32-image.c: VDSO_NAME := o32
+$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE
+       $(call if_changed,genvdso)
+
+obj-y += vdso-o32-image.o
+
+endif
+
+#
+# Build N32 VDSO.
+#
+
+targets += $(obj-vdso-y:%.o=%-n32.o)
+targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c
+
+ifdef CONFIG_MIPS32_N32
+
+obj-vdso-n32 := $(obj-vdso-y:%.o=$(obj)/%-n32.o)
+
+$(obj-vdso-n32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=n32
+$(obj-vdso-n32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=n32
+
+$(obj)/%-n32.o: $(src)/%.S FORCE
+       $(call if_changed_dep,as_o_S)
+
+$(obj)/%-n32.o: $(src)/%.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+
+$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
+$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
+       $(call if_changed,vdsold)
+
+$(obj)/vdso-n32-image.c: VDSO_NAME := n32
+$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE
+       $(call if_changed,genvdso)
+
+obj-y += vdso-n32-image.o
+
+endif
+
+# FIXME: Need install rule for debug.
+# Needs to deal with dependency for generation of dbg by cmd_genvdso...
diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S
new file mode 100644 (file)
index 0000000..be37bbb
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include "vdso.h"
+
+#include <linux/elfnote.h>
+#include <linux/version.h>
+
+ELFNOTE_START(Linux, 0, "a")
+       .long LINUX_VERSION_CODE
+ELFNOTE_END
+
+/*
+ * The .MIPS.abiflags section must be defined with the FP ABI flags set
+ * to 'any' to be able to link with both old and new libraries.
+ * Newer toolchains are capable of automatically generating this, but we want
+ * to work with older toolchains as well. Therefore, we define the contents of
+ * this section here (under different names), and then genvdso will patch
+ * it to have the correct name and type.
+ *
+ * We base the .MIPS.abiflags section on preprocessor definitions rather than
+ * CONFIG_* because we need to match the particular ABI we are building the
+ * VDSO for.
+ *
+ * See https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
+ * for the .MIPS.abiflags section description.
+ */
+
+       .section .mips_abiflags, "a"
+       .align 3
+__mips_abiflags:
+       .hword  0               /* version */
+       .byte   __mips          /* isa_level */
+
+       /* isa_rev */
+#ifdef __mips_isa_rev
+       .byte   __mips_isa_rev
+#else
+       .byte   0
+#endif
+
+       /* gpr_size */
+#ifdef __mips64
+       .byte   2               /* AFL_REG_64 */
+#else
+       .byte   1               /* AFL_REG_32 */
+#endif
+
+       /* cpr1_size */
+#if (defined(__mips_isa_rev) && __mips_isa_rev >= 6) || defined(__mips64)
+       .byte   2               /* AFL_REG_64 */
+#else
+       .byte   1               /* AFL_REG_32 */
+#endif
+
+       .byte   0               /* cpr2_size (AFL_REG_NONE) */
+       .byte   0               /* fp_abi (Val_GNU_MIPS_ABI_FP_ANY) */
+       .word   0               /* isa_ext */
+       .word   0               /* ases */
+       .word   0               /* flags1 */
+       .word   0               /* flags2 */
diff --git a/arch/mips/vdso/genvdso.c b/arch/mips/vdso/genvdso.c
new file mode 100644 (file)
index 0000000..530a36f
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 tool is used to generate the real VDSO images from the raw image. It
+ * first patches up the MIPS ABI flags and GNU attributes sections defined in
+ * elf.S to have the correct name and type. It then generates a C source file
+ * to be compiled into the kernel containing the VDSO image data and a
+ * mips_vdso_image struct for it, including symbol offsets extracted from the
+ * image.
+ *
+ * We need to be passed both a stripped and unstripped VDSO image. The stripped
+ * image is compiled into the kernel, but we must also patch up the unstripped
+ * image's ABI flags sections so that it can be installed and used for
+ * debugging.
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <byteswap.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Define these in case the system elf.h is not new enough to have them. */
+#ifndef SHT_GNU_ATTRIBUTES
+# define SHT_GNU_ATTRIBUTES    0x6ffffff5
+#endif
+#ifndef SHT_MIPS_ABIFLAGS
+# define SHT_MIPS_ABIFLAGS     0x7000002a
+#endif
+
+enum {
+       ABI_O32 = (1 << 0),
+       ABI_N32 = (1 << 1),
+       ABI_N64 = (1 << 2),
+
+       ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
+};
+
+/* Symbols the kernel requires offsets for. */
+static struct {
+       const char *name;
+       const char *offset_name;
+       unsigned int abis;
+} vdso_symbols[] = {
+       { "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
+       { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
+       {}
+};
+
+static const char *program_name;
+static const char *vdso_name;
+static unsigned char elf_class;
+static unsigned int elf_abi;
+static bool need_swap;
+static FILE *out_file;
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define HOST_ORDER            ELFDATA2LSB
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define HOST_ORDER            ELFDATA2MSB
+#endif
+
+#define BUILD_SWAP(bits)                                               \
+       static uint##bits##_t swap_uint##bits(uint##bits##_t val)       \
+       {                                                               \
+               return need_swap ? bswap_##bits(val) : val;             \
+       }
+
+BUILD_SWAP(16)
+BUILD_SWAP(32)
+BUILD_SWAP(64)
+
+#define __FUNC(name, bits) name##bits
+#define _FUNC(name, bits) __FUNC(name, bits)
+#define FUNC(name) _FUNC(name, ELF_BITS)
+
+#define __ELF(x, bits) Elf##bits##_##x
+#define _ELF(x, bits) __ELF(x, bits)
+#define ELF(x) _ELF(x, ELF_BITS)
+
+/*
+ * Include genvdso.h twice with ELF_BITS defined differently to get functions
+ * for both ELF32 and ELF64.
+ */
+
+#define ELF_BITS 64
+#include "genvdso.h"
+#undef ELF_BITS
+
+#define ELF_BITS 32
+#include "genvdso.h"
+#undef ELF_BITS
+
+static void *map_vdso(const char *path, size_t *_size)
+{
+       int fd;
+       struct stat stat;
+       void *addr;
+       const Elf32_Ehdr *ehdr;
+
+       fd = open(path, O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
+                       path, strerror(errno));
+               return NULL;
+       }
+
+       if (fstat(fd, &stat) != 0) {
+               fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
+                       path, strerror(errno));
+               return NULL;
+       }
+
+       addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
+                   0);
+       if (addr == MAP_FAILED) {
+               fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
+                       path, strerror(errno));
+               return NULL;
+       }
+
+       /* ELF32/64 header formats are the same for the bits we're checking. */
+       ehdr = addr;
+
+       if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+               fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
+                       path);
+               return NULL;
+       }
+
+       elf_class = ehdr->e_ident[EI_CLASS];
+       switch (elf_class) {
+       case ELFCLASS32:
+       case ELFCLASS64:
+               break;
+       default:
+               fprintf(stderr, "%s: '%s' has invalid ELF class\n",
+                       program_name, path);
+               return NULL;
+       }
+
+       switch (ehdr->e_ident[EI_DATA]) {
+       case ELFDATA2LSB:
+       case ELFDATA2MSB:
+               need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
+               break;
+       default:
+               fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
+                       program_name, path);
+               return NULL;
+       }
+
+       if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
+               fprintf(stderr,
+                       "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
+                       program_name, path);
+               return NULL;
+       } else if (swap_uint16(ehdr->e_type) != ET_DYN) {
+               fprintf(stderr,
+                       "%s: '%s' has invalid ELF type (expected ET_DYN)\n",
+                       program_name, path);
+               return NULL;
+       }
+
+       *_size = stat.st_size;
+       return addr;
+}
+
+static bool patch_vdso(const char *path, void *vdso)
+{
+       if (elf_class == ELFCLASS64)
+               return patch_vdso64(path, vdso);
+       else
+               return patch_vdso32(path, vdso);
+}
+
+static bool get_symbols(const char *path, void *vdso)
+{
+       if (elf_class == ELFCLASS64)
+               return get_symbols64(path, vdso);
+       else
+               return get_symbols32(path, vdso);
+}
+
+int main(int argc, char **argv)
+{
+       const char *dbg_vdso_path, *vdso_path, *out_path;
+       void *dbg_vdso, *vdso;
+       size_t dbg_vdso_size, vdso_size, i;
+
+       program_name = argv[0];
+
+       if (argc < 4 || argc > 5) {
+               fprintf(stderr,
+                       "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
+                       program_name);
+               return EXIT_FAILURE;
+       }
+
+       dbg_vdso_path = argv[1];
+       vdso_path = argv[2];
+       out_path = argv[3];
+       vdso_name = (argc > 4) ? argv[4] : "";
+
+       dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
+       if (!dbg_vdso)
+               return EXIT_FAILURE;
+
+       vdso = map_vdso(vdso_path, &vdso_size);
+       if (!vdso)
+               return EXIT_FAILURE;
+
+       /* Patch both the VDSOs' ABI flags sections. */
+       if (!patch_vdso(dbg_vdso_path, dbg_vdso))
+               return EXIT_FAILURE;
+       if (!patch_vdso(vdso_path, vdso))
+               return EXIT_FAILURE;
+
+       if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
+               fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
+                       dbg_vdso_path, strerror(errno));
+               return EXIT_FAILURE;
+       } else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
+               fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
+                       vdso_path, strerror(errno));
+               return EXIT_FAILURE;
+       }
+
+       out_file = fopen(out_path, "w");
+       if (!out_file) {
+               fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
+                       out_path, strerror(errno));
+               return EXIT_FAILURE;
+       }
+
+       fprintf(out_file, "/* Automatically generated - do not edit */\n");
+       fprintf(out_file, "#include <linux/linkage.h>\n");
+       fprintf(out_file, "#include <linux/mm.h>\n");
+       fprintf(out_file, "#include <asm/vdso.h>\n");
+
+       /* Write out the stripped VDSO data. */
+       fprintf(out_file,
+               "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
+               vdso_size);
+       for (i = 0; i < vdso_size; i++) {
+               if (!(i % 10))
+                       fprintf(out_file, "\n\t");
+               fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
+       }
+       fprintf(out_file, "\n};\n");
+
+       /* Preallocate a page array. */
+       fprintf(out_file,
+               "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
+               vdso_size);
+
+       fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
+               (vdso_name[0]) ? "_" : "", vdso_name);
+       fprintf(out_file, "\t.data = vdso_data,\n");
+       fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
+       fprintf(out_file, "\t.mapping = {\n");
+       fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
+       fprintf(out_file, "\t\t.pages = vdso_pages,\n");
+       fprintf(out_file, "\t},\n");
+
+       /* Calculate and write symbol offsets to <output file> */
+       if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
+               unlink(out_path);
+               return EXIT_FAILURE;
+       }
+
+       fprintf(out_file, "};\n");
+
+       return EXIT_SUCCESS;
+}
diff --git a/arch/mips/vdso/genvdso.h b/arch/mips/vdso/genvdso.h
new file mode 100644 (file)
index 0000000..9433472
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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.
+ */
+
+static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
+{
+       const ELF(Ehdr) *ehdr = vdso;
+       void *shdrs;
+       ELF(Shdr) *shdr;
+       char *shstrtab, *name;
+       uint16_t sh_count, sh_entsize, i;
+       unsigned int local_gotno, symtabno, gotsym;
+       ELF(Dyn) *dyn = NULL;
+
+       shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
+       sh_count = swap_uint16(ehdr->e_shnum);
+       sh_entsize = swap_uint16(ehdr->e_shentsize);
+
+       shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
+       shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+
+       for (i = 0; i < sh_count; i++) {
+               shdr = shdrs + (i * sh_entsize);
+               name = shstrtab + swap_uint32(shdr->sh_name);
+
+               /*
+                * Ensure there are no relocation sections - ld.so does not
+                * relocate the VDSO so if there are relocations things will
+                * break.
+                */
+               switch (swap_uint32(shdr->sh_type)) {
+               case SHT_REL:
+               case SHT_RELA:
+                       fprintf(stderr,
+                               "%s: '%s' contains relocation sections\n",
+                               program_name, path);
+                       return false;
+               case SHT_DYNAMIC:
+                       dyn = vdso + FUNC(swap_uint)(shdr->sh_offset);
+                       break;
+               }
+
+               /* Check for existing sections. */
+               if (strcmp(name, ".MIPS.abiflags") == 0) {
+                       fprintf(stderr,
+                               "%s: '%s' already contains a '.MIPS.abiflags' section\n",
+                               program_name, path);
+                       return false;
+               }
+
+               if (strcmp(name, ".mips_abiflags") == 0) {
+                       strcpy(name, ".MIPS.abiflags");
+                       shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
+                       shdr->sh_entsize = shdr->sh_size;
+               }
+       }
+
+       /*
+        * Ensure the GOT has no entries other than the standard 2, for the same
+        * reason we check that there's no relocation sections above.
+        * The standard two entries are:
+        * - Lazy resolver
+        * - Module pointer
+        */
+       if (dyn) {
+               local_gotno = symtabno = gotsym = 0;
+
+               while (FUNC(swap_uint)(dyn->d_tag) != DT_NULL) {
+                       switch (FUNC(swap_uint)(dyn->d_tag)) {
+                       /*
+                        * This member holds the number of local GOT entries.
+                        */
+                       case DT_MIPS_LOCAL_GOTNO:
+                               local_gotno = FUNC(swap_uint)(dyn->d_un.d_val);
+                               break;
+                       /*
+                        * This member holds the number of entries in the
+                        * .dynsym section.
+                        */
+                       case DT_MIPS_SYMTABNO:
+                               symtabno = FUNC(swap_uint)(dyn->d_un.d_val);
+                               break;
+                       /*
+                        * This member holds the index of the first dynamic
+                        * symbol table entry that corresponds to an entry in
+                        * the GOT.
+                        */
+                       case DT_MIPS_GOTSYM:
+                               gotsym = FUNC(swap_uint)(dyn->d_un.d_val);
+                               break;
+                       }
+
+                       dyn++;
+               }
+
+               if (local_gotno > 2 || symtabno - gotsym) {
+                       fprintf(stderr,
+                               "%s: '%s' contains unexpected GOT entries\n",
+                               program_name, path);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static inline bool FUNC(get_symbols)(const char *path, void *vdso)
+{
+       const ELF(Ehdr) *ehdr = vdso;
+       void *shdrs, *symtab;
+       ELF(Shdr) *shdr;
+       const ELF(Sym) *sym;
+       char *strtab, *name;
+       uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
+       uint64_t offset;
+       uint32_t flags;
+
+       shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
+       sh_count = swap_uint16(ehdr->e_shnum);
+       sh_entsize = swap_uint16(ehdr->e_shentsize);
+
+       for (i = 0; i < sh_count; i++) {
+               shdr = shdrs + (i * sh_entsize);
+
+               if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
+                       break;
+       }
+
+       if (i == sh_count) {
+               fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
+                       path);
+               return false;
+       }
+
+       /* Get flags */
+       flags = swap_uint32(ehdr->e_flags);
+       if (elf_class == ELFCLASS64)
+               elf_abi = ABI_N64;
+       else if (flags & EF_MIPS_ABI2)
+               elf_abi = ABI_N32;
+       else
+               elf_abi = ABI_O32;
+
+       /* Get symbol table. */
+       symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+       st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
+       st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
+
+       /* Get string table. */
+       shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
+       strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+
+       /* Write offsets for symbols needed by the kernel. */
+       for (i = 0; vdso_symbols[i].name; i++) {
+               if (!(vdso_symbols[i].abis & elf_abi))
+                       continue;
+
+               for (j = 0; j < st_count; j++) {
+                       sym = symtab + (j * st_entsize);
+                       name = strtab + swap_uint32(sym->st_name);
+
+                       if (!strcmp(name, vdso_symbols[i].name)) {
+                               offset = FUNC(swap_uint)(sym->st_value);
+
+                               fprintf(out_file,
+                                       "\t.%s = 0x%" PRIx64 ",\n",
+                                       vdso_symbols[i].offset_name, offset);
+                               break;
+                       }
+               }
+
+               if (j == st_count) {
+                       fprintf(stderr,
+                               "%s: '%s' is missing required symbol '%s'\n",
+                               program_name, path, vdso_symbols[i].name);
+                       return false;
+               }
+       }
+
+       return true;
+}
diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c
new file mode 100644 (file)
index 0000000..ce89c9e
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include "vdso.h"
+
+#include <linux/compiler.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/time.h>
+
+#include <asm/clocksource.h>
+#include <asm/io.h>
+#include <asm/mips-cm.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+static __always_inline int do_realtime_coarse(struct timespec *ts,
+                                             const union mips_vdso_data *data)
+{
+       u32 start_seq;
+
+       do {
+               start_seq = vdso_data_read_begin(data);
+
+               ts->tv_sec = data->xtime_sec;
+               ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+       } while (vdso_data_read_retry(data, start_seq));
+
+       return 0;
+}
+
+static __always_inline int do_monotonic_coarse(struct timespec *ts,
+                                              const union mips_vdso_data *data)
+{
+       u32 start_seq;
+       u32 to_mono_sec;
+       u32 to_mono_nsec;
+
+       do {
+               start_seq = vdso_data_read_begin(data);
+
+               ts->tv_sec = data->xtime_sec;
+               ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+
+               to_mono_sec = data->wall_to_mono_sec;
+               to_mono_nsec = data->wall_to_mono_nsec;
+       } while (vdso_data_read_retry(data, start_seq));
+
+       ts->tv_sec += to_mono_sec;
+       timespec_add_ns(ts, to_mono_nsec);
+
+       return 0;
+}
+
+#ifdef CONFIG_CSRC_R4K
+
+static __always_inline u64 read_r4k_count(void)
+{
+       unsigned int count;
+
+       __asm__ __volatile__(
+       "       .set push\n"
+       "       .set mips32r2\n"
+       "       rdhwr   %0, $2\n"
+       "       .set pop\n"
+       : "=r" (count));
+
+       return count;
+}
+
+#endif
+
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static __always_inline u64 read_gic_count(const union mips_vdso_data *data)
+{
+       void __iomem *gic = get_gic(data);
+       u32 hi, hi2, lo;
+
+       do {
+               hi = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+               lo = __raw_readl(gic + GIC_UMV_SH_COUNTER_31_00_OFS);
+               hi2 = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+       } while (hi2 != hi);
+
+       return (((u64)hi) << 32) + lo;
+}
+
+#endif
+
+static __always_inline u64 get_ns(const union mips_vdso_data *data)
+{
+       u64 cycle_now, delta, nsec;
+
+       switch (data->clock_mode) {
+#ifdef CONFIG_CSRC_R4K
+       case VDSO_CLOCK_R4K:
+               cycle_now = read_r4k_count();
+               break;
+#endif
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+       case VDSO_CLOCK_GIC:
+               cycle_now = read_gic_count(data);
+               break;
+#endif
+       default:
+               return 0;
+       }
+
+       delta = (cycle_now - data->cs_cycle_last) & data->cs_mask;
+
+       nsec = (delta * data->cs_mult) + data->xtime_nsec;
+       nsec >>= data->cs_shift;
+
+       return nsec;
+}
+
+static __always_inline int do_realtime(struct timespec *ts,
+                                      const union mips_vdso_data *data)
+{
+       u32 start_seq;
+       u64 ns;
+
+       do {
+               start_seq = vdso_data_read_begin(data);
+
+               if (data->clock_mode == VDSO_CLOCK_NONE)
+                       return -ENOSYS;
+
+               ts->tv_sec = data->xtime_sec;
+               ns = get_ns(data);
+       } while (vdso_data_read_retry(data, start_seq));
+
+       ts->tv_nsec = 0;
+       timespec_add_ns(ts, ns);
+
+       return 0;
+}
+
+static __always_inline int do_monotonic(struct timespec *ts,
+                                       const union mips_vdso_data *data)
+{
+       u32 start_seq;
+       u64 ns;
+       u32 to_mono_sec;
+       u32 to_mono_nsec;
+
+       do {
+               start_seq = vdso_data_read_begin(data);
+
+               if (data->clock_mode == VDSO_CLOCK_NONE)
+                       return -ENOSYS;
+
+               ts->tv_sec = data->xtime_sec;
+               ns = get_ns(data);
+
+               to_mono_sec = data->wall_to_mono_sec;
+               to_mono_nsec = data->wall_to_mono_nsec;
+       } while (vdso_data_read_retry(data, start_seq));
+
+       ts->tv_sec += to_mono_sec;
+       ts->tv_nsec = 0;
+       timespec_add_ns(ts, ns + to_mono_nsec);
+
+       return 0;
+}
+
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+/*
+ * This is behind the ifdef so that we don't provide the symbol when there's no
+ * possibility of there being a usable clocksource, because there's nothing we
+ * can do without it. When libc fails the symbol lookup it should fall back on
+ * the standard syscall path.
+ */
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       const union mips_vdso_data *data = get_vdso_data();
+       struct timespec ts;
+       int ret;
+
+       ret = do_realtime(&ts, data);
+       if (ret)
+               return ret;
+
+       if (tv) {
+               tv->tv_sec = ts.tv_sec;
+               tv->tv_usec = ts.tv_nsec / 1000;
+       }
+
+       if (tz) {
+               tz->tz_minuteswest = data->tz_minuteswest;
+               tz->tz_dsttime = data->tz_dsttime;
+       }
+
+       return 0;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
+int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+       const union mips_vdso_data *data = get_vdso_data();
+       int ret;
+
+       switch (clkid) {
+       case CLOCK_REALTIME_COARSE:
+               ret = do_realtime_coarse(ts, data);
+               break;
+       case CLOCK_MONOTONIC_COARSE:
+               ret = do_monotonic_coarse(ts, data);
+               break;
+       case CLOCK_REALTIME:
+               ret = do_realtime(ts, data);
+               break;
+       case CLOCK_MONOTONIC:
+               ret = do_monotonic(ts, data);
+               break;
+       default:
+               ret = -ENOSYS;
+               break;
+       }
+
+       /* If we return -ENOSYS libc should fall back to a syscall. */
+       return ret;
+}
diff --git a/arch/mips/vdso/sigreturn.S b/arch/mips/vdso/sigreturn.S
new file mode 100644 (file)
index 0000000..715bf59
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include "vdso.h"
+
+#include <uapi/asm/unistd.h>
+
+#include <asm/regdef.h>
+#include <asm/asm.h>
+
+       .section        .text
+       .cfi_sections   .debug_frame
+
+LEAF(__vdso_rt_sigreturn)
+       .cfi_startproc
+       .frame  sp, 0, ra
+       .mask   0x00000000, 0
+       .fmask  0x00000000, 0
+       .cfi_signal_frame
+
+       li      v0, __NR_rt_sigreturn
+       syscall
+
+       .cfi_endproc
+       END(__vdso_rt_sigreturn)
+
+#if _MIPS_SIM == _MIPS_SIM_ABI32
+
+LEAF(__vdso_sigreturn)
+       .cfi_startproc
+       .frame  sp, 0, ra
+       .mask   0x00000000, 0
+       .fmask  0x00000000, 0
+       .cfi_signal_frame
+
+       li      v0, __NR_sigreturn
+       syscall
+
+       .cfi_endproc
+       END(__vdso_sigreturn)
+
+#endif
diff --git a/arch/mips/vdso/vdso.h b/arch/mips/vdso/vdso.h
new file mode 100644 (file)
index 0000000..cfb1be4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/sgidefs.h>
+
+#if _MIPS_SIM != _MIPS_SIM_ABI64 && defined(CONFIG_64BIT)
+
+/* Building 32-bit VDSO for the 64-bit kernel. Fake a 32-bit Kconfig. */
+#undef CONFIG_64BIT
+#define CONFIG_32BIT 1
+#ifndef __ASSEMBLY__
+#include <asm-generic/atomic64.h>
+#endif
+#endif
+
+#ifndef __ASSEMBLY__
+
+#include <asm/asm.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+static inline unsigned long get_vdso_base(void)
+{
+       unsigned long addr;
+
+       /*
+        * We can't use cpu_has_mips_r6 since it needs the cpu_data[]
+        * kernel symbol.
+        */
+#ifdef CONFIG_CPU_MIPSR6
+       /*
+        * lapc <symbol> is an alias to addiupc reg, <symbol> - .
+        *
+        * We can't use addiupc because there is no label-label
+        * support for the addiupc reloc
+        */
+       __asm__("lapc   %0, _start                      \n"
+               : "=r" (addr) : :);
+#else
+       /*
+        * Get the base load address of the VDSO. We have to avoid generating
+        * relocations and references to the GOT because ld.so does not peform
+        * relocations on the VDSO. We use the current offset from the VDSO base
+        * and perform a PC-relative branch which gives the absolute address in
+        * ra, and take the difference. The assembler chokes on
+        * "li %0, _start - .", so embed the offset as a word and branch over
+        * it.
+        *
+        */
+
+       __asm__(
+       "       .set push                               \n"
+       "       .set noreorder                          \n"
+       "       bal     1f                              \n"
+       "        nop                                    \n"
+       "       .word   _start - .                      \n"
+       "1:     lw      %0, 0($31)                      \n"
+       "       " STR(PTR_ADDU) " %0, $31, %0           \n"
+       "       .set pop                                \n"
+       : "=r" (addr)
+       :
+       : "$31");
+#endif /* CONFIG_CPU_MIPSR6 */
+
+       return addr;
+}
+
+static inline const union mips_vdso_data *get_vdso_data(void)
+{
+       return (const union mips_vdso_data *)(get_vdso_base() - PAGE_SIZE);
+}
+
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static inline void __iomem *get_gic(const union mips_vdso_data *data)
+{
+       return (void __iomem *)data - PAGE_SIZE;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
new file mode 100644 (file)
index 0000000..8df7dd5
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/sgidefs.h>
+
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
+#elif _MIPS_SIM == _MIPS_SIM_NABI32
+OUTPUT_FORMAT("elf32-ntradlittlemips", "elf32-ntradbigmips", "elf32-ntradlittlemips")
+#else
+OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", "elf32-tradlittlemips")
+#endif
+
+OUTPUT_ARCH(mips)
+
+SECTIONS
+{
+       PROVIDE(_start = .);
+       . = SIZEOF_HEADERS;
+
+       /*
+        * In order to retain compatibility with older toolchains we provide the
+        * ABI flags section ourself. Newer assemblers will automatically
+        * generate .MIPS.abiflags sections so we discard such input sections,
+        * and then manually define our own section here. genvdso will patch
+        * this section to have the correct name/type.
+        */
+       .mips_abiflags  : { *(.mips_abiflags) }         :text :abiflags
+
+       .reginfo        : { *(.reginfo) }               :text :reginfo
+
+       .hash           : { *(.hash) }                  :text
+       .gnu.hash       : { *(.gnu.hash) }
+       .dynsym         : { *(.dynsym) }
+       .dynstr         : { *(.dynstr) }
+       .gnu.version    : { *(.gnu.version) }
+       .gnu.version_d  : { *(.gnu.version_d) }
+       .gnu.version_r  : { *(.gnu.version_r) }
+
+       .note           : { *(.note.*) }                :text :note
+
+       .text           : { *(.text*) }                 :text
+       PROVIDE (__etext = .);
+       PROVIDE (_etext = .);
+       PROVIDE (etext = .);
+
+       .eh_frame_hdr   : { *(.eh_frame_hdr) }          :text :eh_frame_hdr
+       .eh_frame       : { KEEP (*(.eh_frame)) }       :text
+
+       .dynamic        : { *(.dynamic) }               :text :dynamic
+
+       .rodata         : { *(.rodata*) }               :text
+
+       _end = .;
+       PROVIDE(end = .);
+
+       /DISCARD/       : {
+               *(.MIPS.abiflags)
+               *(.gnu.attributes)
+               *(.note.GNU-stack)
+               *(.data .data.* .gnu.linkonce.d.* .sdata*)
+               *(.bss .sbss .dynbss .dynsbss)
+       }
+}
+
+PHDRS
+{
+       /*
+        * Provide a PT_MIPS_ABIFLAGS header to assign the ABI flags section
+        * to. We can specify the header type directly here so no modification
+        * is needed later on.
+        */
+       abiflags        0x70000003;
+
+       /*
+        * The ABI flags header must exist directly after the PT_INTERP header,
+        * so we must explicitly place the PT_MIPS_REGINFO header after it to
+        * stop the linker putting one in at the start.
+        */
+       reginfo         0x70000000;
+
+       text            PT_LOAD         FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+       dynamic         PT_DYNAMIC      FLAGS(4);               /* PF_R */
+       note            PT_NOTE         FLAGS(4);               /* PF_R */
+       eh_frame_hdr    PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+       LINUX_2.6 {
+#ifndef DISABLE_MIPS_VDSO
+       global:
+               __vdso_clock_gettime;
+               __vdso_gettimeofday;
+#endif
+       local: *;
+       };
+}
index 02a1945..89d3e4d 100644 (file)
@@ -140,9 +140,10 @@ static cycle_t gic_hpt_read(struct clocksource *cs)
 }
 
 static struct clocksource gic_clocksource = {
-       .name   = "GIC",
-       .read   = gic_hpt_read,
-       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .name           = "GIC",
+       .read           = gic_hpt_read,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .archdata       = { .vdso_clock_mode = VDSO_CLOCK_GIC },
 };
 
 static void __init __gic_clocksource_init(void)
index aeaa061..9e17ef2 100644 (file)
@@ -29,6 +29,7 @@ struct gic_pcpu_mask {
        DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
 };
 
+static unsigned long __gic_base_addr;
 static void __iomem *gic_base;
 static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
 static DEFINE_SPINLOCK(gic_lock);
@@ -301,6 +302,17 @@ int gic_get_c0_fdc_int(void)
                                  GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
 }
 
+int gic_get_usm_range(struct resource *gic_usm_res)
+{
+       if (!gic_present)
+               return -1;
+
+       gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
+       gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
+
+       return 0;
+}
+
 static void gic_handle_shared_int(bool chained)
 {
        unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
@@ -798,6 +810,8 @@ static void __init __gic_init(unsigned long gic_base_addr,
 {
        unsigned int gicconfig;
 
+       __gic_base_addr = gic_base_addr;
+
        gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
 
        gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
index 4e68616..ce824db 100644 (file)
@@ -9,6 +9,7 @@
 #define __LINUX_IRQCHIP_MIPS_GIC_H
 
 #include <linux/clocksource.h>
+#include <linux/ioport.h>
 
 #define GIC_MAX_INTRS                  256
 
 #define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x))
 #define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE)
 
+#ifdef CONFIG_MIPS_GIC
+
 extern unsigned int gic_present;
 
 extern void gic_init(unsigned long gic_base_addr,
@@ -264,4 +267,18 @@ extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
 extern int gic_get_c0_compare_int(void);
 extern int gic_get_c0_perfcount_int(void);
 extern int gic_get_c0_fdc_int(void);
+extern int gic_get_usm_range(struct resource *gic_usm_res);
+
+#else /* CONFIG_MIPS_GIC */
+
+#define gic_present    0
+
+static inline int gic_get_usm_range(struct resource *gic_usm_res)
+{
+       /* Shouldn't be called. */
+       return -1;
+}
+
+#endif /* CONFIG_MIPS_GIC */
+
 #endif /* __LINUX_IRQCHIP_MIPS_GIC_H */