From: Stephen Rothwell Date: Wed, 4 Nov 2015 23:31:13 +0000 (+1100) Subject: Merge remote-tracking branch 'mips/mips-for-linux-next' X-Git-Tag: KARO-TXUL-2015-12-04~133 X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-linux.git;a=commitdiff_plain;h=a2a43ccf6ff3802cf0e3e4abad9347083f14f7f5;hp=c37fd4f37ab50a3bd9ea4c19ef3f00507e42298a Merge remote-tracking branch 'mips/mips-for-linux-next' --- diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild index dd295335891a..5c3f688a5232 100644 --- a/arch/mips/Kbuild +++ b/arch/mips/Kbuild @@ -17,6 +17,7 @@ obj- := $(platform-) obj-y += kernel/ obj-y += mm/ obj-y += net/ +obj-y += vdso/ ifdef CONFIG_KVM obj-y += kvm/ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index e3aa5b0b4ef1..10feb1520b0c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -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 diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index e250524021ac..f0e314ceb8ba 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -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 diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 252e347958f3..3f70ba54ae21 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -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 # diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 17503a05938e..6d38948f0f1e 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -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); diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 2d5c7a7f24bb..a7e569c7968e 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -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; } diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts index c678115f5b7f..b18c46637d21 100644 --- a/arch/mips/boot/dts/mti/malta.dts +++ b/arch/mips/boot/dts/mti/malta.dts @@ -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>; diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig index 1cdff6b6327d..b3e7a1b61220 100644 --- a/arch/mips/configs/bigsur_defconfig +++ b/arch/mips/configs/bigsur_defconfig @@ -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 diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig index 5135dc0b950a..2924ba34a01b 100644 --- a/arch/mips/configs/capcella_defconfig +++ b/arch/mips/configs/capcella_defconfig @@ -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 diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig index 0126e66d60cb..e94d266c4b97 100644 --- a/arch/mips/configs/e55_defconfig +++ b/arch/mips/configs/e55_defconfig @@ -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 diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig index a75c65da08b4..87435897fd50 100644 --- a/arch/mips/configs/fuloong2e_defconfig +++ b/arch/mips/configs/fuloong2e_defconfig @@ -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 diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig index 0179c7fa014f..e620a2c3eba4 100644 --- a/arch/mips/configs/lasat_defconfig +++ b/arch/mips/configs/lasat_defconfig @@ -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 diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 54cc3853d259..004cf52d1b7d 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -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 diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 61a4460d67d3..5afb4840aec7 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -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 diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig index d41742dd26c8..98f13879bb8f 100644 --- a/arch/mips/configs/malta_kvm_defconfig +++ b/arch/mips/configs/malta_kvm_defconfig @@ -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 diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig index a7806e83ea0f..3b5d5913f548 100644 --- a/arch/mips/configs/malta_kvm_guest_defconfig +++ b/arch/mips/configs/malta_kvm_guest_defconfig @@ -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 diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig index 4bce1f8ebe98..7f50dd67aa8d 100644 --- a/arch/mips/configs/malta_qemu_32r6_defconfig +++ b/arch/mips/configs/malta_qemu_32r6_defconfig @@ -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 diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig index fb042ce86b4b..a9d433a17fcf 100644 --- a/arch/mips/configs/maltaaprp_defconfig +++ b/arch/mips/configs/maltaaprp_defconfig @@ -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 diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig index c83338a39917..2774ef064505 100644 --- a/arch/mips/configs/maltasmvp_eva_defconfig +++ b/arch/mips/configs/maltasmvp_eva_defconfig @@ -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 diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig index 62344648eb7a..9bbd2218f0bf 100644 --- a/arch/mips/configs/maltaup_defconfig +++ b/arch/mips/configs/maltaup_defconfig @@ -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 diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig index c388bff09148..732215732751 100644 --- a/arch/mips/configs/maltaup_xpa_defconfig +++ b/arch/mips/configs/maltaup_xpa_defconfig @@ -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 diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig index 7a346605c498..a2c045fab6c5 100644 --- a/arch/mips/configs/mpc30x_defconfig +++ b/arch/mips/configs/mpc30x_defconfig @@ -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 diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h index 37f84078e78a..940760844e2f 100644 --- a/arch/mips/include/asm/abi.h +++ b/arch/mips/include/asm/abi.h @@ -11,19 +11,20 @@ #include #include +#include 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 */ diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index f82d3af07931..835b402e4574 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -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) { diff --git a/arch/mips/include/asm/bcache.h b/arch/mips/include/asm/bcache.h index 8c34484cea82..a00857b135c3 100644 --- a/arch/mips/include/asm/bcache.h +++ b/arch/mips/include/asm/bcache.h @@ -9,6 +9,7 @@ #ifndef _ASM_BCACHE_H #define _ASM_BCACHE_H +#include /* 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 index 000000000000..3deb1d0c1a94 --- /dev/null +++ b/arch/mips/include/asm/clocksource.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 + +/* 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 */ diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index fe67f12ac239..d1e04c943f5f 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -131,11 +131,7 @@ #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 index 000000000000..254f00deb9d5 --- /dev/null +++ b/arch/mips/include/asm/debug.h @@ -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 + +/* + * 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__ */ diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index 53b26933b12c..b01a6ff468e0 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -8,6 +8,7 @@ #ifndef _ASM_ELF_H #define _ASM_ELF_H +#include #include #include @@ -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, diff --git a/arch/mips/include/asm/fw/fw.h b/arch/mips/include/asm/fw/fw.h index f3e6978aad70..d0ef8b4892bb 100644 --- a/arch/mips/include/asm/fw/fw.h +++ b/arch/mips/include/asm/fw/fw.h @@ -10,21 +10,6 @@ #include /* 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); diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index 1461c10c1c4c..71e4096a2145 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -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 */ diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 133336b493b6..dd6005b75e0c 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -35,6 +35,17 @@ #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 index 000000000000..cfd777663c64 --- /dev/null +++ b/arch/mips/include/asm/mach-malta/malta-dtshim.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton + * + * 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 + +#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__ */ diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 1f1927ab4269..6516e9da5133 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -11,6 +11,7 @@ #ifndef __MIPS_ASM_MIPS_CM_H__ #define __MIPS_ASM_MIPS_CM_H__ +#include #include #include #include @@ -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__ */ diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index f386f32702f1..e09035239e53 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -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); diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index c64781cf649f..e7c1e28438e0 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -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 @@ -126,15 +129,9 @@ #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 diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 59ee6dcf6eed..3f832c3dd8f5 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -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 diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h index cca56aa40ff4..8f4ca5dd992b 100644 --- a/arch/mips/include/asm/vdso.h +++ b/arch/mips/include/asm/vdso.h @@ -1,29 +1,136 @@ /* - * 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 * - * 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 +#include +#include -#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 */ diff --git a/arch/mips/include/uapi/asm/Kbuild b/arch/mips/include/uapi/asm/Kbuild index 96fe7395ed8d..f2cf41461146 100644 --- a/arch/mips/include/uapi/asm/Kbuild +++ b/arch/mips/include/uapi/asm/Kbuild @@ -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 index 000000000000..c9c7195272c4 --- /dev/null +++ b/arch/mips/include/uapi/asm/auxvec.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 */ diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 459cb017306c..934b15b5b575 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -34,8 +35,6 @@ #include #include -#include - #include #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)); diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d982be1ea1c3..68e2b7db9348 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -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 index 000000000000..6d246ad05638 --- /dev/null +++ b/arch/mips/kernel/cps-vec-ns16550.S @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#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 diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 209ded16806b..8fd5a276cad2 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -25,14 +25,32 @@ .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 @@ -47,11 +65,9 @@ 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 diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 09a51d091941..6b9064499bd3 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -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; } diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e5ed7ada1433..1f910563fdf6 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c @@ -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); diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index ab1478d5a4db..3e2b0b6c3b08 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -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; diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index b8ceee576cdf..1448c1f43d4e 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -9,6 +9,8 @@ */ #include +#include +#include #include #include @@ -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 */ diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 8af4d627b68b..566b8d2c092c 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -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) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index f2977f00911b..1f5aac7f9ec3 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -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) diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c index 076ead2a9859..87bc74a5a518 100644 --- a/arch/mips/kernel/segment.c +++ b/arch/mips/kernel/segment.c @@ -10,6 +10,7 @@ #include #include #include +#include #include 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) { diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 479515109e5b..5b46b672c939 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 2fec67bfc457..bf792e2839a6 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -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); } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index f7e89524e316..4909639aa35b 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #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, }; diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 0d017fdcaf07..a7bc38430500 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -38,7 +38,6 @@ #include #include #include -#include #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, }; diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index c88937745b4e..e04c8057b882 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -8,6 +8,7 @@ * option) any later version. */ +#include #include #include #include @@ -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); } diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c index 5f0ab5bcd01e..9b63829cf929 100644 --- a/arch/mips/kernel/smp-gic.c +++ b/arch/mips/kernel/smp-gic.c @@ -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(); } } diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c index 39f7ab7b0426..f7d86955d1b8 100644 --- a/arch/mips/kernel/spinlock_test.c +++ b/arch/mips/kernel/spinlock_test.c @@ -5,7 +5,7 @@ #include #include #include - +#include 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; diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c index 1ba775d24d38..506021f62549 100644 --- a/arch/mips/kernel/stacktrace.c +++ b/arch/mips/kernel/stacktrace.c @@ -12,14 +12,15 @@ * 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); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index fdb392b27e81..4e106d52f304 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -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); } diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 990354dd6bde..490cea569d57 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -85,6 +85,7 @@ #include #include #include +#include #include #include #include @@ -2295,7 +2296,6 @@ sigbus: } #ifdef CONFIG_DEBUG_FS -extern struct dentry *mips_debugfs_dir; static int __init debugfs_unaligned(void) { struct dentry *d; diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index ed2a278722a9..975e99759bab 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -1,122 +1,175 @@ /* - * 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 * - * 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 -#include -#include -#include -#include #include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include + +/* Kernel-provided data used by the VDSO. */ +static union mips_vdso_data vdso_data __page_aligned_data; /* - * Including 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; -} diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c index 3fc2e6d70c77..a0706fd4ce0a 100644 --- a/arch/mips/lantiq/clk.c +++ b/arch/mips/lantiq/clk.c @@ -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))) diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h index 77e4bdb1fe8c..7376ce817eda 100644 --- a/arch/mips/lantiq/clk.h +++ b/arch/mips/lantiq/clk.h @@ -31,13 +31,18 @@ #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 diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c index 2c218c3bbca5..2e7f60c9fc5d 100644 --- a/arch/mips/lantiq/irq.c +++ b/arch/mips/lantiq/irq.c @@ -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, diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c index 8750dc0a1bf6..80aad3080ef8 100644 --- a/arch/mips/lantiq/xway/clk.c +++ b/arch/mips/lantiq/xway/clk.c @@ -4,6 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2010 John Crispin + * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ #include @@ -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; +} diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c index 248429ab2622..8f6e02f1e965 100644 --- a/arch/mips/lantiq/xway/prom.c +++ b/arch/mips/lantiq/xway/prom.c @@ -4,6 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2010 John Crispin + * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ #include @@ -19,8 +20,11 @@ #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; diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c index fe68f9ae47c1..dd1aaaf8e3e6 100644 --- a/arch/mips/lantiq/xway/reset.c +++ b/arch/mips/lantiq/xway/reset.c @@ -4,6 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2010 John Crispin + * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ #include @@ -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 */ @@ -32,11 +30,29 @@ /* 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 @@ -47,6 +63,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(<q_rcu_lock, flags); + ltq_rcu_w32((ltq_rcu_r32(reg_off) & ~(clr)) | (set), reg_off); + spin_unlock_irqrestore(<q_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)); diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c index 2b15491de494..7b3a01456014 100644 --- a/arch/mips/lantiq/xway/sysctrl.c +++ b/arch/mips/lantiq/xway/sysctrl.c @@ -4,11 +4,13 @@ * by the Free Software Foundation. * * Copyright (C) 2011-2012 John Crispin + * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG */ #include #include #include +#include #include #include #include @@ -18,16 +20,18 @@ #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 */ @@ -41,13 +45,56 @@ /* 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) @@ -56,12 +103,15 @@ #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) @@ -70,10 +120,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); } } diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 1e9e900cd3c3..0344e575f522 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -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 index 000000000000..77e5f9c1f005 --- /dev/null +++ b/arch/mips/lib/bswapdi.c @@ -0,0 +1,15 @@ +#include + +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 index 000000000000..2b302ff121d2 --- /dev/null +++ b/arch/mips/lib/bswapsi.c @@ -0,0 +1,11 @@ +#include + +unsigned int __bswapsi2(unsigned int u) +{ + return (((u) & 0xff000000) >> 24) | + (((u) & 0x00ff0000) >> 8) | + (((u) & 0x0000ff00) << 8) | + (((u) & 0x000000ff) << 24); +} + +EXPORT_SYMBOL(__bswapsi2); diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index 506a67a98cdf..be650ed7db59 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 67ede4ef9b8d..b4c64bd3f723 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -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 index 000000000000..5eefe3281b24 --- /dev/null +++ b/arch/mips/mm/sc-debugfs.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +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); diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 53ea8391f9bb..3bd0597d9c3d 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -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; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 323d1d302f2b..32e0be27673f 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -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); diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index ea35587a5c29..5827af77c18e 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile @@ -5,9 +5,18 @@ # Copyright (C) 2008 Wind River Systems, Inc. # written by Ralf Baechle # -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 index 000000000000..f7133efc5843 --- /dev/null +++ b/arch/mips/mti-malta/malta-dtshim.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Paul Burton + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index 53c24784a2f7..571148c5fd0b 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -302,6 +302,7 @@ mips_pci_controller: return; if (!register_vsmp_smp_ops()) return; + register_up_smp_ops(); } void platform_early_l2_init(void) diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index dadeb8379182..d5f8dae6a797 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c @@ -21,147 +21,20 @@ #include #include -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) diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c index 9d1e7f5ec36c..4740c82fb97a 100644 --- a/arch/mips/mti-malta/malta-setup.c +++ b/arch/mips/mti-malta/malta-setup.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -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 */ diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index ed6732f9aa87..53a42b07008b 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -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 index 000000000000..5286a7d73d79 --- /dev/null +++ b/arch/mips/vdso/.gitignore @@ -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 index 000000000000..ef5f348f386a --- /dev/null +++ b/arch/mips/vdso/Makefile @@ -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 index 000000000000..be37bbb1f061 --- /dev/null +++ b/arch/mips/vdso/elf.S @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 +#include + +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 index 000000000000..530a36f465ce --- /dev/null +++ b/arch/mips/vdso/genvdso.c @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 []\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 \n"); + fprintf(out_file, "#include \n"); + fprintf(out_file, "#include \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 */ + 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 index 000000000000..94334727059a --- /dev/null +++ b/arch/mips/vdso/genvdso.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 index 000000000000..ce89c9e294f9 --- /dev/null +++ b/arch/mips/vdso/gettimeofday.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +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 index 000000000000..715bf5993529 --- /dev/null +++ b/arch/mips/vdso/sigreturn.S @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 + +#include +#include + + .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 index 000000000000..cfb1be441dec --- /dev/null +++ b/arch/mips/vdso/vdso.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 + +#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 +#endif +#endif + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +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 is an alias to addiupc reg, - . + * + * 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 index 000000000000..8df7dd53e8e0 --- /dev/null +++ b/arch/mips/vdso/vdso.lds.S @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith + * + * 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 + +#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: *; + }; +} diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 02a1945e5093..89d3e4d7900c 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -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) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index aeaa061f0dbf..9e17ef27a183 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -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)); diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 4e6861605050..ce824db48d64 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -9,6 +9,7 @@ #define __LINUX_IRQCHIP_MIPS_GIC_H #include +#include #define GIC_MAX_INTRS 256 @@ -245,6 +246,8 @@ #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 */