Re: [PATCH 0/8] revised patch for arch/tile/ support

From: Chris Metcalf
Date: Fri May 28 2010 - 23:53:53 EST


Arnd Bergmann suggested that providing a diff of what has changed
between the two "arch/tile" patch sets would be helpful to the reviewers.

The "hvglue.ld" file was renamed, but I didn't bother to include it in
the diff otherwise, since all that changed was the addition of a comment
at the top. A new "spinlock_common.h" is included in the diff.

diff -ru tile.old/Kbuild tile/Kbuild
--- tile.old/Kbuild 2010-05-28 18:03:30.805351000 -0400
+++ tile/Kbuild 2010-05-28 23:07:06.099173000 -0400
@@ -1,4 +1,3 @@

obj-y += kernel/
obj-y += mm/
-obj-y += feedback/
diff -ru tile.old/Kconfig tile/Kconfig
--- tile.old/Kconfig 2010-05-28 18:03:30.834316000 -0400
+++ tile/Kconfig 2010-05-28 23:07:04.674403000 -0400
@@ -1,9 +1,70 @@
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/config-language.txt.

-mainmenu "Linux/TILE Kernel Configuration"
+config MMU
+ def_bool y
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_HARDIRQS
+ def_bool y
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ def_bool y
+
+config GENERIC_IRQ_PROBE
+ def_bool y
+
+config GENERIC_PENDING_IRQ
+ def_bool y
+ depends on GENERIC_HARDIRQS && SMP
+
+config ZONE_DMA
+ def_bool y
+
+config SEMAPHORE_SLEEPERS
+ def_bool y
+
+config CC_OPTIMIZE_FOR_SIZE
+ def_bool y
+
+config HAVE_ARCH_ALLOC_REMAP
+ def_bool y
+
+config HAVE_SETUP_PER_CPU_AREA
+ def_bool y
+
+config NEED_PER_CPU_PAGE_FIRST_CHUNK
+ def_bool y
+
+config SYS_SUPPORTS_HUGETLBFS
+ def_bool y
+
+config GENERIC_TIME
+ def_bool y
+
+config GENERIC_CLOCKEVENTS
+ def_bool y
+
+config CLOCKSOURCE_WATCHDOG
+ def_bool y
+
+# FIXME: tilegx can implement a more efficent rwsem.
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+# We have a very flat architecture from a migration point of view,
+# so save boot time by presetting this (particularly useful on tile-sim).
+config DEFAULT_MIGRATION_COST
+ int
+ default "10000000"

-config GENERIC_CALIBRATE_DELAY
+# We only support gcc 4.4 and above, so this should work.
+config ARCH_SUPPORTS_OPTIMIZED_INLINING
+ def_bool y
+
+config ARCH_PHYS_ADDR_T_64BIT
def_bool y

config LOCKDEP_SUPPORT
@@ -13,26 +74,62 @@
def_bool y
select STACKTRACE

+config ARCH_DISCONTIGMEM_ENABLE
+ def_bool y
+
+config ARCH_DISCONTIGMEM_DEFAULT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config STRICT_DEVMEM
+ def_bool y
+
+# SMP is required for Tilera Linux.
+config SMP
+ def_bool y
+
+# Allow checking for compile-time determined overflow errors in
+# copy_from_user(). There are still unprovable places in the
+# generic code as of 2.6.34, so this option is not really compatible
+# with -Werror, which is more useful in general.
+config DEBUG_COPY_FROM_USER
+ def_bool n
+
+config SERIAL_CONSOLE
+ def_bool y
+
+config HVC_TILE
+ select HVC_DRIVER
+ def_bool y
+
config TILE
def_bool y
- select HAVE_OPROFILE
- select HAVE_IDE
select GENERIC_FIND_FIRST_BIT
select GENERIC_FIND_NEXT_BIT
select RESOURCES_64BIT
select USE_GENERIC_SMP_HELPERS

# FIXME: investigate whether we need/want these options.
-# select HAVE_GENERIC_DMA_COHERENT
-# select HAVE_DMA_ATTRS
# select HAVE_IOREMAP_PROT
# select HAVE_OPTPROBES
# select HAVE_REGS_AND_STACK_ACCESS_API
# select HAVE_HW_BREAKPOINT
# select PERF_EVENTS
# select HAVE_USER_RETURN_NOTIFIER
+# config NO_BOOTMEM
+# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+# config HUGETLB_PAGE_SIZE_VARIABLE
+
+
+mainmenu "Linux/TILE Kernel Configuration"

+# Please note: TILE-Gx support is not yet finalized; this is
+# the preliminary support. TILE-Gx drivers are only provided
+# with the alpha or beta test versions for Tilera customers.
config TILEGX
+ depends on EXPERIMENTAL
bool "Building with TILE-Gx (64-bit) compiler and toolchain"

config 64BIT
@@ -44,47 +141,10 @@
default "arch/tile/configs/tile_defconfig" if !TILEGX
default "arch/tile/configs/tilegx_defconfig" if TILEGX

-config MMU
- def_bool y
-
source "init/Kconfig"

menu "Tilera-specific configuration"

-# This flag should be marked as "def_bool y" if the kernel is being
-# built as part of the Tilera MDE, which includes a variety of
-# platform-independent kernel changes to add features and performance,
-# and "def_bool n" if building Tile Linux from generic sources.
-#
-# Over time we hope the use of this flag decreases as more of the
-# Tilera platform-independent changes are accepted into the community.
-# It should only be used here in this file, in "depends on" clauses.
-#
-# Note that enabling PCI requires a one-line change in the
-# drivers/pci/Makefile, and TILEmpower requires a quirk change.
-#
-config TILERA_MDE
- def_bool n
-
-# SMP is required for Tilera Linux.
-config SMP
- def_bool y
-
-# By default we always build with -Werror, but allow an escape hatch,
-# for example to build vanilla 2.6.26 with gcc 4.4, which generates
-# warnings in the architecture-independent code.
-config WERROR
- bool "Build the kernel with warnings treated as errors"
- depends on TILERA_MDE
- default y
-
-# Allow checking for compile-time determined overflow errors in
-# copy_from_user(). There are still unprovable places in the
-# generic code as of 2.6.34, so this option is not really compatible
-# with WERROR, which is more useful in general.
-config DEBUG_COPY_FROM_USER
- def_bool n
-
config NR_CPUS
int "Maximum number of tiles (2-255)"
range 2 255
@@ -95,34 +155,6 @@
smaller kernel memory footprint results from using a smaller
value on chips with fewer tiles.

-config HOMECACHE
- bool "Support for dynamic home cache management"
- depends on TILERA_MDE
- ---help---
- Home cache management allows Linux to dynamically adjust
- which core's (or cores') cache is the "home" for every page
- of memory. This allows performance improvements on TILEPro
- (for example, by enabling the default "allbutstack" mode
- where stack pages are always homed on the core running the
- task). TILE64 has less performant cache-coherent support,
- so it is not recommended to disable homecaching for TILE64.
-
-config DATAPLANE
- bool "Support for Zero-Overhead Linux mode"
- depends on SMP
- depends on NO_HZ
- depends on TILERA_MDE
- ---help---
- Zero-Overhead Linux mode, also called "dataplane" mode,
- allows Linux cpus running only a single user task to run
- without any kernel overhead on that cpu. The normal
- scheduler tick is disabled, kernel threads such as the
- softlockup thread are not run, kernel TLB flush IPIs are
- deferred, vmstat updates are not performed, etc.
-
-config SERIAL_CONSOLE
- def_bool y
-
source "kernel/time/Kconfig"

source "kernel/Kconfig.hz"
@@ -188,26 +220,6 @@
By default, 2, i.e. 2^2 == 4 DDR2 controllers.
In a system with more controllers, this value should be raised.

-# FIXME: not yet implemented.
-config HUGETLB_PAGE_SIZE_VARIABLE
- def_bool n
- depends on HUGETLB_PAGE
-
-# This option is not likely to work yet
-config HIGHPTE
- def_bool n
-
-config ARCH_DISCONTIGMEM_ENABLE
- def_bool y
-
-# We do not currently support this, though it would be reasonable
-# with memory striping on TILEPro, or on systems with just one controller.
-config ARCH_FLATMEM_ENABLE
- def_bool n
-
-config ARCH_DISCONTIGMEM_DEFAULT
- def_bool y
-
# Need 16MB areas to enable hugetlb
# See build-time check in arch/tile/mm/init.c.
config FORCE_MAX_ZONEORDER
@@ -215,7 +227,7 @@
default 9

choice
- depends on EXPERIMENTAL
+ depends on !TILEGX
prompt "Memory split" if EMBEDDED
default VMSPLIT_3G
---help---
@@ -304,132 +316,20 @@
This is used to work around broken boot loaders. This should
be set to 'N' under normal conditions.

-config FEEDBACK_COLLECT
- bool "Collect feedback for optimizing the build"
- default n
- ---help---
- This option enables collecting feedback data that can be
- used to optimize a later build of the kernel. The feedback
- data can be read from /proc/tile/feedback.
- See the FEEDBACK_USE option for how to use this data.
-
-config FEEDBACK_USE
- string "Path to file with feedback data to optimize the build"
- default ""
- ---help---
- Supply an absolute path to a feedback data file (as generated
- by tile-convert-feedback) to use for optimizing the kernel.
- See the FEEDBACK_COLLECT option for how to collect this data.
-
-# This is not useful to enable now, since we have no huge-page drivers.
-config NR_HUGE_VMAPS
- int # "Number of huge page addresses reserved for the kernel"
- default 0
- ---help---
- The kernel will reserve address regions for huge pages
- needed by kernel drivers, in much the same way it reserves
- address space for the normal small-page vmalloc subsystem.
- Since the impact on addressable kernel memory is much
- greater, this is broken out as a separate configuration.
-
config VMALLOC_RESERVE
hex
default 0x1000000

-config XGBE_MAIN
- tristate "Tilera GBE/XGBE character device support"
- default y
- depends on HUGETLBFS
- ---help---
- This is the low-level driver for access to xgbe/gbe/pcie.
-
-config NET_TILE
- tristate "Tilera GBE/XGBE network driver support"
- select CRC32
- depends on XGBE_MAIN
- depends on !TILEGX
- ---help---
- This is a standard Linux network device driver for the
- Tilera Gigabit Ethernet and XAUI interfaces.
-
-config NET_TILEGX
- tristate "Tilera GBE/XGBE network driver support"
- select CRC32
- depends on TILEGX
- ---help---
- This is a standard Linux network device driver for the
- Tilera Gigabit Ethernet and XAUI interfaces (mPIPE).
-
-config PSEUDO_NAPI
- boolean "Support optimized kernel API for Tilera network driver"
- default y
- depends on NET_TILE || NET_TILEGX
- depends on TILERA_MDE
- ---help---
- Define this to take turns between grabbing packets and
- processing them. This can easily yield a 20% improvement
- due to reduced interrupts.
-
-config TILEPCI_ENDP
- tristate "Tilera PCIE Endpoint Channel Driver"
- default y
- depends on !TILEGX
- ---help---
- This device is required on Tilera PCI cards; the driver
- allows Tilera Linux on the chip to communicate with the
- Intel Linux running on the host.
-
-config TILE_IDE_GPIO
- bool "Tilera IDE driver for GPIO"
- depends on IDE
- default y
- ---help---
- This device provides an IDE interface using the GPIO pins.
-
-config TILE_SOFTUART
- bool "Tilera Soft UART"
- default n
- depends on !TILEGX
- ---help---
- This device provides access to the FlexIO UART functionality.
- It requires a dedicated hypervisor "softuart" driver tile.
-
endmenu # Tilera-specific configuration

menu "Bus options"

-config PCI
- bool "PCI support"
- default y
- select PCI_DOMAINS
- ---help---
- Enable PCI root complex support, so PCIe endpoint devices can
- be attached to the Tile chip. Many, but not all, PCI devices
- are supported under Tilera's root complex driver.
-
-config PCI_DOMAINS
+config NO_IOMEM
bool
+ def_bool !PCI

source "drivers/pci/Kconfig"

-config HOTPLUG
- bool "Support for hot-pluggable devices"
- ---help---
- Say Y here if you want to plug devices into your computer while
- the system is running, and be able to use them quickly. In many
- cases, the devices can likewise be unplugged at any time too.
-
- One well known example of this is PCMCIA- or PC-cards, credit-card
- size devices such as network cards, modems or hard drives which are
- plugged into slots found on all modern laptop computers. Another
- example, used on modern desktops as well as laptops, is USB.
-
- Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
- software (at <http://linux-hotplug.sourceforge.net/>) and install it.
- Then your kernel will automatically call out to a user mode "policy
- agent" (/sbin/hotplug) to load modules and set up software needed
- to use devices as you hotplug them.
-
source "drivers/pci/hotplug/Kconfig"

endmenu
@@ -458,76 +358,3 @@
source "crypto/Kconfig"

source "lib/Kconfig"
-
-# FIXME: tilegx can implement a more efficent rwsem.
-config RWSEM_GENERIC_SPINLOCK
- def_bool y
-
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
-config GENERIC_IRQ_PROBE
- def_bool y
-
-config GENERIC_PENDING_IRQ
- def_bool y
- depends on GENERIC_HARDIRQS && SMP
-
-config ZONE_DMA
- def_bool y
-
-config SEMAPHORE_SLEEPERS
- def_bool y
-
-config CC_OPTIMIZE_FOR_SIZE
- def_bool y
-
-config RWSEM_GENERIC_SPINLOCK
- def_bool y
-
-config HAVE_ARCH_ALLOC_REMAP
- def_bool y
-
-config HAVE_SETUP_PER_CPU_AREA
- def_bool y
-
-config NEED_PER_CPU_PAGE_FIRST_CHUNK
- def_bool y
-
-config SYS_SUPPORTS_HUGETLBFS
- def_bool y
-
-config GENERIC_TIME
- def_bool y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
-config CLOCKSOURCE_WATCHDOG
- def_bool y
-
-# We have a very flat architecture from a migration point of view,
-# so save boot time by presetting this (particularly useful on tile-sim).
-config DEFAULT_MIGRATION_COST
- int
- default "10000000"
-
-# We only support gcc 4.4 and above, so this should work.
-config ARCH_SUPPORTS_OPTIMIZED_INLINING
- def_bool y
-
-# This may not work out of the box, but it should be easy to make it work.
-config ARCH_SUPPORTS_DEBUG_PAGEALLOC
- def_bool y
-
-config ARCH_PHYS_ADDR_T_64BIT
- def_bool y
-
-# FIXME: Enabling this will allow us to remove the bootmem support,
-# which hackily only works on controller zero at the moment.
-# However, it currently is not supported.
-config NO_BOOTMEM
- def_bool n
diff -ru tile.old/Kconfig.debug tile/Kconfig.debug
--- tile.old/Kconfig.debug 2010-05-28 18:03:30.857289000 -0400
+++ tile/Kconfig.debug 2010-05-28 23:07:04.653422000 -0400
@@ -1,13 +1,7 @@
menu "Kernel hacking"

-config TRACE_IRQFLAGS_SUPPORT
- def_bool y
-
source "lib/Kconfig.debug"

-config STRICT_DEVMEM
- def_bool y
-
config EARLY_PRINTK
bool "Early printk" if EMBEDDED && DEBUG_KERNEL
default y
diff -ru tile.old/Makefile tile/Makefile
--- tile.old/Makefile 2010-05-28 18:03:30.870281000 -0400
+++ tile/Makefile 2010-05-28 23:07:06.121168000 -0400
@@ -8,31 +8,33 @@
# for "archclean" and "archdep" for cleaning up and making dependencies for
# this architecture

+ifeq ($(CROSS_COMPILE),)
+# If building with TILERA_ROOT set (i.e. using the Tilera Multicore
+# Development Environment) we can set CROSS_COMPILE based on that.
ifdef TILERA_ROOT
-TILERA_BIN = $(TILERA_ROOT)/bin/
+CROSS_COMPILE = $(TILERA_ROOT)/bin/tile-
+endif
endif

-# Test for cross compiling
-COMPILE_ARCH = $(shell uname -m)
-ifneq ($(COMPILE_ARCH), $(ARCH))
- CROSS_COMPILE = $(TILERA_BIN)tile-
+# If we're not cross-compiling, make sure we're on the right architecture.
+ifeq ($(CROSS_COMPILE),)
+HOST_ARCH = $(shell uname -m)
+ifneq ($(HOST_ARCH),$(ARCH))
+$(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH))
+endif
endif

-CC = $(CROSS_COMPILE)gcc

-# FIXME: Handle feedback.
-ifeq ($(CONFIG_WERROR),y)
-# We try to keep the builds warning-free.
-KBUILD_CFLAGS += -Werror
-endif
KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS)

-LIBGCC_PATH := `$(CC) -print-libgcc-file-name`
+LIBGCC_PATH := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)

# Provide the path to use for "make defconfig".
KBUILD_DEFCONFIG := $(ARCH)_defconfig

# Used as a file extension when useful, e.g. head_$(BITS).o
+# Not needed for (e.g.) "$(CC) -m32" since the compiler automatically
+# uses the right default anyway.
export BITS
ifeq ($(CONFIG_TILEGX),y)
BITS := 64
@@ -45,24 +47,6 @@
libs-y += arch/tile/lib/
libs-y += $(LIBGCC_PATH)

+
# See arch/tile/Kbuild for content of core part of the kernel
core-y += arch/tile/
-
-drivers-y += arch/tile/drivers/
-drivers-y += arch/tile/oprofile/
-
-boot := arch/tile/boot
-
-all: vmlinux
-
-CLEAN_FILES += arch/tile/vmlinux.lds
-
-install: vmlinux
-ifeq ($(COMPILE_ARCH), $(ARCH))
- cp $< $(INSTALL_PATH)
-else
-ifndef TILERA_ROOT
-$(error Must set TILERA_ROOT to do a cross-install)
-endif
- cp $< $(TILERA_ROOT)/tile$(INSTALL_PATH)
-endif
diff -ru tile.old/configs/tile_defconfig tile/configs/tile_defconfig
--- tile.old/configs/tile_defconfig 2010-05-28 18:03:30.889258000 -0400
+++ tile/configs/tile_defconfig 2010-05-28 22:57:14.692455000 -0400
@@ -1,15 +1,42 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.34-rc7
-# Thu May 13 11:56:25 2010
+# Linux kernel version: 2.6.34
+# Fri May 28 17:51:43 2010
#
-CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+CONFIG_WERROR=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_HVC_TILE=y
CONFIG_TILE=y
# CONFIG_TILEGX is not set
CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
-CONFIG_MMU=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
CONFIG_CONSTRUCTORS=y

@@ -59,7 +86,6 @@
# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
# CONFIG_INITRAMFS_COMPRESSION_LZO is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
CONFIG_EMBEDDED=y
@@ -98,7 +124,6 @@
#
# GCOV-based kernel profiling
#
-# CONFIG_GCOV_KERNEL is not set
# CONFIG_SLOW_WORK is not set
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_SLABINFO=y
@@ -159,14 +184,9 @@
#
# Tilera-specific configuration
#
-CONFIG_TILERA_MDE=y
-CONFIG_SMP=y
-CONFIG_WERROR=y
-# CONFIG_DEBUG_COPY_FROM_USER is not set
CONFIG_NR_CPUS=64
CONFIG_HOMECACHE=y
CONFIG_DATAPLANE=y
-CONFIG_SERIAL_CONSOLE=y
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -181,11 +201,6 @@
CONFIG_HIGHMEM=y
CONFIG_NUMA=y
CONFIG_NODES_SHIFT=2
-# CONFIG_HUGETLB_PAGE_SIZE_VARIABLE is not set
-# CONFIG_HIGHPTE is not set
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-# CONFIG_ARCH_FLATMEM_ENABLE is not set
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
CONFIG_FORCE_MAX_ZONEORDER=9
# CONFIG_VMSPLIT_375G is not set
# CONFIG_VMSPLIT_35G is not set
@@ -213,8 +228,10 @@
# CONFIG_CMDLINE_BOOL is not set
# CONFIG_FEEDBACK_COLLECT is not set
CONFIG_FEEDBACK_USE=""
-CONFIG_NR_HUGE_VMAPS=0
+# CONFIG_HUGEVMAP is not set
CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_MEMPROF=y
CONFIG_XGBE_MAIN=y
CONFIG_NET_TILE=y
CONFIG_PSEUDO_NAPI=y
@@ -714,6 +731,7 @@
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
+CONFIG_HVC_DRIVER=y
# CONFIG_IPMI_HANDLER is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_R3964 is not set
@@ -724,7 +742,6 @@
#
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
-CONFIG_DEVPORT=y
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_COMPAT=y
@@ -929,7 +946,6 @@
# CONFIG_EXT3_FS_SECURITY is not set
# CONFIG_EXT4_FS is not set
CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
@@ -1072,7 +1088,6 @@
#
# Kernel hacking
#
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
@@ -1116,16 +1131,14 @@
# CONFIG_DEBUG_SG is not set
# CONFIG_DEBUG_NOTIFIERS is not set
# CONFIG_DEBUG_CREDENTIALS is not set
-# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-# CONFIG_LKDTM is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_SYSCTL_SYSCALL_CHECK is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_PAGE_POISONING is not set
CONFIG_RING_BUFFER=y
CONFIG_RING_BUFFER_ALLOW_SWAP=y
CONFIG_TRACING_SUPPORT=y
@@ -1141,9 +1154,7 @@
# CONFIG_WORKQUEUE_TRACER is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_RING_BUFFER_BENCHMARK is not set
-# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_SAMPLES is not set
-CONFIG_STRICT_DEVMEM=y
CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
@@ -1276,22 +1287,3 @@
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_NLATTR=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_PENDING_IRQ=y
-CONFIG_ZONE_DMA=y
-CONFIG_SEMAPHORE_SLEEPERS=y
-CONFIG_HAVE_ARCH_ALLOC_REMAP=y
-CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-CONFIG_SYS_SUPPORTS_HUGETLBFS=y
-CONFIG_GENERIC_TIME=y
-CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_CLOCKSOURCE_WATCHDOG=y
-CONFIG_DEFAULT_MIGRATION_COST=10000000
-CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
-CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-# CONFIG_NO_BOOTMEM is not set
Only in tile.old: drivers
Only in tile.old: feedback
diff -ru tile.old/include/arch/abi.h tile/include/arch/abi.h
--- tile.old/include/arch/abi.h 2010-05-28 18:03:31.579736000 -0400
+++ tile/include/arch/abi.h 2010-05-28 23:07:05.843397000 -0400
@@ -76,7 +76,7 @@
//! String prefix to use for printf().
#define INT_REG_FMT "ll"

-#else
+#elif !defined(__LP64__) /* avoid confusion with LP64 cross-build tools */

//! Unsigned type that can hold a register.
typedef unsigned long uint_reg_t;
diff -ru tile.old/include/arch/chip.h tile/include/arch/chip.h
--- tile.old/include/arch/chip.h 2010-05-28 18:03:31.588724000 -0400
+++ tile/include/arch/chip.h 2010-05-28 23:07:04.781288000 -0400
@@ -16,8 +16,8 @@
#include <arch/chip_tile64.h>
#elif __tile_chip__ == 1
#include <arch/chip_tilepro.h>
-
-
+#elif defined(__tilegx__)
+#include <arch/chip_tilegx.h>
#else
#error Unexpected Tilera chip type
#endif
diff -ru tile.old/include/arch/chip_tile64.h tile/include/arch/chip_tile64.h
--- tile.old/include/arch/chip_tile64.h 2010-05-28 18:03:31.600712000 -0400
+++ tile/include/arch/chip_tile64.h 2010-05-28 23:07:05.863374000 -0400
@@ -193,60 +193,60 @@
/** Does the chip have native single step support? */
#define CHIP_HAS_SINGLE_STEP() 0

+#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */

+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 8

+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 16

+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 16

+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 1

+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 0

+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 0

+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 0

+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 0

+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 0

+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 0

+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 0

+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0

+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 0

+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 0

+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 0

+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0

+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 0

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#endif /* !__OPEN_SOURCE__ */
#endif /* __ARCH_CHIP_H__ */
diff -ru tile.old/include/arch/chip_tilepro.h tile/include/arch/chip_tilepro.h
--- tile.old/include/arch/chip_tilepro.h 2010-05-28 18:03:31.609701000 -0400
+++ tile/include/arch/chip_tilepro.h 2010-05-28 23:07:05.851404000 -0400
@@ -193,60 +193,60 @@
/** Does the chip have native single step support? */
#define CHIP_HAS_SINGLE_STEP() 0

+#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */

+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 16

+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 16

+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 32

+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 0

+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1

+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 1

+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1

+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 1

+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 1

+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1

+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1

+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 1

+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 1

+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 1

+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 1

+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 1

+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 1

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#endif /* !__OPEN_SOURCE__ */
#endif /* __ARCH_CHIP_H__ */
Only in tile.old/include/arch: cycle.h
Only in tile.old/include/arch: inline.h
diff -ru tile.old/include/arch/interrupts.h tile/include/arch/interrupts.h
--- tile.old/include/arch/interrupts.h 2010-05-28 18:03:31.645675000 -0400
+++ tile/include/arch/interrupts.h 2010-05-28 23:07:04.742333000 -0400
@@ -12,7 +12,8 @@
* more details.
*/

-
-
-
+#ifdef __tilegx__
+#include <arch/interrupts_64.h>
+#else
#include <arch/interrupts_32.h>
+#endif
Only in tile.old/include/arch: sim.h
diff -ru tile.old/include/arch/spr_def.h tile/include/arch/spr_def.h
--- tile.old/include/arch/spr_def.h 2010-05-28 18:03:31.718596000 -0400
+++ tile/include/arch/spr_def.h 2010-05-28 23:07:04.778296000 -0400
@@ -12,7 +12,8 @@
* more details.
*/

-
-
-
+#ifdef __tilegx__
+#include <arch/spr_def_64.h>
+#else
#include <arch/spr_def_32.h>
+#endif
diff -ru tile.old/include/asm/Kbuild tile/include/asm/Kbuild
--- tile.old/include/asm/Kbuild 2010-05-28 18:03:31.751566000 -0400
+++ tile/include/asm/Kbuild 2010-05-28 23:07:06.106169000 -0400
@@ -1,17 +1,3 @@
include include/asm-generic/Kbuild.asm

-header-y += hardwall.h
-header-y += memprof.h
header-y += ucontext.h
-header-y += user.h
-
-unifdef-y += bme.h
-unifdef-y += page.h
-unifdef-y += tilepci.h
-
-# FIXME: The kernel probably shouldn't provide these to user-space,
-# but it's convenient for now to do so.
-unifdef-y += opcode-tile.h
-unifdef-y += opcode_constants.h
-unifdef-y += opcode-tile_32.h
-unifdef-y += opcode_constants_32.h
Only in tile.old/include/asm: a.out.h
Only in tile.old/include/asm: addrspace.h
Only in tile.old/include/asm: asm.h
diff -ru tile.old/include/asm/atomic.h tile/include/asm/atomic.h
--- tile.old/include/asm/atomic.h 2010-05-28 18:03:31.793516000 -0400
+++ tile/include/asm/atomic.h 2010-05-28 23:07:05.209010000 -0400
@@ -145,11 +145,11 @@

#endif /* __ASSEMBLY__ */

-
+#ifndef __tilegx__
#include <asm/atomic_32.h>
-
-
-
+#else
+#include <asm/atomic_64.h>
+#endif

/* Provide the appropriate atomic_long_t definitions. */
#ifndef __ASSEMBLY__
diff -ru tile.old/include/asm/backtrace.h tile/include/asm/backtrace.h
--- tile.old/include/asm/backtrace.h 2010-05-28 18:03:31.825489000 -0400
+++ tile/include/asm/backtrace.h 2010-05-28 23:07:05.990252000 -0400
@@ -15,18 +15,9 @@
#ifndef _TILE_BACKTRACE_H
#define _TILE_BACKTRACE_H

-#ifndef _LANGUAGE_ASSEMBLY

-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */

-#ifdef __KERNEL__
#include <linux/types.h>
-#else
-#include <stdint.h>
-#include <stdbool.h>
-#endif

#include <arch/chip.h>

@@ -197,22 +188,6 @@
} CallerLocation;


-#ifdef __cplusplus
-} /* extern "C" */
-#endif /* __cplusplus */
-
-#else /* __ASSEMBLY__ */
-
-/* BacktraceIterator offsets */
-#define BACKTRACE_ITERATOR_SIZE 24
-
-#define BACKTRACE_ITERATOR_PC_OFFSET 0
-#define BACKTRACE_ITERATOR_SP_OFFSET 4
-#define BACKTRACE_ITERATOR_FP_OFFSET 8
-#define BACKTRACE_ITERATOR_INITIAL_FRAME_CALLER_PC 12
-#define BACKTRACE_ITERATOR_READ_MEMORY_FUNC 16
-#define BACKTRACE_ITERATOR_READ_MEMORY_FUNC_EXTRA 20

-#endif /* __ASSEMBLY__ */

#endif /* _TILE_BACKTRACE_H */
diff -ru tile.old/include/asm/bitops.h tile/include/asm/bitops.h
--- tile.old/include/asm/bitops.h 2010-05-28 18:03:31.841470000 -0400
+++ tile/include/asm/bitops.h 2010-05-28 23:07:05.260975000 -0400
@@ -22,11 +22,11 @@
#error only <linux/bitops.h> can be included directly
#endif

-
-
-
+#ifdef __tilegx__
+#include <asm/bitops_64.h>
+#else
#include <asm/bitops_32.h>
-
+#endif

/**
* __ffs - find first set bit in word
diff -ru tile.old/include/asm/bitsperlong.h tile/include/asm/bitsperlong.h
--- tile.old/include/asm/bitsperlong.h 2010-05-28 18:03:31.862457000 -0400
+++ tile/include/asm/bitsperlong.h 2010-05-28 23:07:05.262991000 -0400
@@ -15,11 +15,11 @@
#ifndef _ASM_TILE_BITSPERLONG_H
#define _ASM_TILE_BITSPERLONG_H

-
-
-
+#ifdef __LP64__
+# define __BITS_PER_LONG 64
+#else
# define __BITS_PER_LONG 32
-
+#endif

#include <asm-generic/bitsperlong.h>

Only in tile.old/include/asm: bme.h
diff -ru tile.old/include/asm/bugs.h tile/include/asm/bugs.h
--- tile.old/include/asm/bugs.h 2010-05-28 18:03:31.886439000 -0400
+++ tile/include/asm/bugs.h 2010-05-28 23:07:05.271964000 -0400
@@ -1,22 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_BUGS_H
-#define _ASM_TILE_BUGS_H
-
-static inline void check_bugs(void)
-{
-}
-
-#endif /* _ASM_TILE_BUGS_H */
+#include <asm-generic/bugs.h>
diff -ru tile.old/include/asm/byteorder.h tile/include/asm/byteorder.h
--- tile.old/include/asm/byteorder.h 2010-05-28 18:03:31.905415000 -0400
+++ tile/include/asm/byteorder.h 2010-05-28 23:07:05.275961000 -0400
@@ -1,20 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_BYTEORDER_H
-#define _ASM_TILE_BYTEORDER_H
-
#include <linux/byteorder/little_endian.h>
-
-#endif /* _ASM_TILE_BYTEORDER_H */
diff -ru tile.old/include/asm/checksum.h tile/include/asm/checksum.h
--- tile.old/include/asm/checksum.h 2010-05-28 18:03:31.945371000 -0400
+++ tile/include/asm/checksum.h 2010-05-28 23:07:05.310928000 -0400
@@ -15,106 +15,10 @@
#ifndef _ASM_TILE_CHECKSUM_H
#define _ASM_TILE_CHECKSUM_H

-#include <linux/in6.h>
-#include <linux/uaccess.h>
+#include <asm-generic/checksum.h>

-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- * the same as csum_partial, but copies from src while it checksums.
- */
-__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum);
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums, and handles user-space pointer exceptions correctly, when needed.
- *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
- */
-
-__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
- int len, __wsum sum, int *err_ptr);
-
-/*
- * Note: when you get a NULL pointer exception here this means someone
- * passed in an incorrect kernel address to one of these functions.
- *
- * If you use these functions directly please don't forget the
- * access_ok().
- */
-static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst,
- int len, __wsum sum)
-{
- return csum_partial_copy(src, dst, len, sum);
-}
-
-/*
- * Fold a partial checksum
- */
-
-static inline __sum16 csum_fold(__wsum sum)
-{
- /* Add up 16-bit and 16-bit for 16+c bit, then add up carry. */
- unsigned long ret;
-
-
-
-
- ret = __insn_sadh_u(sum, 0);
- ret = __insn_sadh_u(ret, 0);
-
- return (__force __sum16) ~ret;
-}
-
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
-
-static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
-{
- u64 value = sum;
- value += (u32) saddr;
- value += (u32) daddr;
- value += (u32) ((ntohs(len) << 16) + (proto << 8));
- value = (value & 0xffffffff) + (value >> 32);
- value = (value & 0xffffffff) + (value >> 32);
- return (__wsum) value;
-}
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
- unsigned short len,
- unsigned short proto,
- __wsum sum)
-{
- return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
-}
-
-/*
- * this routine is used for miscellaneous IP-like checksums, mainly
- * in icmp.c
- */
-
-static inline __sum16 ip_compute_csum(const void *buff, int len)
-{
- return csum_fold(csum_partial(buff, len, 0));
-}
+/* Allow us to provide a more optimized do_csum(). */
+__wsum do_csum(const unsigned char *buff, int len);
+#define do_csum do_csum

#endif /* _ASM_TILE_CHECKSUM_H */
diff -ru tile.old/include/asm/compat.h tile/include/asm/compat.h
--- tile.old/include/asm/compat.h 2010-05-28 18:03:31.947365000 -0400
+++ tile/include/asm/compat.h 2010-05-28 23:07:05.352898000 -0400
@@ -78,14 +78,16 @@
unsigned int st_uid;
unsigned int st_gid;
unsigned int st_rdev;
+ unsigned int __pad1;
int st_size;
- unsigned int st_blksize;
- unsigned int st_blocks;
- unsigned int st_atime;
+ int st_blksize;
+ int __pad2;
+ int st_blocks;
+ int st_atime;
unsigned int st_atime_nsec;
- unsigned int st_mtime;
+ int st_mtime;
unsigned int st_mtime_nsec;
- unsigned int st_ctime;
+ int st_ctime;
unsigned int st_ctime_nsec;
unsigned int __unused[2];
};
@@ -249,4 +251,58 @@
siginfo_t *info, sigset_t *set,
struct pt_regs *regs);

+/* Compat syscalls. */
+struct compat_sigaction;
+struct compat_siginfo;
+struct compat_sigaltstack;
+long compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp);
+long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
+ struct compat_sigaction __user *oact,
+ size_t sigsetsize);
+long compat_sys_rt_sigqueueinfo(int pid, int sig,
+ struct compat_siginfo __user *uinfo);
+long compat_sys_rt_sigreturn(void);
+long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr);
+long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
+long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
+long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high);
+long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high);
+long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len);
+long compat_sys_sync_file_range2(int fd, unsigned int flags,
+ u32 offset_lo, u32 offset_hi,
+ u32 nbytes_lo, u32 nbytes_hi);
+long compat_sys_fallocate(int fd, int mode,
+ u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi);
+long compat_sys_stat64(char __user *filename,
+ struct compat_stat64 __user *statbuf);
+long compat_sys_lstat64(char __user *filename,
+ struct compat_stat64 __user *statbuf);
+long compat_sys_fstat64(unsigned int fd, struct compat_stat64 __user *statbuf);
+long compat_sys_fstatat64(int dfd, char __user *filename,
+ struct compat_stat64 __user *statbuf, int flag);
+long compat_sys_sched_rr_get_interval(compat_pid_t pid,
+ struct compat_timespec __user *interval);
+ssize_t compat_sys_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
+ size_t count);
+
+/* Versions of compat functions that differ from generic Linux. */
+struct compat_msgbuf;
+long tile_compat_sys_msgsnd(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, int msgflg);
+long tile_compat_sys_msgrcv(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, long msgtyp, int msgflg);
+long tile_compat_sys_ptrace(compat_long_t request, compat_long_t pid,
+ compat_long_t addr, compat_long_t data);
+
+/* Tilera Linux syscalls that don't have "compat" versions. */
+#define compat_sys_raise_fpe sys_raise_fpe
+#define compat_sys_flush_cache sys_flush_cache
+
#endif /* _ASM_TILE_COMPAT_H */
diff -ru tile.old/include/asm/delay.h tile/include/asm/delay.h
--- tile.old/include/asm/delay.h 2010-05-28 18:03:31.966351000 -0400
+++ tile/include/asm/delay.h 2010-05-28 23:07:05.330909000 -0400
@@ -15,8 +15,6 @@
#ifndef _ASM_TILE_DELAY_H
#define _ASM_TILE_DELAY_H

-#include <arch/cycle.h>
-
/* Undefined functions to get compile-time errors. */
extern void __bad_udelay(void);
extern void __bad_ndelay(void);
@@ -33,26 +31,4 @@
((n) > 20000 ? __bad_ndelay() : __ndelay(n)) : \
__ndelay(n))

-/*
- * Our stall mechanism is an instruction that takes 6 cycles, and
- * looping around it takes 8.
- */
-#define CYCLES_PER_RELAX_LOOP 8
-
-/*
- * Idle the core for 8 * iterations cycles.
- * Also make this a compiler barrier, as it's sometimes used in
- * lieue of cpu_relax(), which has barrier semantics.
- */
-static inline void
-relax(int iterations)
-{
- for (/*above*/; iterations > 0; iterations--)
- cycle_relax();
- barrier();
-}
-
-/* Delay using bounded exponential backoff. */
-extern void delay_backoff(int iterations);
-
#endif /* _ASM_TILE_DELAY_H */
diff -ru tile.old/include/asm/dma-mapping.h tile/include/asm/dma-mapping.h
--- tile.old/include/asm/dma-mapping.h 2010-05-28 18:03:31.979338000 -0400
+++ tile/include/asm/dma-mapping.h 2010-05-28 23:07:05.347888000 -0400
@@ -59,35 +59,17 @@
void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle);

-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
- enum dma_data_direction direction)
-{
- panic("dma_sync_single_for_cpu");
-}
-
-static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
- size_t size, enum dma_data_direction direction)
-{
- panic("dma_sync_single_for_device");
-}
-
-static inline void
-dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
- unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- panic("dma_sync_single_range_for_cpu");
-}
-
-static inline void
-dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
- unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- panic("dma_sync_single_range_for_device");
-}
+extern void dma_sync_single_for_cpu(struct device *, dma_addr_t, size_t,
+ enum dma_data_direction);
+extern void dma_sync_single_for_device(struct device *, dma_addr_t,
+ size_t, enum dma_data_direction);
+extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
+ unsigned long offset, size_t,
+ enum dma_data_direction);
+extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
+ unsigned long offset, size_t,
+ enum dma_data_direction);
+extern void dma_cache_sync(void *vaddr, size_t, enum dma_data_direction);

static inline int
dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
@@ -120,11 +102,5 @@

#define dma_is_consistent(d, h) (1)

-static inline void
-dma_cache_sync(void *vaddr, size_t size,
- enum dma_data_direction direction)
-{
- panic("dma_cache_sync");
-}

#endif /* _ASM_TILE_DMA_MAPPING_H */
diff -ru tile.old/include/asm/dma.h tile/include/asm/dma.h
--- tile.old/include/asm/dma.h 2010-05-28 18:03:31.982327000 -0400
+++ tile/include/asm/dma.h 2010-05-28 23:07:05.362870000 -0400
@@ -15,20 +15,11 @@
#ifndef _ASM_TILE_DMA_H
#define _ASM_TILE_DMA_H

-#include <asm/page.h>
-
-#define MAX_DMA_ADDRESS ((unsigned long)high_memory - 1)
-
-/* Reserve a DMA channel. */
-extern int request_dma(unsigned int dmanr, const char *device_id);
-
-/* Release it again. */
-extern void free_dma(unsigned int dmanr);
+#include <asm-generic/dma.h>

+/* Needed by drivers/pci/quirks.c */
#ifdef CONFIG_PCI
extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy (0)
#endif

#endif /* _ASM_TILE_DMA_H */
diff -ru tile.old/include/asm/elf.h tile/include/asm/elf.h
--- tile.old/include/asm/elf.h 2010-05-28 18:03:31.988338000 -0400
+++ tile/include/asm/elf.h 2010-05-28 23:07:05.361880000 -0400
@@ -39,11 +39,11 @@
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];

-
-
-
+#ifdef __tilegx__
+#define ELF_CLASS ELFCLASS64
+#else
#define ELF_CLASS ELFCLASS32
-
+#endif
#define ELF_DATA ELFDATA2LSB

/*
@@ -63,23 +63,23 @@
(x)->e_machine == CHIP_COMPAT_ELF_TYPE()))

/* The module loader only handles a few relocation types. */
-
+#ifndef __tilegx__
#define R_TILE_32 1
#define R_TILE_JOFFLONG_X1 15
#define R_TILE_IMM16_X0_LO 25
#define R_TILE_IMM16_X1_LO 26
#define R_TILE_IMM16_X0_HA 29
#define R_TILE_IMM16_X1_HA 30
-
-
-
-
-
-
-
-
-
-
+#else
+#define R_TILEGX_64 1
+#define R_TILEGX_JUMPOFF_X1 21
+#define R_TILEGX_IMM16_X0_HW0 36
+#define R_TILEGX_IMM16_X1_HW0 37
+#define R_TILEGX_IMM16_X0_HW1 38
+#define R_TILEGX_IMM16_X1_HW1 39
+#define R_TILEGX_IMM16_X0_HW2_LAST 48
+#define R_TILEGX_IMM16_X1_HW2_LAST 49
+#endif

/* Use standard page size for core dumps. */
#define ELF_EXEC_PAGESIZE PAGE_SIZE
@@ -120,8 +120,6 @@
extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)

-#ifdef __KERNEL__
-
/* Tilera Linux has no personalities currently, so no need to do anything. */
#define SET_PERSONALITY(ex) do { } while (0)

@@ -130,8 +128,6 @@
struct linux_binprm;
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
int executable_stack);
-#endif
-
#ifdef CONFIG_COMPAT

#define COMPAT_ELF_PLATFORM "tilegx-m32"
diff -ru tile.old/include/asm/futex.h tile/include/asm/futex.h
--- tile.old/include/asm/futex.h 2010-05-28 18:03:32.050266000 -0400
+++ tile/include/asm/futex.h 2010-05-28 23:07:05.387861000 -0400
@@ -23,7 +23,6 @@
#ifndef _ASM_TILE_FUTEX_H
#define _ASM_TILE_FUTEX_H

-#ifdef __KERNEL__
#ifndef __ASSEMBLY__

#include <linux/futex.h>
@@ -36,23 +35,23 @@
extern struct __get_user futex_andn(int *v, int n);
extern struct __get_user futex_cmpxchg(int *v, int o, int n);

-
+#ifndef __tilegx__
extern struct __get_user futex_xor(int *v, int n);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#else
+static inline struct __get_user futex_xor(int __user *uaddr, int n)
+{
+ struct __get_user asm_ret = __get_user_4(uaddr);
+ if (!asm_ret.err) {
+ int oldval, newval;
+ do {
+ oldval = asm_ret.val;
+ newval = oldval ^ n;
+ asm_ret = futex_cmpxchg(uaddr, oldval, newval);
+ } while (asm_ret.err == 0 && oldval != asm_ret.val);
+ }
+ return asm_ret;
+}
+#endif

static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
{
@@ -134,6 +133,4 @@

#endif /* !__ASSEMBLY__ */

-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_FUTEX_H */
Only in tile.old/include/asm: hardwall.h
diff -ru tile.old/include/asm/highmem.h tile/include/asm/highmem.h
--- tile.old/include/asm/highmem.h 2010-05-28 18:03:32.092272000 -0400
+++ tile/include/asm/highmem.h 2010-05-28 23:07:05.390850000 -0400
@@ -21,8 +21,6 @@
#ifndef _ASM_TILE_HIGHMEM_H
#define _ASM_TILE_HIGHMEM_H

-#ifdef __KERNEL__
-
#include <linux/interrupt.h>
#include <linux/threads.h>
#include <asm/kmap_types.h>
@@ -72,6 +70,4 @@

#define flush_cache_kmaps() do { } while (0)

-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_HIGHMEM_H */
diff -ru tile.old/include/asm/homecache.h tile/include/asm/homecache.h
--- tile.old/include/asm/homecache.h 2010-05-28 18:03:32.095262000 -0400
+++ tile/include/asm/homecache.h 2010-05-28 23:07:05.422818000 -0400
@@ -104,131 +104,11 @@
* routines use homecache_change_page_home() to reset the home
* back to the default before returning the page to the allocator.
*/
-#ifdef CONFIG_HOMECACHE
-#define homecache_free_pages(addr, order) free_pages(addr, order)
-#else
void homecache_free_pages(unsigned long addr, unsigned int order);
-#endif
#define homecache_free_page(page) \
homecache_free_pages((page), 0)


-#ifdef CONFIG_HOMECACHE
-
-/* Get home cache of a page. */
-#define page_home(page) ((page)->home)
-
-/* Set home cache of a page. */
-#define set_page_home(page, _home) \
- do { \
- int __home = (_home); \
- BUG_ON(__home <= PAGE_HOME_UNKNOWN || __home >= NR_CPUS); \
- (page)->home = __home; \
- } while (0)
-
-/*
- * Allocate a page intended for user-space with suitable homecaching.
- */
-struct page *homecache_alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma,
- unsigned long addr);
-
-/*
- * Regenerate a PTE that has been migrated by taking the vm_page_prot
- * values for caching and the PTE's own read/write/access/dirty bits,
- * then rewriting the PTE. This will cause various components (e.g.
- * the home, whether it's coherent, etc.) to be filled in correctly.
- * In addition, reset the PTE to match the page.
- */
-extern void homecache_update_migrating_pte(struct page *, pte_t *,
- struct vm_area_struct *,
- unsigned long address);
-
-/*
- * Make a freshly-allocated page be homed on the current cpu,
- * or some other home if requested by homecache_alloc_pages() et al.
- * If the page is unsuitable for allocation (e.g. it is cached on
- * a dataplane tile and some other tile is requesting it) we return
- * "1" and sequester the page just like homecache_check_free_page().
- */
-extern int homecache_new_kernel_page(struct page *, int order);
-
-/*
- * Called by the page_alloc allocation code prior to checking the
- * per-cpu free lists. If there's a hit for the type of page that
- * we're currently looking for here, we return that page and
- * short-circuit any futher allocation work.
- * Must be called with interrupts disabled.
- */
-extern struct page *homecache_get_cached_page(struct zone *zone, int gfpflags);
-
-/*
- * Called by the page_alloc free code when just about to return a page
- * to the free pool. If it returns "1", the generic code does not
- * return the page to the free pool.
- */
-extern int homecache_check_free_page(struct page *, int order);
-
-/*
- * Report the number of pages sequestered by homecache_new_kernel_page()
- * or homecache_check_free_page().
- */
-extern long homecache_count_sequestered_pages(void);
-
-/*
- * Recover any free pages that were sequestered by homecache_free_page()
- * by doing a global cache flush and returning them to the free pool.
- * Called from the page allocator when free pool is empty.
- */
-extern int homecache_recover_free_pages(void);
-
-/*
- * Take a user page and try to associate it with the current cpu.
- * Called from do_wp_page() when un-cow'ing a page with only one reference.
- * The page must be locked.
- */
-extern void homecache_home_page_here(struct page *, int order, pgprot_t);
-
-/*
- * Update caching to match a pgprot, and unmap any other mappings of
- * this page in other address spaces. Called when we are mapping a page
- * into an address space, before any page table locks are taken.
- * If the page is a file mapping with no shared writers and we are setting
- * up a read-only mapping, we ignore vm_page_prot and make it immutable.
- * The page must be locked.
- */
-extern void homecache_update_page(struct page *, int order,
- struct vm_area_struct *, int writable);
-
-/*
- * Make an immutable page writable by giving it default cache homing.
- * This may only last as long as it takes to complete the action
- * (e.g. page writeout) that required it to be locked in the first place,
- * since if the page is mapped not shared-writable it will be reset to
- * immutable when the page gets faulted back in again.
- * The page must be locked.
- */
-extern void homecache_make_writable(struct page *page, int order);
-
-/*
- * Fix the caching on a new page that we are about to map into user space.
- * The page is freshly-allocated, so should not be locked.
- * This is currently only used by the hugepage code; small pages
- * come through homecache_alloc_page_vma().
- */
-extern void homecache_new_user_page(struct page *, int order,
- pgprot_t prot, int writable);
-
-/* Migrate the current user-space process to the current cpu. */
-extern void homecache_migrate(void);
-
-/* Migrate the current kernel thread to the current cpu. */
-extern void homecache_migrate_kthread(void);
-
-/* Acquire/release the lock needed to create new kernel PTE mappings. */
-extern unsigned long homecache_kpte_lock(void);
-extern void homecache_kpte_unlock(unsigned long);
-
-#else

/*
* Report the page home for LOWMEM pages by examining their kernel PTE,
@@ -241,6 +121,5 @@
#define homecache_kpte_lock() 0
#define homecache_kpte_unlock(flags) do {} while (0)

-#endif /* CONFIG_HOMECACHE */

#endif /* _ASM_TILE_HOMECACHE_H */
Only in tile.old/include/asm: hugevmap.h
diff -ru tile.old/include/asm/hv_driver.h tile/include/asm/hv_driver.h
--- tile.old/include/asm/hv_driver.h 2010-05-28 18:03:32.128265000 -0400
+++ tile/include/asm/hv_driver.h 2010-05-28 23:07:05.423818000 -0400
@@ -20,7 +20,6 @@
#ifndef _ASM_TILE_HV_DRIVER_H
#define _ASM_TILE_HV_DRIVER_H

-#ifdef __KERNEL__
#include <hv/hypervisor.h>

struct hv_driver_cb;
@@ -58,6 +57,4 @@
}


-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_HV_DRIVER_H */
diff -ru tile.old/include/asm/ide.h tile/include/asm/ide.h
--- tile.old/include/asm/ide.h 2010-05-28 18:03:32.141263000 -0400
+++ tile/include/asm/ide.h 2010-05-28 23:07:05.447794000 -0400
@@ -15,8 +15,6 @@
#ifndef _ASM_TILE_IDE_H
#define _ASM_TILE_IDE_H

-#ifdef __KERNEL__
-
/* For IDE on PCI */
#define MAX_HWIFS 10

@@ -24,6 +22,4 @@

#include <asm-generic/ide_iops.h>

-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_IDE_H */
diff -ru tile.old/include/asm/io.h tile/include/asm/io.h
--- tile.old/include/asm/io.h 2010-05-28 18:03:32.144265000 -0400
+++ tile/include/asm/io.h 2010-05-28 23:07:05.447788000 -0400
@@ -37,22 +37,34 @@
*/
#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)

-#define readb_relaxed(a) readb(a)
-#define readw_relaxed(a) readw(a)
-#define readl_relaxed(a) readl(a)
-#define readq_relaxed(a) readq(a)
+/*
+ * Some places try to pass in an loff_t for PHYSADDR (?!), so we cast it to
+ * long before casting it to a pointer to avoid compiler warnings.
+ */
+#if CHIP_HAS_MMIO()
+extern void __iomem *ioremap(resource_size_t offset, unsigned long size);
+extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
+ pgprot_t pgprot);
+extern void iounmap(volatile void __iomem *addr);
+#else
+#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr))
+#define iounmap(addr) ((void)0)
+#endif

-#ifdef CONFIG_PCI
+#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
+#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)

-#define readb(addr) _tile_readb((unsigned long)addr)
-#define readw(addr) _tile_readw((unsigned long)addr)
-#define readl(addr) _tile_readl((unsigned long)addr)
-#define readq(addr) _tile_readq((unsigned long)addr)
+void __iomem *ioport_map(unsigned long port, unsigned int len);
+extern inline void ioport_unmap(void __iomem *addr) {}

-#define writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
-#define writew(val, addr) _tile_writew(val, (unsigned long)addr)
-#define writel(val, addr) _tile_writel(val, (unsigned long)addr)
-#define writeq(val, addr) _tile_writeq(val, (unsigned long)addr)
+#define mmiowb()
+
+/* Conversion between virtual and physical mappings. */
+#define mm_ptov(addr) ((void *)phys_to_virt(addr))
+#define mm_vtop(addr) ((unsigned long)virt_to_phys(addr))
+
+#ifdef CONFIG_PCI

extern u8 _tile_readb(unsigned long addr);
extern u16 _tile_readw(unsigned long addr);
@@ -63,43 +75,14 @@
extern void _tile_writel(u32 val, unsigned long addr);
extern void _tile_writeq(u64 val, unsigned long addr);

-extern u32 inb(u32 addr);
-extern u32 inw(u32 addr);
-extern u32 inl(u32 addr);
-extern void outb(u32 val, u32 addr);
-extern void outw(u32 val, u32 addr);
-extern void outl(u32 val, u32 addr);
-
-#else
-
-#define readb(addr) \
- ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
-#define readw(addr) \
- ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
-#define readl(addr) \
- ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-#define readq(addr) \
- ({ unsigned long long __v = (*(volatile unsigned long long *)(addr)); __v; })
-
-#define writeb(val, addr) \
- (void)((*(volatile unsigned char *) (addr)) = (val))
-#define writew(val, addr) \
- (void)((*(volatile unsigned short *) (addr)) = (val))
-#define writel(val, addr) \
- (void)((*(volatile unsigned int *) (addr)) = (val))
-#define writeq(val, addr) \
- (void)((*(volatile unsigned long long *) (addr)) = (val))
-
-#define inb(addr) readb(addr)
-#define inw(addr) readw(addr)
-#define inl(addr) readl(addr)
-#define inq(addr) readq(addr)
-#define outb(x, addr) ((void)writeb((x), (addr)))
-#define outw(x, addr) ((void)writew((x), (addr)))
-#define outl(x, addr) ((void)writel((x), (addr)))
-#define outq(x, addr) ((void)writeq((x), (addr)))
-
-#endif
+#define readb(addr) _tile_readb((unsigned long)addr)
+#define readw(addr) _tile_readw((unsigned long)addr)
+#define readl(addr) _tile_readl((unsigned long)addr)
+#define readq(addr) _tile_readq((unsigned long)addr)
+#define writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
+#define writew(val, addr) _tile_writew(val, (unsigned long)addr)
+#define writel(val, addr) _tile_writel(val, (unsigned long)addr)
+#define writeq(val, addr) _tile_writeq(val, (unsigned long)addr)

#define __raw_readb readb
#define __raw_readw readw
@@ -110,117 +93,128 @@
#define __raw_writel writel
#define __raw_writeq writeq

-#define inb_p(port) inb((port))
-#define outb_p(val, port) outb((val), (port))
-#define inw_p(port) inw((port))
-#define outw_p(val, port) outw((val), (port))
-#define inl_p(port) inl((port))
-#define outl_p(val, port) outl((val), (port))
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
+#define readq_relaxed readq
+
+#define ioread8 readb
+#define ioread16 readw
+#define ioread32 readl
+#define ioread64 readq
+#define iowrite8 writeb
+#define iowrite16 writew
+#define iowrite32 writel
+#define iowrite64 writeq

-static inline void insb(unsigned long port, void *dst, unsigned long count)
+static inline void *memcpy_fromio(void *dst, void *src, int len)
{
- unsigned char *p = dst;
- while (count--)
- *p++ = inb(port);
+ int x;
+ BUG_ON((unsigned long)src & 0x3);
+ for (x = 0; x < len; x += 4)
+ *(u32 *)(dst + x) = readl(src + x);
+ return dst;
}
-static inline void insw(unsigned long port, void *dst, unsigned long count)
+
+static inline void *memcpy_toio(void *dst, void *src, int len)
{
- unsigned short *p = dst;
- while (count--)
- *p++ = inw(port);
+ int x;
+ BUG_ON((unsigned long)dst & 0x3);
+ for (x = 0; x < len; x += 4)
+ writel(*(u32 *)(src + x), dst + x);
+ return dst;
}
-static inline void insl(unsigned long port, void *dst, unsigned long count)
+
+#endif
+
+/*
+ * The Tile architecture does not support IOPORT, even with PCI.
+ * Unfortunately we can't yet simply not declare these methods,
+ * since some generic code that compiles into the kernel, but
+ * we never run, uses them unconditionally.
+ */
+
+extern int ioport_panic(void);
+
+static inline u8 inb(unsigned long addr)
{
- unsigned int *p = dst;
- while (count--)
- *p++ = inl(port);
+ return ioport_panic();
}

-static inline void outsb(unsigned long port, const void *src,
- unsigned long count)
+static inline u16 inw(unsigned long addr)
{
- const unsigned char *p = src;
- while (count--)
- outb(*p++, port);
+ return ioport_panic();
}
-static inline void outsw(unsigned long port, const void *src,
- unsigned long count)
+
+static inline u32 inl(unsigned long addr)
{
- const unsigned short *p = src;
- while (count--)
- outw(*p++, port);
+ return ioport_panic();
}
-static inline void outsl(unsigned long port, const void *src,
- unsigned long count)
+
+static inline void outb(u8 b, unsigned long addr)
{
- const unsigned int *p = src;
- while (count--)
- outl(*p++, port);
+ ioport_panic();
}

+static inline void outw(u16 b, unsigned long addr)
+{
+ ioport_panic();
+}

-/*
- * Some places try to pass in an loff_t for PHYSADDR (?!), so we cast it to
- * long before casting it to a pointer to avoid compiler warnings.
- */
-#if CHIP_HAS_MMIO()
-extern void __iomem *ioremap(resource_size_t offset, unsigned long size);
-extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
- pgprot_t pgprot);
-extern void iounmap(volatile void __iomem *addr);
-#else
-#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr))
-#define iounmap(addr) ((void)0)
-#endif
+static inline void outl(u32 b, unsigned long addr)
+{
+ ioport_panic();
+}

-void __iomem *ioport_map(unsigned long port, unsigned int len);
-extern inline void ioport_unmap(void __iomem *addr) {}
+#define inb_p(addr) inb(addr)
+#define inw_p(addr) inw(addr)
+#define inl_p(addr) inl(addr)
+#define outb_p(x, addr) outb((x), (addr))
+#define outw_p(x, addr) outw((x), (addr))
+#define outl_p(x, addr) outl((x), (addr))

-#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
-#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
-#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
+static inline void insb(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}

-#define ioread8(addr) readb(addr)
-#define ioread16(addr) readw(addr)
-#define ioread32(addr) readl(addr)
-#define ioread64(addr) readq(addr)
-#define iowrite8(val, addr) writeb((val), (addr))
-#define iowrite16(val, addr) writew((val), (addr))
-#define iowrite32(val, addr) writel((val), (addr))
-#define iowrite64(val, addr) writeq((val), (addr))
-
-#define ioread8_rep(a, b, c) insb((unsigned long)(a), (b), (c))
-#define ioread16_rep(a, b, c) insw((unsigned long)(a), (b), (c))
-#define ioread32_rep(a, b, c) insl((unsigned long)(a), (b), (c))
-
-#define iowrite8_rep(a, b, c) outsb((unsigned long)(a), (b), (c))
-#define iowrite16_rep(a, b, c) outsw((unsigned long)(a), (b), (c))
-#define iowrite32_rep(a, b, c) outsl((unsigned long)(a), (b), (c))
+static inline void insw(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}

-#define mmiowb()
+static inline void insl(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}

-/* Conversion between virtual and physical mappings. */
-#define mm_ptov(addr) ((void *)phys_to_virt(addr))
-#define mm_vtop(addr) ((unsigned long)virt_to_phys(addr))
+static inline void outsb(unsigned long addr, const void *buffer, int count)
+{
+ ioport_panic();
+}

-static inline void *memcpy_fromio(void *dst, void *src, int len)
+static inline void outsw(unsigned long addr, const void *buffer, int count)
{
- int x;
- if ((unsigned long)src & 0x3)
- panic("memcpy_fromio from non dword aligned address");
- for (x = 0; x < len; x += 4)
- *(u32 *)(dst + x) = readl(src + x);
- return dst;
+ ioport_panic();
}

-static inline void *memcpy_toio(void *dst, void *src, int len)
+static inline void outsl(unsigned long addr, const void *buffer, int count)
{
- int x;
- if ((unsigned long)dst & 0x3)
- panic("memcpy_toio to non dword aligned address");
- for (x = 0; x < len; x += 4)
- writel(*(u32 *)(src + x), dst + x);
- return dst;
+ ioport_panic();
}

+#define ioread8_rep(p, dst, count) \
+ insb((unsigned long) (p), (dst), (count))
+#define ioread16_rep(p, dst, count) \
+ insw((unsigned long) (p), (dst), (count))
+#define ioread32_rep(p, dst, count) \
+ insl((unsigned long) (p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) \
+ outsb((unsigned long) (p), (src), (count))
+#define iowrite16_rep(p, src, count) \
+ outsw((unsigned long) (p), (src), (count))
+#define iowrite32_rep(p, src, count) \
+ outsl((unsigned long) (p), (src), (count))
+
#endif /* _ASM_TILE_IO_H */
diff -ru tile.old/include/asm/irq.h tile/include/asm/irq.h
--- tile.old/include/asm/irq.h 2010-05-28 18:03:32.157277000 -0400
+++ tile/include/asm/irq.h 2010-05-28 23:07:05.485756000 -0400
@@ -15,7 +15,6 @@
#ifndef _ASM_TILE_IRQ_H
#define _ASM_TILE_IRQ_H

-#ifdef __KERNEL__
#include <linux/hardirq.h>

/* The hypervisor interface provides 32 IRQs. */
@@ -27,18 +26,12 @@
/* The HV interrupt state object. */
DECLARE_PER_CPU(HV_IntrState, dev_intr_state);

-
void ack_bad_irq(unsigned int irq);
-void tile_irq_request_level(int tile_irq);
-void tile_irq_request_edge(int tile_irq);
-void tile_enable_irq(int irq);
-
-/* Register or unregister a function to be called upon a particular IRQ. */
-void tile_request_irq(void (*handler)(void *), void *dev_id, int index);
-void tile_free_irq(int index);
-
-extern int tile_irq_base;

-#endif /* __KERNEL__ */
+/*
+ * Paravirtualized drivers should call this when their init calls
+ * discover a valid HV IRQ.
+ */
+void tile_irq_activate(unsigned int irq);

#endif /* _ASM_TILE_IRQ_H */
diff -ru tile.old/include/asm/irqflags.h tile/include/asm/irqflags.h
--- tile.old/include/asm/irqflags.h 2010-05-28 18:03:32.161264000 -0400
+++ tile/include/asm/irqflags.h 2010-05-28 23:07:05.488744000 -0400
@@ -161,28 +161,43 @@

/* We provide a somewhat more restricted set for assembly. */

+#ifdef __tilegx__

+#if INT_MEM_ERROR != 0
+# error Fix IRQ_DISABLED() macro
+#endif

+/* Return 0 or 1 to indicate whether interrupts are currently disabled. */
+#define IRQS_DISABLED(tmp) \
+ mfspr tmp, INTERRUPT_MASK_1; \
+ andi tmp, tmp, 1

+/* Load up a pointer to &interrupts_enabled_mask. */
+#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
+ moveli reg, hw2_last(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw1(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw0(interrupts_enabled_mask); \
+ add reg, reg, tp

+/* Disable interrupts. */
+#define IRQ_DISABLE(tmp0, tmp1) \
+ moveli tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS); \
+ shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS); \
+ shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS); \
+ mtspr INTERRUPT_MASK_SET_1, tmp0

+/* Disable ALL synchronous interrupts (used by NMI entry). */
+#define IRQ_DISABLE_ALL(tmp) \
+ movei tmp, -1; \
+ mtspr INTERRUPT_MASK_SET_1, tmp

+/* Enable interrupts. */
+#define IRQ_ENABLE(tmp0, tmp1) \
+ GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
+ ld tmp0, tmp0; \
+ mtspr INTERRUPT_MASK_RESET_1, tmp0

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#else /* !__tilegx__ */

/*
* Return 0 or 1 to indicate whether interrupts are currently disabled.
@@ -232,7 +247,7 @@
lw tmp1, tmp1; \
mtspr INTERRUPT_MASK_RESET_1_0, tmp0; \
mtspr INTERRUPT_MASK_RESET_1_1, tmp1
-
+#endif

/*
* Do the CPU's IRQ-state tracing from assembly code. We call a
Only in tile.old/include/asm: kvm.h
diff -ru tile.old/include/asm/mman.h tile/include/asm/mman.h
--- tile.old/include/asm/mman.h 2010-05-28 18:03:32.243228000 -0400
+++ tile/include/asm/mman.h 2010-05-28 23:07:05.521712000 -0400
@@ -29,80 +29,6 @@
#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
#define MAP_HUGETLB 0x4000 /* create a huge page mapping */

-/*
- * Specify the "home cache" for the page explicitly. The home cache is
- * the cache of one particular "home" cpu, which is used as a coherence
- * point for normal cached operations. Normally the kernel chooses for
- * you, but you can use the MAP_CACHE_HOME_xxx flags to override.
- *
- * User code should not use any symbols with a leading "_" as they are
- * implementation specific and may change from release to release
- * without warning.
- *
- * See the Tilera mmap(2) man page for more details (e.g. "tile-man mmap").
- */
-
-/* Implementation details; do not use directly. */
-#define _MAP_CACHE_INCOHERENT 0x40000
-#define _MAP_CACHE_HOME 0x80000
-#define _MAP_CACHE_HOME_SHIFT 20
-#define _MAP_CACHE_HOME_MASK 0x3ff
-#define _MAP_CACHE_MKHOME(n) \
- (_MAP_CACHE_HOME | (((n) & _MAP_CACHE_HOME_MASK) << _MAP_CACHE_HOME_SHIFT))
-
-/* Set the home cache to the specified cpu. */
-#define MAP_CACHE_HOME(n) _MAP_CACHE_MKHOME(n)
-
-/* Set the home cache to the current cpu. */
-#define _MAP_CACHE_HOME_HERE (_MAP_CACHE_HOME_MASK - 0)
-#define MAP_CACHE_HOME_HERE _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_HERE)
-
-/* Request no on-chip home, i.e. read from memory. Invalid with PROT_WRITE. */
-#define _MAP_CACHE_HOME_NONE (_MAP_CACHE_HOME_MASK - 1)
-#define MAP_CACHE_HOME_NONE _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_NONE)
-
-/* Request no on-chip home, and allow incoherent PROT_WRITE mappings. */
-#define MAP_CACHE_INCOHERENT (_MAP_CACHE_INCOHERENT | MAP_CACHE_HOME_NONE)
-
-/* Force the system to choose a single home cache, on a cpu of its choice. */
-#define _MAP_CACHE_HOME_SINGLE (_MAP_CACHE_HOME_MASK - 2)
-#define MAP_CACHE_HOME_SINGLE _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_SINGLE)
-
-/* Create a mapping that follows the task when it migrates. */
-#define _MAP_CACHE_HOME_TASK (_MAP_CACHE_HOME_MASK - 3)
-#define MAP_CACHE_HOME_TASK _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_TASK)
-
-#if CHIP_HAS_CBOX_HOME_MAP()
-/* Create a hash-for-home mapping. */
-#define _MAP_CACHE_HOME_HASH (_MAP_CACHE_HOME_MASK - 4)
-#define MAP_CACHE_HOME_HASH _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_HASH)
-#endif
-
-/*
- * Specify local caching attributes for the mapping. Normally the kernel
- * chooses whether to use the local cache, but these flags can be used
- * to override the kernel.
- */
-
-/* Disable use of local L2 (ignored on tile64). */
-#define MAP_CACHE_NO_L2 0x20000
-
-/* Disable use of local L1 (ignored on tile64). */
-#define MAP_CACHE_NO_L1 0x08000
-
-/* Convenience alias that should be used for forward compatibility. */
-#define MAP_CACHE_NO_LOCAL (MAP_CACHE_NO_L1 | MAP_CACHE_NO_L2)
-
-/* Convenience alias for direct-to-RAM mappings. */
-#define MAP_CACHE_NONE (MAP_CACHE_HOME_NONE | MAP_CACHE_NO_LOCAL)
-
-/* Arrange for this mapping to take priority in the cache. */
-#define MAP_CACHE_PRIORITY 0x02000
-
-/*
- * Environment variable that controls hash-for-home in user programs.
- */
-#define MAP_CACHE_HASH_ENV_VAR "LD_CACHE_HASH"

/*
* Flags for mlockall
@@ -110,17 +36,5 @@
#define MCL_CURRENT 1 /* lock all current mappings */
#define MCL_FUTURE 2 /* lock all future mappings */

-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
-
-#include <asm/page.h>
-
-struct vm_area_struct;
-struct address_space;
-extern int arch_vm_area_flags(struct mm_struct *mm, unsigned long flags,
- unsigned long vm_flags, pid_t *, pgprot_t *);
-extern int arch_vm_area_validate(struct vm_area_struct *,
- struct address_space *);
-
-#endif /* kernel C code */

#endif /* _ASM_TILE_MMAN_H */
diff -ru tile.old/include/asm/mmu_context.h tile/include/asm/mmu_context.h
--- tile.old/include/asm/mmu_context.h 2010-05-28 18:03:32.271204000 -0400
+++ tile/include/asm/mmu_context.h 2010-05-28 23:07:05.550694000 -0400
@@ -114,9 +114,6 @@
* the icache in case some physical page now being mapped
* has subsequently been repurposed and has new code.
*/
-
-
-
__flush_icache();

}
Only in tile/include/asm: opcode-tile_64.h
Only in tile/include/asm: opcode_constants_64.h
diff -ru tile.old/include/asm/page.h tile/include/asm/page.h
--- tile.old/include/asm/page.h 2010-05-28 18:03:32.366106000 -0400
+++ tile/include/asm/page.h 2010-05-28 23:07:05.588654000 -0400
@@ -15,9 +15,9 @@
#ifndef _ASM_TILE_PAGE_H
#define _ASM_TILE_PAGE_H

-#include <arch/chip.h>
-
#include <linux/const.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>

/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
#define PAGE_SHIFT 16
@@ -29,17 +29,6 @@
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define HPAGE_MASK (~(HPAGE_SIZE - 1))

-#ifndef __KERNEL__
-/* Tolerate i386-derived user code that expects LARGE_PAGE_xxx. */
-#define LARGE_PAGE_SIZE HPAGE_SIZE
-#define LARGE_PAGE_SHIFT HPAGE_SHIFT
-#define LARGE_PAGE_MASK HPAGE_MASK
-#endif
-
-#ifdef __KERNEL__
-
-#include <hv/hypervisor.h>
-
/*
* The {,H}PAGE_SHIFT values must match the HV_LOG2_PAGE_SIZE_xxx
* definitions in <hv/hypervisor.h>. We validate this at build time
@@ -126,16 +115,16 @@
return hv_pte_val(pgd);
}

+#ifdef __tilegx__

+typedef HV_PTE pmd_t;

+static inline u64 pmd_val(pmd_t pmd)
+{
+ return hv_pte_val(pmd);
+}

-
-
-
-
-
-
-
+#endif

#endif /* !__ASSEMBLY__ */

@@ -153,47 +142,47 @@
#define __pa_to_highbits(pa) ((phys_addr_t)(pa) >> NR_PA_HIGHBIT_SHIFT)
#define __pfn_to_highbits(pfn) ((pfn) >> (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT))

+#ifdef __tilegx__

+/*
+ * We reserve the lower half of memory for user-space programs, and the
+ * upper half for system code. We re-map all of physical memory in the
+ * upper half, which takes a quarter of our VA space. Then we have
+ * the vmalloc regions. The supervisor code lives at 0xfffffff700000000,
+ * with the hypervisor above that.
+ *
+ * Loadable kernel modules are placed immediately after the static
+ * supervisor code, with each being allocated a 256MB region of
+ * address space, so we don't have to worry about the range of "jal"
+ * and other branch instructions.
+ *
+ * For now we keep life simple and just allocate one pmd (4GB) for vmalloc.
+ * Similarly, for now we don't play any struct page mapping games.
+ */

+#if CHIP_PA_WIDTH() + 2 > CHIP_VA_WIDTH()
+# error Too much PA to map with the VA available!
+#endif
+#define HALF_VA_SPACE (_AC(1, UL) << (CHIP_VA_WIDTH() - 1))

+#define MEM_LOW_END (HALF_VA_SPACE - 1) /* low half */
+#define MEM_HIGH_START (-HALF_VA_SPACE) /* high half */
+#define PAGE_OFFSET MEM_HIGH_START
+#define _VMALLOC_START _AC(0xfffffff500000000, UL) /* 4 GB */
+#define HUGE_VMAP_BASE _AC(0xfffffff600000000, UL) /* 4 GB */
+#define MEM_SV_START _AC(0xfffffff700000000, UL) /* 256 MB */
+#define MEM_SV_INTRPT MEM_SV_START
+#define MEM_MODULE_START _AC(0xfffffff710000000, UL) /* 256 MB */
+#define MEM_MODULE_END (MEM_MODULE_START + (256*1024*1024))
+#define MEM_HV_START _AC(0xfffffff800000000, UL) /* 32 GB */

+/* Highest DTLB address we will use */
+#define KERNEL_HIGH_VADDR MEM_SV_START

+/* Since we don't currently provide any fixmaps, we use an impossible VA. */
+#define FIXADDR_TOP MEM_HV_START

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#else /* !__tilegx__ */

/*
* A PAGE_OFFSET of 0xC0000000 means that the kernel has
@@ -245,7 +234,7 @@
#define MEM_MODULE_START VMALLOC_START
#define MEM_MODULE_END VMALLOC_END

-
+#endif /* __tilegx__ */

#ifndef __ASSEMBLY__

@@ -342,5 +331,4 @@
#include <asm-generic/memory_model.h>
#include <asm-generic/getorder.h>

-#endif /* __KERNEL__ */
#endif /* _ASM_TILE_PAGE_H */
diff -ru tile.old/include/asm/pci-bridge.h tile/include/asm/pci-bridge.h
--- tile.old/include/asm/pci-bridge.h 2010-05-28 18:03:32.396084000 -0400
+++ tile/include/asm/pci-bridge.h 2010-05-28 23:07:05.589645000 -0400
@@ -15,8 +15,6 @@
#ifndef _ASM_TILE_PCI_BRIDGE_H
#define _ASM_TILE_PCI_BRIDGE_H

-#ifdef __KERNEL__
-
#include <linux/ioport.h>
#include <linux/pci.h>

@@ -116,6 +114,4 @@
}
#endif

-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_PCI_BRIDGE_H */
diff -ru tile.old/include/asm/pgalloc.h tile/include/asm/pgalloc.h
--- tile.old/include/asm/pgalloc.h 2010-05-28 18:03:32.431047000 -0400
+++ tile/include/asm/pgalloc.h 2010-05-28 23:07:05.607630000 -0400
@@ -40,11 +40,11 @@

static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
-
-
-
+#ifdef CONFIG_64BIT
+ set_pte_order(pmdp, pmd, L2_USER_PGTABLE_ORDER);
+#else
set_pte_order(&pmdp->pud.pgd, pmd.pud.pgd, L2_USER_PGTABLE_ORDER);
-
+#endif
}

static inline void pmd_populate_kernel(struct mm_struct *mm,
@@ -100,16 +100,20 @@
/* During init, we can shatter kernel huge pages if needed. */
void shatter_pmd(pmd_t *pmd);

-
-
-
-
-
-
-
-
-
-
-
+#ifdef __tilegx__
+/* We share a single page allocator for both L1 and L2 page tables. */
+#if HV_L1_SIZE != HV_L2_SIZE
+# error Rework assumption that L1 and L2 page tables are same size.
+#endif
+#define L1_USER_PGTABLE_ORDER L2_USER_PGTABLE_ORDER
+#define pud_populate(mm, pud, pmd) \
+ pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd))
+#define pmd_alloc_one(mm, addr) \
+ ((pmd_t *)page_to_virt(pte_alloc_one((mm), (addr))))
+#define pmd_free(mm, pmdp) \
+ pte_free((mm), virt_to_page(pmdp))
+#define __pmd_free_tlb(tlb, pmdp, address) \
+ __pte_free_tlb((tlb), virt_to_page(pmdp), (address))
+#endif

#endif /* _ASM_TILE_PGALLOC_H */
diff -ru tile.old/include/asm/pgtable.h tile/include/asm/pgtable.h
--- tile.old/include/asm/pgtable.h 2010-05-28 18:03:32.444029000 -0400
+++ tile/include/asm/pgtable.h 2010-05-28 23:07:05.621616000 -0400
@@ -127,12 +127,7 @@
#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)

-#ifdef CONFIG_HOMECACHE
-#define page_to_kpgprot(p) \
- (page_home(p) == PAGE_HOME_IMMUTABLE ? PAGE_KERNEL_RO : PAGE_KERNEL)
-#else
#define page_to_kpgprot(p) PAGE_KERNEL
-#endif

/*
* We could tighten these up, but for now writable or executable
@@ -177,14 +172,14 @@
*/
static inline void __pte_clear(pte_t *ptep)
{
-
-
-
+#ifdef __tilegx__
+ ptep->val = 0;
+#else
u32 *tmp = (u32 *)ptep;
tmp[0] = 0;
barrier();
tmp[1] = 0;
-
+#endif
}
#define pte_clear(mm, addr, ptep) __pte_clear(ptep)

@@ -387,11 +382,11 @@

#endif /* !__ASSEMBLY__ */

-
-
-
+#ifdef __tilegx__
+#include <asm/pgtable_64.h>
+#else
#include <asm/pgtable_32.h>
-
+#endif

#ifndef __ASSEMBLY__

diff -ru tile.old/include/asm/pgtable_32.h tile/include/asm/pgtable_32.h
--- tile.old/include/asm/pgtable_32.h 2010-05-28 18:03:32.476000000 -0400
+++ tile/include/asm/pgtable_32.h 2010-05-28 23:07:05.625621000 -0400
@@ -49,19 +49,26 @@
#define LAST_PKMAP PTRS_PER_PTE

#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE*LAST_PKMAP) & PGDIR_MASK)
+
#ifdef CONFIG_HIGHMEM
-# define HUGE_VMAP_END (PKMAP_BASE & ~(HPAGE_SIZE-1))
+# define __VMAPPING_END (PKMAP_BASE & ~(HPAGE_SIZE-1))
#else
-# define HUGE_VMAP_END (FIXADDR_START & ~(HPAGE_SIZE-1))
+# define __VMAPPING_END (FIXADDR_START & ~(HPAGE_SIZE-1))
#endif
+
+#ifdef CONFIG_HUGEVMAP
+#define HUGE_VMAP_END __VMAPPING_END
#define HUGE_VMAP_BASE (HUGE_VMAP_END - CONFIG_NR_HUGE_VMAPS * HPAGE_SIZE)
+#define _VMALLOC_END HUGE_VMAP_BASE
+#else
+#define _VMALLOC_END __VMAPPING_END
+#endif

/*
* Align the vmalloc area to an L2 page table, and leave a guard page
* at the beginning and end. The vmalloc code also puts in an internal
* guard page between each allocation.
*/
-#define _VMALLOC_END HUGE_VMAP_BASE
#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE)
extern unsigned long VMALLOC_RESERVE /* = CONFIG_VMALLOC_RESERVE */;
#define _VMALLOC_START (_VMALLOC_END - VMALLOC_RESERVE)
diff -ru tile.old/include/asm/posix_types.h tile/include/asm/posix_types.h
--- tile.old/include/asm/posix_types.h 2010-05-28 18:03:32.486990000 -0400
+++ tile/include/asm/posix_types.h 2010-05-28 23:07:05.622635000 -0400
@@ -1,77 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_POSIX_TYPES_H
-#define _ASM_TILE_POSIX_TYPES_H
-
-/*
- * This file is generally used by user-level software, so you need to
- * be a little careful about namespace pollution etc.
- */
-
-typedef unsigned long __kernel_ino_t;
-typedef unsigned int __kernel_mode_t;
-typedef unsigned int __kernel_nlink_t;
-typedef long __kernel_off_t;
-typedef long long __kernel_loff_t;
-typedef int __kernel_pid_t;
-typedef unsigned int __kernel_ipc_pid_t;
-typedef unsigned int __kernel_uid_t;
-typedef unsigned int __kernel_gid_t;
-
-
-
-
-
-typedef unsigned int __kernel_size_t;
-typedef int __kernel_ssize_t;
-typedef int __kernel_ptrdiff_t;
-
-typedef long __kernel_time_t;
-typedef long __kernel_suseconds_t;
-typedef long __kernel_clock_t;
-typedef int __kernel_timer_t;
-typedef int __kernel_clockid_t;
-typedef int __kernel_daddr_t;
-typedef char *__kernel_caddr_t;
-typedef unsigned short __kernel_uid16_t;
-typedef unsigned short __kernel_gid16_t;
-typedef unsigned int __kernel_uid32_t;
-typedef unsigned int __kernel_gid32_t;
-
-typedef unsigned short __kernel_old_uid_t;
-typedef unsigned short __kernel_old_gid_t;
-typedef unsigned short __kernel_old_dev_t;
-
-typedef struct {
- int val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef __FD_SET
-#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-
-#undef __FD_CLR
-#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-
-#undef __FD_ISSET
-#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
-
-#undef __FD_ZERO
-#define __FD_ZERO(fdsetp) memset(fdsetp, 0, sizeof(fd_set))
-
-#endif /* defined(__KERNEL__) */
-
-#endif /* _ASM_TILE_POSIX_TYPES_H */
+#include <asm-generic/posix_types.h>
diff -ru tile.old/include/asm/processor.h tile/include/asm/processor.h
--- tile.old/include/asm/processor.h 2010-05-28 18:03:32.489982000 -0400
+++ tile/include/asm/processor.h 2010-05-28 23:07:05.635602000 -0400
@@ -25,13 +25,11 @@
#include <asm/percpu.h>

#include <arch/chip.h>
-#include <arch/cycle.h>
#include <arch/spr_def.h>

struct task_struct;
struct thread_struct;
struct list_head;
-struct khardwall_rectangle;

typedef struct {
unsigned long seg;
@@ -41,9 +39,6 @@
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
-
-
-
void *current_text_addr(void);

#if CHIP_HAS_TILE_DMA()
@@ -79,10 +74,6 @@
unsigned long address; /* what address faulted? */
};

-/* Can't use a normal list_head here due to header-file inclusion issues. */
-struct hardwall_list {
- struct list_head *next, *prev;
-};

struct thread_struct {
/* kernel stack pointer */
@@ -109,10 +100,6 @@
/* Any other miscellaneous processor state bits */
unsigned long proc_status;
#endif
- /* Is this task tied to an activated hardwall? */
- struct khardwall_rectangle *hardwall;
- /* Chains this task into the list at hardwall->list. */
- struct hardwall_list hardwall_list;
#if CHIP_HAS_TILE_DMA()
/* Async DMA TLB fault information */
struct async_tlb dma_async_tlb;
@@ -123,17 +110,6 @@
/* Async SNI TLB fault information */
struct async_tlb sn_async_tlb;
#endif
-#ifdef CONFIG_HOMECACHE
- /* Requested home for allocated pages. */
- int homecache_desired_home;
- /*
- * Per-thread storage for migrating kernel threads.
- * This is effectively a cpumask_t, but header inclusion
- * issues prevent us from declaring it as such here.
- */
- unsigned long homecache_tlb_flush[(NR_CPUS + (8 * sizeof(long)) - 1) /
- (8 * sizeof(long))];
-#endif
};

#endif /* !__ASSEMBLY__ */
@@ -149,19 +125,19 @@
* pt_regs structure this many bytes below the top of the page.
* This aligns the pt_regs structure optimally for cache-line access.
*/
-
-
-
+#ifdef __tilegx__
+#define KSTK_PTREGS_GAP 48
+#else
#define KSTK_PTREGS_GAP 56
-
+#endif

#ifndef __ASSEMBLY__

-
-
-
+#ifdef __tilegx__
+#define TASK_SIZE_MAX (MEM_LOW_END + 1)
+#else
#define TASK_SIZE_MAX PAGE_OFFSET
-
+#endif

/* TASK_SIZE and related variables are always checked in "current" context. */
#ifdef CONFIG_COMPAT
@@ -219,15 +195,6 @@
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);

/* Helper routines for setting home cache modes at exec() time. */
-#if defined(CONFIG_HOMECACHE) && CHIP_HAS_CBOX_HOME_MAP()
-struct vm_area_struct;
-extern void arch_exec_env(char __user *__user *envp);
-extern void arch_exec_vma(struct vm_area_struct *);
-extern void arch_exec_map(unsigned long addr);
-#define arch_exec_env arch_exec_env
-#define arch_exec_vma arch_exec_vma
-#define arch_exec_map arch_exec_map
-#endif /* CHIP_HAS_CBOX_HOME_MAP() */


/*
@@ -252,11 +219,11 @@
#define KSTK_ESP(task) task_sp(task)

/* Standard format for printing registers and other word-size data. */
-
-
-
+#ifdef __tilegx__
+# define REGFMT "0x%016lx"
+#else
# define REGFMT "0x%08lx"
-
+#endif

/*
* Do some slow action (e.g. read a slow SPR).
@@ -265,7 +232,7 @@
*/
static inline void cpu_relax(void)
{
- cycle_relax();
+ __insn_mfspr(SPR_PASS);
barrier();
}

@@ -279,15 +246,6 @@
/* Data on which physical memory controller corresponds to which NUMA node. */
extern int node_controller[];

-#ifdef CONFIG_DATAPLANE
-/*
- * Which cpu does any specific "singlethread" type work, such as
- * running the main timer tick code or the singlethread workqueue.
- * Defined in platform-generic code in kernel/workqueue.c but not
- * always exported.
- */
-extern int singlethread_cpu;
-#endif

/* Do we dump information to the console when a user application crashes? */
extern int show_crashinfo;
diff -ru tile.old/include/asm/ptrace.h tile/include/asm/ptrace.h
--- tile.old/include/asm/ptrace.h 2010-05-28 18:03:32.499974000 -0400
+++ tile/include/asm/ptrace.h 2010-05-28 23:07:05.633608000 -0400
@@ -146,10 +146,10 @@
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
int error_code);

-
-
-
-
+#ifdef __tilegx__
+/* We need this since sigval_t has a user pointer in it, for GETSIGINFO etc. */
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+#endif

#endif /* !__ASSEMBLY__ */

diff -ru tile.old/include/asm/sections.h tile/include/asm/sections.h
--- tile.old/include/asm/sections.h 2010-05-28 18:03:32.503972000 -0400
+++ tile/include/asm/sections.h 2010-05-28 23:07:05.650582000 -0400
@@ -20,8 +20,7 @@
#include <asm-generic/sections.h>

/* Text and data are at different areas in the kernel VA space. */
-extern char __init_text_begin[], __init_text_end[];
-extern char __init_data_begin[], __init_data_end[];
+extern char _sinitdata[], _einitdata[];

/* Write-once data is writable only till the end of initialization. */
extern char __w1data_begin[], __w1data_end[];
diff -ru tile.old/include/asm/sembuf.h tile/include/asm/sembuf.h
--- tile.old/include/asm/sembuf.h 2010-05-28 18:03:32.513967000 -0400
+++ tile/include/asm/sembuf.h 2010-05-28 23:07:05.652593000 -0400
@@ -1,42 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_SEMBUF_H
-#define _ASM_TILE_SEMBUF_H
-
-/*
- * The semid64_ds structure for TILE architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-struct semid64_ds {
- struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
- __kernel_time_t sem_otime; /* last semop time */
-
- unsigned long __unused1;
-
- __kernel_time_t sem_ctime; /* last change time */
-
- unsigned long __unused2;
-
- unsigned long sem_nsems; /* no. of semaphores in array */
- unsigned long __unused3;
- unsigned long __unused4;
-};
-
-#endif /* _ASM_TILE_SEMBUF_H */
+#include <asm-generic/sembuf.h>
diff -ru tile.old/include/asm/setup.h tile/include/asm/setup.h
--- tile.old/include/asm/setup.h 2010-05-28 18:03:32.530951000 -0400
+++ tile/include/asm/setup.h 2010-05-28 23:07:05.666569000 -0400
@@ -15,7 +15,6 @@
#ifndef _ASM_TILE_SETUP_H
#define _ASM_TILE_SETUP_H

-#ifdef __KERNEL__
#include <linux/pfn.h>
#include <linux/init.h>

@@ -23,7 +22,6 @@
* Reserved space for vmalloc and iomap - defined in asm/page.h
*/
#define MAXMEM_PFN PFN_DOWN(MAXMEM)
-#endif

#define COMMAND_LINE_SIZE 2048

diff -ru tile.old/include/asm/shmparam.h tile/include/asm/shmparam.h
--- tile.old/include/asm/shmparam.h 2010-05-28 18:03:32.539936000 -0400
+++ tile/include/asm/shmparam.h 2010-05-28 23:07:05.659580000 -0400
@@ -1,20 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_SHMPARAM_H
-#define _ASM_TILE_SHMPARAM_H
-
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
-
-#endif /* _ASM_TILE_SHMPARAM_H */
+#include <asm-generic/shmparam.h>
diff -ru tile.old/include/asm/siginfo.h tile/include/asm/siginfo.h
--- tile.old/include/asm/siginfo.h 2010-05-28 18:03:32.579892000 -0400
+++ tile/include/asm/siginfo.h 2010-05-28 23:07:05.685548000 -0400
@@ -23,7 +23,8 @@
* Additional Tile-specific SIGILL si_codes
*/
#define ILL_DBLFLT (__SI_FAULT|9) /* double fault */
+#define ILL_HARDWALL (__SI_FAULT|10) /* user networks hardwall violation */
#undef NSIGILL
-#define NSIGILL 9
+#define NSIGILL 10

#endif /* _ASM_TILE_SIGINFO_H */
diff -ru tile.old/include/asm/smp.h tile/include/asm/smp.h
--- tile.old/include/asm/smp.h 2010-05-28 18:03:32.596886000 -0400
+++ tile/include/asm/smp.h 2010-05-28 23:07:05.691560000 -0400
@@ -19,6 +19,7 @@

#include <asm/processor.h>
#include <linux/cpumask.h>
+#include <linux/irqreturn.h>

/* Set up this tile to support receiving hypervisor messages */
void init_messaging(void);
@@ -39,7 +40,7 @@
void evaluate_message(int tag);

/* Process an IRQ_RESCHEDULE IPI. */
-void handle_reschedule_ipi(void *token);
+irqreturn_t handle_reschedule_ipi(int irq, void *token);

/* Boot a secondary cpu */
void online_secondary(void);
@@ -87,9 +88,6 @@

#endif /* !CONFIG_SMP */

-#ifdef CONFIG_DATAPLANE
-extern struct cpumask dataplane_map; /* set of cpus in the dataplane */
-#endif

/* Which cpus may be used as the lotar in a page table entry. */
extern struct cpumask cpu_lotar_map;
diff -ru tile.old/include/asm/spinlock.h tile/include/asm/spinlock.h
--- tile.old/include/asm/spinlock.h 2010-05-28 18:03:32.621853000 -0400
+++ tile/include/asm/spinlock.h 2010-05-28 23:07:05.695536000 -0400
@@ -15,10 +15,10 @@
#ifndef _ASM_TILE_SPINLOCK_H
#define _ASM_TILE_SPINLOCK_H

-
-
-
+#ifdef __tilegx__
+#include <asm/spinlock_64.h>
+#else
#include <asm/spinlock_32.h>
-
+#endif

#endif /* _ASM_TILE_SPINLOCK_H */
diff -ru tile.old/include/asm/spinlock_32.h tile/include/asm/spinlock_32.h
--- tile.old/include/asm/spinlock_32.h 2010-05-28 18:03:32.635843000 -0400
+++ tile/include/asm/spinlock_32.h 2010-05-28 23:07:05.701539000 -0400
@@ -108,9 +108,6 @@
{
u32 val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val << _RD_COUNT_WIDTH)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
arch_read_lock_slow(rwlock, val);
return;
}
@@ -124,9 +121,6 @@
{
u32 val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val != 0)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
arch_write_lock_slow(rwlock, val);
return;
}
@@ -141,9 +135,6 @@
int locked;
u32 val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val & 1)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
return arch_read_trylock_slow(rwlock);
}
locked = (val << _RD_COUNT_WIDTH) == 0;
@@ -163,9 +154,6 @@
* or active readers, we can't take the lock, so give up.
*/
if (unlikely(val != 0)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
if (!(val & 1))
rwlock->lock = val;
return 0;
@@ -185,9 +173,6 @@
mb(); /* guarantee anything modified under the lock is visible */
val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val & 1)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
arch_read_unlock_slow(rwlock);
return;
}
@@ -203,9 +188,6 @@
mb(); /* guarantee anything modified under the lock is visible */
val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val != (1 << _WR_NEXT_SHIFT))) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
arch_write_unlock_slow(rwlock, val);
return;
}
diff -ru tile.old/include/asm/spinlock_types.h tile/include/asm/spinlock_types.h
--- tile.old/include/asm/spinlock_types.h 2010-05-28 18:03:32.659812000 -0400
+++ tile/include/asm/spinlock_types.h 2010-05-28 23:07:05.709529000 -0400
@@ -19,23 +19,23 @@
# error "please don't include this file directly"
#endif

+#ifdef __tilegx__

+/* Low 15 bits are "next"; high 15 bits are "current". */
+typedef struct arch_spinlock {
+ unsigned int lock;
+} arch_spinlock_t;

+#define __ARCH_SPIN_LOCK_UNLOCKED { 0 }

+/* High bit is "writer owns"; low 31 bits are a count of readers. */
+typedef struct arch_rwlock {
+ unsigned int lock;
+} arch_rwlock_t;

+#define __ARCH_RW_LOCK_UNLOCKED { 0 }

-
-
-
-
-
-
-
-
-
-
-
-
+#else

typedef struct arch_spinlock {
/* Next ticket number to hand out. */
@@ -56,5 +56,5 @@

#define __ARCH_RW_LOCK_UNLOCKED { 0 }

-
+#endif
#endif /* _ASM_TILE_SPINLOCK_TYPES_H */
diff -ru tile.old/include/asm/stat.h tile/include/asm/stat.h
--- tile.old/include/asm/stat.h 2010-05-28 18:03:32.684792000 -0400
+++ tile/include/asm/stat.h 2010-05-28 23:07:05.714520000 -0400
@@ -1,79 +1 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- * 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, version 2.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for
- * more details.
- */
-
-#ifndef _ASM_TILE_STAT_H
-#define _ASM_TILE_STAT_H
-
-#include <linux/posix_types.h>
-
-#define STAT_HAVE_NSEC 1
-
-struct stat {
- unsigned long st_dev;
- unsigned long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
-
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned long st_rdev;
- long st_size;
- unsigned long st_blksize;
- unsigned long st_blocks;
-
- unsigned long st_atime;
- unsigned long st_atime_nsec;
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
- unsigned long __unused[2];
-};
-
-
-
-struct stat64 {
- unsigned long long st_dev;
-
- unsigned long long st_ino;
-
- unsigned int st_mode;
- unsigned int st_nlink;
-
- unsigned int st_uid;
- unsigned int st_gid;
-
- unsigned long long st_rdev;
-
- long long st_size;
- unsigned long st_blksize;
-
- /* No. 512-byte blocks allocated */
- unsigned long long st_blocks __attribute__((packed));
-
- unsigned long st_atime;
- unsigned long st_atime_nsec;
-
- unsigned long st_mtime;
- unsigned long st_mtime_nsec;
-
- unsigned long st_ctime;
- unsigned long st_ctime_nsec;
-
- unsigned long __unused8;
-};
-
-
-
-#endif /* _ASM_TILE_STAT_H */
+#include <asm-generic/stat.h>
diff -ru tile.old/include/asm/swab.h tile/include/asm/swab.h
--- tile.old/include/asm/swab.h 2010-05-28 18:03:32.714769000 -0400
+++ tile/include/asm/swab.h 2010-05-28 23:07:05.748487000 -0400
@@ -20,10 +20,10 @@
#define __arch_swab64(x) __builtin_bswap64(x)

/* Use the variant that is natural for the wordsize. */
-
-
-
+#ifdef CONFIG_64BIT
+#define __arch_swab16(x) (__builtin_bswap64(x) >> 48)
+#else
#define __arch_swab16(x) (__builtin_bswap32(x) >> 16)
-
+#endif

#endif /* _ASM_TILE_SWAB_H */
diff -ru tile.old/include/asm/syscalls.h tile/include/asm/syscalls.h
--- tile.old/include/asm/syscalls.h 2010-05-28 18:03:32.733747000 -0400
+++ tile/include/asm/syscalls.h 2010-05-28 23:07:05.765467000 -0400
@@ -39,16 +39,22 @@
int sys_raise_fpe(int code, unsigned long addr, struct pt_regs*);

/* kernel/sys.c */
+ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count);
+long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len, int advice);
+int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi, int advice);
+long sys_flush_cache(void);
long sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long offset);
long sys_mmap2(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-
+ unsigned long fd, unsigned long offset);

+#ifndef __tilegx__
/* mm/fault.c */
int sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
-
+#endif

#endif /* _ASM_TILE_SYSCALLS_H */
diff -ru tile.old/include/asm/system.h tile/include/asm/system.h
--- tile.old/include/asm/system.h 2010-05-28 18:03:32.741735000 -0400
+++ tile/include/asm/system.h 2010-05-28 23:07:05.767478000 -0400
@@ -22,7 +22,6 @@

/* NOTE: we can't include <linux/ptrace.h> due to #include dependencies. */
#include <asm/ptrace.h>
-#include <asm/addrspace.h>

#include <arch/chip.h>
#include <arch/sim_def.h>
@@ -192,17 +191,13 @@
void grant_dma_mpls(void);
void restrict_dma_mpls(void);

-/* User-level network management functions */
-void reset_network_state(void);
-void grant_network_mpls(void);
-void restrict_network_mpls(void);
-int hardwall_deactivate(struct task_struct *task);
-
-/* Hook hardwall code into changes in affinity. */
-#define arch_set_cpus_allowed(p, new_mask) do { \
- if (p->thread.hardwall && !cpumask_equal(&p->cpus_allowed, new_mask)) \
- hardwall_deactivate(p); \
- } while (0)
+
+/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
+extern int _sim_syscall(int syscall_num, ...);
+#define sim_syscall(syscall_num, ...) \
+ _sim_syscall(SIM_CONTROL_SYSCALL + \
+ ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
+ ## __VA_ARGS__)

/*
* Kernel threads can check to see if they need to migrate their
diff -ru tile.old/include/asm/thread_info.h tile/include/asm/thread_info.h
--- tile.old/include/asm/thread_info.h 2010-05-28 18:03:32.751726000 -0400
+++ tile/include/asm/thread_info.h 2010-05-28 23:07:05.771466000 -0400
@@ -16,8 +16,6 @@
#ifndef _ASM_TILE_THREAD_INFO_H
#define _ASM_TILE_THREAD_INFO_H

-#ifdef __KERNEL__
-
#include <asm/processor.h>
#include <asm/page.h>
#ifndef __ASSEMBLY__
@@ -96,11 +94,11 @@
#else /* __ASSEMBLY__ */

/* how to get the thread information struct from ASM */
-
-
-
+#ifdef __tilegx__
+#define GET_THREAD_INFO(reg) move reg, sp; mm reg, zero, LOG2_THREAD_SIZE, 63
+#else
#define GET_THREAD_INFO(reg) mm reg, sp, zero, LOG2_THREAD_SIZE, 31
-
+#endif

#endif /* !__ASSEMBLY__ */

@@ -141,9 +139,9 @@
* ever touches our thread-synchronous status, so we don't
* have to worry about atomic accesses.
*/
-
-
-
+#ifdef __tilegx__
+#define TS_COMPAT 0x0001 /* 32-bit compatibility mode */
+#endif
#define TS_POLLING 0x0004 /* in idle loop but not sleeping */
#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal */
#define TS_EXEC_HASH_SET 0x0010 /* apply TS_EXEC_HASH_xxx flags */
@@ -164,6 +162,4 @@
}
#endif /* !__ASSEMBLY__ */

-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_THREAD_INFO_H */
Only in tile.old/include/asm: tilepci.h
diff -ru tile.old/include/asm/timex.h tile/include/asm/timex.h
--- tile.old/include/asm/timex.h 2010-05-28 18:03:32.776707000 -0400
+++ tile/include/asm/timex.h 2010-05-28 23:07:05.782451000 -0400
@@ -15,18 +15,25 @@
#ifndef _ASM_TILE_TIMEX_H
#define _ASM_TILE_TIMEX_H

-#include <arch/cycle.h>
-
-/* Use this random value, just like most archs. Mysterious. */
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+/*
+ * This rate should be a multiple of the possible HZ values (100, 250, 1000)
+ * and a fraction of the possible hardware timer frequencies. Our timer
+ * frequency is highly tunable but also quite precise, so for the primary use
+ * of this value (setting ACT_HZ from HZ) we just pick a value that causes
+ * ACT_HZ to be set to HZ. We make the value somewhat large just to be
+ * more robust in case someone tries out a new value of HZ.
+ */
+#define CLOCK_TICK_RATE 1000000

typedef unsigned long long cycles_t;

#if CHIP_HAS_SPLIT_CYCLE()
-/* Use out-of-line implementation of get_cycle_count() for code density. */
cycles_t get_cycles(void);
#else
-static inline cycles_t get_cycles(void) { return get_cycle_count(); }
+static inline cycles_t get_cycles(void)
+{
+ return __insn_mfspr(SPR_CYCLE);
+}
#endif

cycles_t get_clock_rate(void);
@@ -37,15 +44,4 @@
/* Called at cpu initialization to start the tile-timer clock device. */
void setup_tile_timer(void);

-/* Preferred technique for setting LPJ. */
-#define arch_calibrate_delay_direct() (get_clock_rate() / HZ)
-
-/* Backup technique for setting LPJ. */
-#define ARCH_HAS_READ_CURRENT_TIMER
-static inline int read_current_timer(unsigned long *timer_value)
-{
- *timer_value = get_cycle_count_low();
- return 0;
-}
-
#endif /* _ASM_TILE_TIMEX_H */
diff -ru tile.old/include/asm/traps.h tile/include/asm/traps.h
--- tile.old/include/asm/traps.h 2010-05-28 18:03:32.849635000 -0400
+++ tile/include/asm/traps.h 2010-05-28 23:07:05.803452000 -0400
@@ -22,9 +22,6 @@
/* kernel/traps.c */
void do_trap(struct pt_regs *, int fault_num, unsigned long reason);

-/* kernel/hardwall.c */
-void do_hardwall_trap(struct pt_regs*, int fault_num);
-
/* kernel/time.c */
void do_timer_interrupt(struct pt_regs *, int fault_num);

@@ -34,10 +31,6 @@
/* kernel/irq.c */
void tile_dev_intr(struct pt_regs *, int intnum);

-/* oprofile/op_common.c */
-void op_handle_perf_interrupt(struct pt_regs*, int fault_num,
- unsigned long perf_count_sts);
-void op_handle_aux_perf_interrupt(struct pt_regs*, int fault_num,
- unsigned long perf_count_sts);
+

#endif /* _ASM_TILE_SYSCALLS_H */
diff -ru tile.old/include/asm/uaccess.h tile/include/asm/uaccess.h
--- tile.old/include/asm/uaccess.h 2010-05-28 18:03:32.902570000 -0400
+++ tile/include/asm/uaccess.h 2010-05-28 23:07:05.820434000 -0400
@@ -45,7 +45,7 @@

#define segment_eq(a, b) ((a).seg == (b).seg)

-
+#ifndef __tilegx__
/*
* We could allow mapping all 16 MB at 0xfc000000, but we set up a
* special hack in arch_setup_additional_pages() to auto-create a mapping
@@ -60,9 +60,9 @@
size <= (MEM_USER_INTRPT + INTRPT_SIZE) - addr);
}
#define is_arch_mappable_range is_arch_mappable_range
-
-
-
+#else
+#define is_arch_mappable_range(addr, size) 0
+#endif

/*
* Test whether a block of memory is a valid user space address.
@@ -372,39 +372,39 @@
#define copy_from_user _copy_from_user
#endif

+#ifdef __tilegx__
+/**
+ * __copy_in_user() - copy data within user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to user space. Caller must check
+ * the specified blocks with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+extern unsigned long __copy_in_user_asm(
+ void __user *to, const void __user *from, unsigned long n);

+static inline unsigned long __must_check
+__copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ might_sleep();
+ return __copy_in_user_asm(to, from, n);
+}

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+static inline unsigned long __must_check
+copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n) && access_ok(VERIFY_READ, from, n))
+ n = __copy_in_user(to, from, n);
+ return n;
+}
+#endif


/**
diff -ru tile.old/include/asm/unistd.h tile/include/asm/unistd.h
--- tile.old/include/asm/unistd.h 2010-05-28 18:03:32.908576000 -0400
+++ tile/include/asm/unistd.h 2010-05-28 23:07:05.829406000 -0400
@@ -12,385 +12,36 @@
* more details.
*/

-#ifndef _ASM_TILE_UNISTD_H
+#if !defined(_ASM_TILE_UNISTD_H) || defined(__SYSCALL)
#define _ASM_TILE_UNISTD_H

-/*
- * This file contains the system call numbers.
- */

-#define __NR_restart_syscall 0
-#define __NR_exit 1
-#define __NR_fork 2
-#define __NR_read 3
-#define __NR_write 4
-#define __NR_open 5
-#define __NR_close 6
-#define __NR_waitpid 7
-#define __NR_creat 8
-#define __NR_link 9
-#define __NR_unlink 10
-#define __NR_execve 11
-#define __NR_chdir 12
-#define __NR_time 13
-#define __NR_mknod 14
-#define __NR_chmod 15
-#define __NR_lchown 16
-#define __NR_stat 17
-#define __NR_lseek 18
-#define __NR_getpid 19
-#define __NR_mount 20
-#define __NR_umount2 21
-#define __NR_setuid 22
-#define __NR_getuid 23
-#define __NR_stime 24
-#define __NR_ptrace 25
-#define __NR_alarm 26
-#define __NR_fstat 27
-#define __NR_pause 28
-#define __NR_utime 29
-#define __NR_access 30
-#define __NR_nice 31
-#define __NR_sync 32
-#define __NR_kill 33
-#define __NR_rename 34
-#define __NR_mkdir 35
-#define __NR_rmdir 36
-#define __NR_dup 37
-#define __NR_pipe 38
-#define __NR_times 39
-#define __NR_brk 40
-#define __NR_setgid 41
-#define __NR_getgid 42
-/* unused 43 */
-#define __NR_geteuid 44
-#define __NR_getegid 45
-#define __NR_acct 46
-#define __NR_ioctl 47
-#define __NR_fcntl 48
-#define __NR_setpgid 49
-#define __NR_umask 50
-#define __NR_chroot 51
-#define __NR_ustat 52
-#define __NR_dup2 53
-#define __NR_getppid 54
-#define __NR_getpgrp 55
-#define __NR_setsid 56
-/* unused 57 */
-/* unused 58 */
-#define __NR_setreuid 59
-#define __NR_setregid 60
-/* unused 61 */
-#define __NR_sethostname 62
-#define __NR_setrlimit 63
-#define __NR_getrlimit 64
-#define __NR_getrusage 65
-#define __NR_gettimeofday 66
-#define __NR_settimeofday 67
-#define __NR_getgroups 68
-#define __NR_setgroups 69
-#define __NR_select 70
-#define __NR_symlink 71
-#define __NR_lstat 72
-#define __NR_readlink 73
-#define __NR_uselib 74
-#define __NR_swapon 75
-#define __NR_reboot 76
-#define __NR_mmap2 77
-#define __NR_munmap 78
-#define __NR_truncate 79
-#define __NR_ftruncate 80
-#define __NR_fchmod 81
-#define __NR_fchown 82
-#define __NR_getpriority 83
-#define __NR_setpriority 84
-#define __NR_statfs 85
-#define __NR_fstatfs 86
-#define __NR_socket 87
-#define __NR_bind 88
-#define __NR_connect 89
-#define __NR_listen 90
-#define __NR_accept 91
-#define __NR_getsockname 92
-#define __NR_getpeername 93
-#define __NR_socketpair 94
-#define __NR_send 95
-#define __NR_sendto 96
-#define __NR_recv 97
-#define __NR_recvfrom 98
-#define __NR_shutdown 99
-#define __NR_setsockopt 100
-#define __NR_getsockopt 101
-#define __NR_sendmsg 102
-#define __NR_recvmsg 103
-#define __NR_syslog 104
-#define __NR_setitimer 105
-#define __NR_getitimer 106
-#define __NR_vhangup 107
-#define __NR_wait4 108
-#define __NR_swapoff 109
-#define __NR_sysinfo 110
-#define __NR_shmget 111
-#define __NR_shmat 112
-#define __NR_shmctl 113
-#define __NR_shmdt 114
-#define __NR_semget 115
-#define __NR_semop 116
-#define __NR_semctl 117
-#define __NR_semtimedop 118
-#define __NR_msgget 119
-#define __NR_msgsnd 120
-#define __NR_msgrcv 121
-#define __NR_msgctl 122
-#define __NR_fsync 123
-#define __NR_sigreturn 124
-#define __NR_clone 125
-#define __NR_setdomainname 126
-#define __NR_uname 127
-#define __NR_adjtimex 128
-#define __NR_mprotect 129
-/* unused 130 */
-#define __NR_init_module 131
-#define __NR_delete_module 132
-#define __NR_quotactl 133
-#define __NR_getpgid 134
-#define __NR_fchdir 135
-#define __NR_bdflush 136
-#define __NR_sysfs 137
-#define __NR_personality 138
-#define __NR_afs_syscall 139 /* Syscall for Andrew File System */
-#define __NR_setfsuid 140
-#define __NR_setfsgid 141
-#define __NR__llseek 142
-#define __NR_getdents 143
-#define __NR_flock 144
-#define __NR_msync 145
-#define __NR_readv 146
-#define __NR_writev 147
-#define __NR_getsid 148
-#define __NR_fdatasync 149
-#define __NR__sysctl 150
-#define __NR_mlock 151
-#define __NR_munlock 152
-#define __NR_mlockall 153
-#define __NR_munlockall 154
-#define __NR_sched_setparam 155
-#define __NR_sched_getparam 156
-#define __NR_sched_setscheduler 157
-#define __NR_sched_getscheduler 158
-#define __NR_sched_yield 159
-#define __NR_sched_get_priority_max 160
-#define __NR_sched_get_priority_min 161
-#define __NR_sched_rr_get_interval 162
-#define __NR_nanosleep 163
-#define __NR_mremap 164
-#define __NR_setresuid 165
-#define __NR_getresuid 166
-#define __NR_poll 167
-#define __NR_nfsservctl 168
-#define __NR_setresgid 169
-#define __NR_getresgid 170
-#define __NR_prctl 171
-#define __NR_rt_sigreturn 172
-#define __NR_rt_sigaction 173
-#define __NR_rt_sigprocmask 174
-#define __NR_rt_sigpending 175
-#define __NR_rt_sigtimedwait 176
-#define __NR_rt_sigqueueinfo 177
-#define __NR_rt_sigsuspend 178
-#define __NR_pread64 179
-#define __NR_pwrite64 180
-#define __NR_chown 181
-#define __NR_getcwd 182
-#define __NR_capget 183
-#define __NR_capset 184
-#define __NR_sigaltstack 185
-#define __NR_sendfile 186
-#define __NR_getpmsg 187 /* some people actually want streams */
-#define __NR_putpmsg 188 /* some people actually want streams */
-#define __NR_vfork 189
-#define __NR_truncate64 190
-#define __NR_ftruncate64 191
-#define __NR_stat64 192
-#define __NR_lstat64 193
-#define __NR_fstat64 194
-#define __NR_pivot_root 195
-#define __NR_mincore 196
-#define __NR_madvise 197
-#define __NR_getdents64 198
-#define __NR_fcntl64 199
-#define __NR_gettid 200
-#define __NR_readahead 201
-#define __NR_setxattr 202
-#define __NR_lsetxattr 203
-#define __NR_fsetxattr 204
-#define __NR_getxattr 205
-#define __NR_lgetxattr 206
-#define __NR_fgetxattr 207
-#define __NR_listxattr 208
-#define __NR_llistxattr 209
-#define __NR_flistxattr 210
-#define __NR_removexattr 211
-#define __NR_lremovexattr 212
-#define __NR_fremovexattr 213
-#define __NR_tkill 214
-#define __NR_sendfile64 215
-#define __NR_futex 216
-#define __NR_sched_setaffinity 217
-#define __NR_sched_getaffinity 218
-#define __NR_io_setup 219
-#define __NR_io_destroy 220
-#define __NR_io_getevents 221
-#define __NR_io_submit 222
-#define __NR_io_cancel 223
-#define __NR_fadvise64 224
-#define __NR_migrate_pages 225
-#define __NR_exit_group 226
-#define __NR_lookup_dcookie 227
-#define __NR_epoll_create 228
-#define __NR_epoll_ctl 229
-#define __NR_epoll_wait 230
-#define __NR_remap_file_pages 231
-#define __NR_set_tid_address 232
-#define __NR_timer_create 233
-#define __NR_timer_settime (__NR_timer_create+1)
-#define __NR_timer_gettime (__NR_timer_create+2)
-#define __NR_timer_getoverrun (__NR_timer_create+3)
-#define __NR_timer_delete (__NR_timer_create+4)
-#define __NR_clock_settime (__NR_timer_create+5)
-#define __NR_clock_gettime (__NR_timer_create+6)
-#define __NR_clock_getres (__NR_timer_create+7)
-#define __NR_clock_nanosleep (__NR_timer_create+8)
-#define __NR_statfs64 242
-#define __NR_fstatfs64 243
-#define __NR_tgkill 244
-#define __NR_utimes 245
-#define __NR_fadvise64_64 246
-#define __NR_mbind 247
-#define __NR_get_mempolicy 248
-#define __NR_set_mempolicy 249
-#define __NR_mq_open 250
-#define __NR_mq_unlink (__NR_mq_open+1)
-#define __NR_mq_timedsend (__NR_mq_open+2)
-#define __NR_mq_timedreceive (__NR_mq_open+3)
-#define __NR_mq_notify (__NR_mq_open+4)
-#define __NR_mq_getsetattr (__NR_mq_open+5)
-#define __NR_kexec_load 256
-#define __NR_waitid 257
-#define __NR_add_key 258
-#define __NR_request_key 259
-#define __NR_keyctl 260
-#define __NR_ioprio_set 261
-#define __NR_ioprio_get 262
-#define __NR_inotify_init 263
-#define __NR_inotify_add_watch 264
-#define __NR_inotify_rm_watch 265
-#define __NR_raise_fpe 266 /* TILE-specific */
-#define __NR_openat 267
-#define __NR_mkdirat 268
-#define __NR_mknodat 269
-#define __NR_fchownat 270
-#define __NR_futimesat 271
-#define __NR_fstatat64 272
-#define __NR_unlinkat 273
-#define __NR_renameat 274
-#define __NR_linkat 275
-#define __NR_symlinkat 276
-#define __NR_readlinkat 277
-#define __NR_fchmodat 278
-#define __NR_faccessat 279
-#define __NR_pselect6 280
-#define __NR_ppoll 281
-#define __NR_unshare 282
-#define __NR_set_robust_list 283
-#define __NR_get_robust_list 284
-#define __NR_splice 285
-#define __NR_sync_file_range2 286
-#define __NR_tee 287
-#define __NR_vmsplice 288
-#define __NR_move_pages 289
-#define __NR_mmap 290
-#define __NR_cmpxchg_badaddr 291 /* TILE-specific */
-#define __NR_getcpu 292
-#define __NR_epoll_pwait 293
-#define __NR_utimensat 294
-#define __NR_signalfd 295
-#define __NR_timerfd_create 296
-#define __NR_eventfd 297
-#define __NR_fallocate 298
-#define __NR_timerfd_settime 299
-#define __NR_timerfd_gettime 300
-#define __NR_flush_cache 301
-#define __NR_accept4 302
-#define __NR_signalfd4 303
-#define __NR_eventfd2 304
-#define __NR_epoll_create1 305
-#define __NR_dup3 306
-#define __NR_pipe2 307
-#define __NR_inotify_init1 308
-#define __NR_preadv 309
-#define __NR_pwritev 310
-#define __NR_rt_tgsigqueueinfo 311
-#define __NR_perf_event_open 312
-#define __NR_recvmmsg 313
+#ifndef __LP64__
+/* Use the flavor of this syscall that matches the 32-bit API better. */
+#define __ARCH_WANT_SYNC_FILE_RANGE2
+#endif

-#define NR_syscalls 314
+/* Use the standard ABI for syscalls. */
+#include <asm-generic/unistd.h>

-/* "Fast" syscalls don't preserve the caller-saved registers. */
+#ifndef __tilegx__
+/* "Fast" syscalls provide atomic support for 32-bit chips. */
#define __NR_FAST_cmpxchg -1
#define __NR_FAST_atomic_update -2
#define __NR_FAST_cmpxchg64 -3
+#define __NR_cmpxchg_badaddr (__NR_arch_specific_syscall + 0)
+__SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
+#endif

-#define NR_fast_syscalls 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+/* Additional Tilera-specific syscalls. */
+#define __NR_flush_cache (__NR_arch_specific_syscall + 1)
+__SYSCALL(__NR_flush_cache, sys_flush_cache)

#ifdef __KERNEL__
-
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_RT_SIGACTION
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_LLSEEK
-
-
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_STAT64
-
-
+/* In compat mode, we use sys_llseek() for compat_sys_llseek(). */
#ifdef CONFIG_COMPAT
-#define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_SYS_LLSEEK
#endif
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but not all the conditional syscalls are prototyped in kernel/sys_ni.c,
- * causing build warnings, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
#endif

-#endif /* __KERNEL__ */
#endif /* _ASM_TILE_UNISTD_H */
Only in tile.old/include/hv: drv_eeprom_intf.h
Only in tile.old/include/hv: drv_gpio_intf.h
Only in tile.old/include/hv: drv_hpi_intf.h
Only in tile.old/include/hv: drv_i2cm_intf.h
Only in tile.old/include/hv: drv_memprof_intf.h
Only in tile.old/include/hv: drv_pcie_channel_intf.h
Only in tile.old/include/hv: drv_pcie_common.h
Only in tile.old/include/hv: drv_pcie_rctest_intf.h
Only in tile.old/include/hv: drv_rshim_intf.h
Only in tile.old/include/hv: drv_softuart_intf.h
Only in tile.old/include/hv: drv_srom_intf.h
Only in tile.old/include/hv: drv_watchdog_intf.h
Only in tile.old/include/hv: drv_xgbe_impl.h
Only in tile.old/include/hv: drv_xgbe_intf.h
Only in tile.old/include/hv: iorpc.h
Only in tile.old/include: netio
Only in tile.old: initramfs
diff -ru tile.old/kernel/Makefile tile/kernel/Makefile
--- tile.old/kernel/Makefile 2010-05-28 18:03:33.247396000 -0400
+++ tile/kernel/Makefile 2010-05-28 23:07:06.108168000 -0400
@@ -3,10 +3,9 @@
#

extra-y := vmlinux.lds head_$(BITS).o
-obj-y := irq.o time.o process.o reboot.o proc.o pci-dma.o init_task.o \
- ptrace.o setup.o traps.o hv_drivers.o \
- hardwall.o messaging.o single_step.o sys.o signal.o stack.o \
- backtrace.o hugevmap.o memprof.o entry.o \
+obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
+ pci-dma.o proc.o process.o ptrace.o reboot.o \
+ setup.o signal.o single_step.o stack.o sys.o time.o traps.o \
intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o

obj-$(CONFIG_TILEGX) += futex_64.o
@@ -15,4 +14,3 @@
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
-obj-$(CONFIG_PCI) += pci.o
diff -ru tile.old/kernel/asm-offsets.c tile/kernel/asm-offsets.c
--- tile.old/kernel/asm-offsets.c 2010-05-28 18:03:33.261373000 -0400
+++ tile/kernel/asm-offsets.c 2010-05-28 23:07:04.914157000 -0400
@@ -22,18 +22,18 @@
#include <hv/hypervisor.h>

/* Check for compatible compiler early in the build. */
-
-
-
-
-
-
-
-
-
-
-
-
+#ifdef CONFIG_TILEGX
+# ifndef __tilegx__
+# error Can only build TILE-Gx configurations with tilegx compiler
+# endif
+# ifndef __LP64__
+# error Must not specify -m32 when building the TILE-Gx kernel
+# endif
+#else
+# ifdef __tilegx__
+# error Can not build TILEPro/TILE64 configurations with tilegx compiler
+# endif
+#endif

void foo(void)
{
diff -ru tile.old/kernel/backtrace.c tile/kernel/backtrace.c
--- tile.old/kernel/backtrace.c 2010-05-28 18:03:33.273371000 -0400
+++ tile/kernel/backtrace.c 2010-05-28 23:07:06.001250000 -0400
@@ -12,34 +12,17 @@
* more details.
*/

-#ifndef __KERNEL__
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#else
#include <linux/kernel.h>
#include <linux/string.h>
-#define abort() BUG()
-#endif

-#if defined(__KERNEL__)
#include <asm/backtrace.h>
-#elif defined(__tile__)
-#include <sys/backtrace.h>
-#else
-#include "tools/backtrace/backtrace.h"
-#endif

#include <arch/chip.h>

#if TILE_CHIP < 10


-#ifdef __tile__
#include <asm/opcode-tile.h>
-#else
-#include "tile-desc.h"
-#endif


#define TREG_SP 54
@@ -56,7 +39,6 @@


/* This implementation only makes sense for native tools. */
-#ifdef __tile__
/** Default function to read memory. */
static bool
bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra)
@@ -70,7 +52,6 @@
memcpy(result, (const void *)addr, size);
return true;
}
-#endif


/** Locates an instruction inside the given bundle that
@@ -505,12 +486,7 @@
VirtualAddress fp, initial_frame_caller_pc;

if (read_memory_func == NULL) {
-#ifdef __tile__
read_memory_func = bt_read_memory;
-#else
- /* Cross-tools MUST provide a way to read memory. */
- abort();
-#endif
}

/* Find out where we are in the initial frame. */
@@ -532,7 +508,9 @@
break;

default:
- abort();
+ /* Give up. */
+ fp = -1;
+ break;
}

/* The frame pointer should theoretically be aligned mod 8. If
@@ -567,7 +545,9 @@
break;

default:
- abort();
+ /* Give up. */
+ fp = -1;
+ break;
}

state->pc = pc;
diff -ru tile.old/kernel/compat.c tile/kernel/compat.c
--- tile.old/kernel/compat.c 2010-05-28 18:03:33.296340000 -0400
+++ tile/kernel/compat.c 2010-05-28 23:07:04.914154000 -0400
@@ -12,6 +12,9 @@
* more details.
*/

+/* Adjust unistd.h to provide 32-bit numbers and functions. */
+#define __SYSCALL_COMPAT
+
#include <linux/compat.h>
#include <linux/msg.h>
#include <linux/syscalls.h>
@@ -20,6 +23,8 @@
#include <linux/fcntl.h>
#include <linux/smp_lock.h>
#include <linux/uaccess.h>
+#include <linux/signal.h>
+#include <asm/syscalls.h>

/*
* Syscalls that take 64-bit numbers traditionally take them in 32-bit
@@ -74,110 +79,6 @@
}


-/*
- * The 32-bit runtime uses layouts for "struct stat" and "struct stat64"
- * that match the TILEPro/TILE64 runtime. Unfortunately the "stat64"
- * layout on existing 32 bit architectures doesn't quite match the
- * "normal" 64-bit bit layout, so we have to convert for that too.
- * Worse, it has an unaligned "st_blocks", so we have to use __copy_to_user().
- */
-
-int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
-{
- compat_ino_t ino;
-
- if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
- return -EOVERFLOW;
- if (kbuf->size >= 0x7fffffff)
- return -EOVERFLOW;
- ino = kbuf->ino;
- if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
- return -EOVERFLOW;
- if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
- __put_user(old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
- __put_user(ino, &ubuf->st_ino) ||
- __put_user(kbuf->mode, &ubuf->st_mode) ||
- __put_user(kbuf->nlink, &ubuf->st_nlink) ||
- __put_user(kbuf->uid, &ubuf->st_uid) ||
- __put_user(kbuf->gid, &ubuf->st_gid) ||
- __put_user(old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
- __put_user(kbuf->size, &ubuf->st_size) ||
- __put_user(kbuf->atime.tv_sec, &ubuf->st_atime) ||
- __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
- __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
- __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
- __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
- __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
- __put_user(kbuf->blksize, &ubuf->st_blksize) ||
- __put_user(kbuf->blocks, &ubuf->st_blocks))
- return -EFAULT;
- return 0;
-}
-
-static int cp_stat64(struct compat_stat64 __user *ubuf, struct kstat *stat)
-{
- if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat64)) ||
- __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
- __put_user(stat->ino, &ubuf->st_ino) ||
- __put_user(stat->mode, &ubuf->st_mode) ||
- __put_user(stat->nlink, &ubuf->st_nlink) ||
- __put_user(stat->uid, &ubuf->st_uid) ||
- __put_user(stat->gid, &ubuf->st_gid) ||
- __put_user(huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
- __put_user(stat->size, &ubuf->st_size) ||
- __put_user(stat->blksize, &ubuf->st_blksize) ||
- __copy_to_user(&ubuf->st_blocks, &stat->blocks, sizeof(long)) ||
- __put_user(stat->atime.tv_sec, &ubuf->st_atime) ||
- __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec) ||
- __put_user(stat->mtime.tv_sec, &ubuf->st_mtime) ||
- __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
- __put_user(stat->ctime.tv_sec, &ubuf->st_ctime) ||
- __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec))
- return -EFAULT;
- return 0;
-}
-
-long compat_sys_stat64(char __user *filename,
- struct compat_stat64 __user *statbuf)
-{
- struct kstat stat;
- int ret = vfs_stat(filename, &stat);
-
- if (!ret)
- ret = cp_stat64(statbuf, &stat);
- return ret;
-}
-
-long compat_sys_lstat64(char __user *filename,
- struct compat_stat64 __user *statbuf)
-{
- struct kstat stat;
- int ret = vfs_lstat(filename, &stat);
- if (!ret)
- ret = cp_stat64(statbuf, &stat);
- return ret;
-}
-
-long compat_sys_fstat64(unsigned int fd, struct compat_stat64 __user *statbuf)
-{
- struct kstat stat;
- int ret = vfs_fstat(fd, &stat);
- if (!ret)
- ret = cp_stat64(statbuf, &stat);
- return ret;
-}
-
-long compat_sys_fstatat64(int dfd, char __user *filename,
- struct compat_stat64 __user *statbuf, int flag)
-{
- struct kstat stat;
- int error;
-
- error = vfs_fstatat(dfd, filename, &stat, flag);
- if (error)
- return error;
- return cp_stat64(statbuf, &stat);
-}

long compat_sys_sched_rr_get_interval(compat_pid_t pid,
struct compat_timespec __user *interval)
@@ -252,3 +153,31 @@
out:
return err;
}
+
+/* Provide the compat syscall number to call mapping. */
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (compat_##call),
+
+/* The generic versions of these don't work for Tile. */
+#define compat_sys_msgrcv tile_compat_sys_msgrcv
+#define compat_sys_msgsnd tile_compat_sys_msgsnd
+
+/* See comments in sys.c */
+#define compat_sys_fadvise64 sys32_fadvise64
+#define compat_sys_fadvise64_64 sys32_fadvise64_64
+#define compat_sys_readahead sys32_readahead
+#define compat_sys_sync_file_range compat_sys_sync_file_range2
+
+/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
+#define compat_sys_stat64 sys_newstat
+#define compat_sys_lstat64 sys_newlstat
+#define compat_sys_fstat64 sys_newfstat
+#define compat_sys_fstatat64 sys_newfstatat
+
+/* Pass full 64-bit values through ptrace. */
+#define compat_sys_ptrace tile_compat_sys_ptrace
+
+void *compat_sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls-1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff -ru tile.old/kernel/compat_signal.c tile/kernel/compat_signal.c
--- tile.old/kernel/compat_signal.c 2010-05-28 18:03:33.328312000 -0400
+++ tile/kernel/compat_signal.c 2010-05-28 23:07:04.916159000 -0400
@@ -253,9 +253,9 @@
return err;
}

-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *regs)
+long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr,
+ struct pt_regs *regs)
{
stack_t uss, uoss;
int ret;
@@ -287,7 +287,7 @@
return ret;
}

-long compat_sys_rt_sigreturn(struct pt_regs *regs)
+long _compat_sys_rt_sigreturn(struct pt_regs *regs)
{
struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
@@ -308,7 +308,7 @@
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;

- if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+ if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
goto badframe;

return r0;
diff -ru tile.old/kernel/entry.S tile/kernel/entry.S
--- tile.old/kernel/entry.S 2010-05-28 18:03:33.383252000 -0400
+++ tile/kernel/entry.S 2010-05-28 23:07:04.915164000 -0400
@@ -17,19 +17,12 @@
#include <asm/unistd.h>
#include <asm/irqflags.h>

-
-
-
-
-/*
- * Don't use a local label in a #define because of compiler limitations.
- * Otherwise we end up with multiple copies of functions like skb_put().
- */
-
-
+#ifdef __tilegx__
+#define bnzt bnezt
+#endif

STD_ENTRY(current_text_addr)
- { move r0,lr; jrp lr }
+ { move r0, lr; jrp lr }
STD_ENDPROC(current_text_addr)

STD_ENTRY(_sim_syscall)
@@ -60,7 +53,7 @@
* careful not to write to the stack here.
*/
STD_ENTRY(kernel_execve)
- movei TREG_SYSCALL_NR_NAME,__NR_execve
+ moveli TREG_SYSCALL_NR_NAME, __NR_execve
swint1
jrp lr
STD_ENDPROC(kernel_execve)
@@ -146,34 +139,3 @@
nap
jrp lr
STD_ENDPROC(_cpu_idle)
-
-#ifdef CONFIG_FEEDBACK_COLLECT
- /* Provide the header of the .feedback section. */
- .section .feedback.start, "aw"
- .align 8
- .global __feedback_section_start
-__feedback_section_start:
- .word 0x4fd5adb1 /* FEEDBACK_HEADER_MAGIC */
- .word 1 /* FEEDBACK_HEADER_VERSION */
-
- .word 0
- .word __feedback_section_end - __feedback_section_start
- .word __feedback_functions_start - __feedback_section_start
- .word __feedback_functions_end - __feedback_section_start
-
- .global __feedback_edges_count
-__feedback_edges_count:
- .word 0 /* ConflictMissGraph starts out empty. */
- .word __feedback_section_end - __feedback_section_start
-
- /* No support for the linker hooks generated by the compiler. */
- .section .text.__feedback_function_entered,"ax"
- .weak __feedback_function_entered
-__feedback_function_entered:
- jrp lr
- ENDPROC(__feedback_function_entered)
- .weak __feedback_function_resumed
- .weak __feedback_function_entered_asm
-__feedback_function_resumed = __feedback_function_entered
-__feedback_function_entered_asm = __feedback_function_entered
-#endif
Only in tile.old/kernel: hardwall.c
diff -ru tile.old/kernel/head_32.S tile/kernel/head_32.S
--- tile.old/kernel/head_32.S 2010-05-28 18:03:33.399235000 -0400
+++ tile/kernel/head_32.S 2010-05-28 23:07:04.943136000 -0400
@@ -15,6 +15,7 @@
*/

#include <linux/linkage.h>
+#include <linux/init.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/thread_info.h>
@@ -28,7 +29,7 @@
* minimal setup needed to call the generic C routines.
*/

- .section .text.head, "ax"
+ __HEAD
ENTRY(_start)
/* Notify the hypervisor of what version of the API we want */
{
@@ -165,13 +166,13 @@
.org swapper_pg_dir + HV_L1_SIZE
END(swapper_pg_dir)

-.section ".init.data","wa"
/*
* Isolate swapper_pgprot to its own cache line, since each cpu
* starting up will read it using VA-is-PA and local homing.
* This would otherwise likely conflict with other data on the cache
* line, once we have set its permanent home in the page tables.
*/
+ __INITDATA
.align CHIP_L2_LINE_SIZE()
ENTRY(swapper_pgprot)
PTE 0, 0, HV_PTE_READABLE | HV_PTE_WRITABLE, 1
Only in tile.old/kernel: hugevmap.c
Only in tile.old/kernel: hv_drivers.c
Only in tile.old/kernel: hvglue.ld
Only in tile/kernel: hvglue.lds
diff -ru tile.old/kernel/intvec_32.S tile/kernel/intvec_32.S
--- tile.old/kernel/intvec_32.S 2010-05-28 18:03:33.414220000 -0400
+++ tile/kernel/intvec_32.S 2010-05-28 23:07:04.921151000 -0400
@@ -16,6 +16,7 @@

#include <linux/linkage.h>
#include <linux/errno.h>
+#include <linux/init.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
@@ -364,35 +365,6 @@

.endm

-#ifdef CONFIG_DATAPLANE
- /*
- * Branch to the specified label if this is not a dataplane tile,
- * clobbering r20, r21 and r22.
- */
- .macro branch_if_not_dataplane, label
- {
- mfspr r22, SYSTEM_SAVE_1_0
- moveli r21, lo16(dataplane_map)
- }
- {
- auli r21, r21, ha16(dataplane_map)
- mm r22, r22, zero, 0, LOG2_THREAD_SIZE-1
- }
- {
- shri r20, r22, 5
- }
- {
- s2a r20, r20, r21
- movei r21, 1
- }
- {
- lw r20, r20
- shl r21, r21, r22
- }
- and r20, r20, r21
- bzt r20, \label
- .endm
-#endif

/*
* Save the rest of the registers that we didn't save in the actual
@@ -640,32 +612,6 @@
.endif
#endif

-#ifdef CONFIG_DATAPLANE
- /* If we're not a dataplane tile, skip the call. */
- branch_if_not_dataplane 0f /* clobbers r20, r21, r22 */
-
- /* If we're not coming from user-space, don't worry about this. */
- PTREGS_PTR(r20, PTREGS_OFFSET_EX1)
- lw r20, r20
- andi r20, r20, SPR_EX_CONTEXT_1_1__PL_MASK
- bnz r20, 0f
-
- /* Like TRACE_IRQFLAGS, save r0-r3 before calling C code. */
- .ifnc \function,handle_syscall
- { move r30, r0; move r31, r1 }
- { move r32, r2; move r33, r3 }
- .endif
-
- /* Do dataplane tile TLB management for kernel entry. */
- jal homecache_tlb_defer_enter
- FEEDBACK_REENTER(\function)
-
- .ifnc \function,handle_syscall
- { move r0, r30; move r1, r31 }
- { move r2, r32; move r3, r33 }
- .endif
-0:
-#endif /* CONFIG_SMP */
.endm

.macro check_single_stepping, kind, not_single_stepping
@@ -905,26 +851,6 @@
/* Get base of stack in r32; note r30/31 are used as arguments here. */
GET_THREAD_INFO(r32)

-#ifdef CONFIG_HOMECACHE
- /*
- * If we're returning to user-space, see if we need to re-homecache
- * pages due to migration. Note that homecache_migrate() will
- * internally enable interrupts if current->mm != NULL.
- */
- {
- addli r0, r32, THREAD_INFO_HOMECACHE_CPU_OFFSET
- mfspr r1, SYSTEM_SAVE_1_0
- }
- {
- lw r0, r0
- mm r1, r1, zero, 0, LOG2_THREAD_SIZE-1
- }
- seq r0, r0, r1
- bbst r0, 1f
- jal homecache_migrate
- FEEDBACK_REENTER(interrupt_return)
-1:
-#endif

/* Check to see if there is any work to do before returning to user. */
{
@@ -971,14 +897,6 @@
lw r32, r32
}
bnz r0, 1f
-#ifdef CONFIG_DATAPLANE
- branch_if_not_dataplane 2f
- jal homecache_tlb_defer_exit
- FEEDBACK_REENTER(interrupt_return)
- bnz r30, 2f /* don't handle nohz stuff in an NMI */
- jal single_process_check_nohz
- FEEDBACK_REENTER(interrupt_return)
-#endif
j 2f
#if PT_FLAGS_DISABLE_IRQ != 1
# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use bbnst below
@@ -997,17 +915,6 @@
bzt r30, .Lrestore_regs
3:

-#ifdef CONFIG_OPROFILE
- /* We are relying on INT_PERF_COUNT at 33, and AUX_PERF_COUNT at 48 */
- {
- moveli r0, lo16(INT_MASK(INT_PERF_COUNT))
- bz r31, .Lrestore_regs
- }
-#if CHIP_HAS_AUX_PERF_COUNTERS()
- auli r0, r0, ha16(INT_MASK(INT_AUX_PERF_COUNT))
-#endif
- mtspr INTERRUPT_MASK_RESET_1_1, r0
-#endif

/*
* We now commit to returning from this interrupt, since we will be
@@ -1356,14 +1263,6 @@
PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
}
FEEDBACK_REENTER(handle_nmi)
-#ifdef CONFIG_OPROFILE
- jal op_enabled
- FEEDBACK_REENTER(handle_nmi)
- {
- movei r30, 1
- move r31, r0
- }
-#endif
j interrupt_return
STD_ENDPROC(handle_nmi)

@@ -1420,7 +1319,7 @@
pop_reg TREG_SYSCALL_NR_NAME, r11

/* Ensure that the syscall number is within the legal range. */
- moveli r21, NR_syscalls
+ moveli r21, __NR_syscalls
{
slt_u r21, TREG_SYSCALL_NR_NAME, r21
moveli r20, lo16(sys_call_table)
@@ -1622,12 +1521,12 @@

/* Put address of pt_regs in reg and jump. */
#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY_LOCAL(ptregs_##x); \
+ STD_ENTRY(x); \
{ \
PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j x \
+ j _##x \
}; \
- STD_ENDPROC(ptregs_##x)
+ STD_ENDPROC(x)

PTREGS_SYSCALL(sys_execve, r3)
PTREGS_SYSCALL(sys_sigaltstack, r2)
@@ -1635,15 +1534,14 @@

/* Save additional callee-saves to pt_regs, put address in reg and jump. */
#define PTREGS_SYSCALL_ALL_REGS(x, reg) \
- STD_ENTRY_LOCAL(ptregs_##x); \
+ STD_ENTRY(x); \
push_extra_callee_saves reg; \
- j x; \
- STD_ENDPROC(ptregs_##x)
+ j _##x; \
+ STD_ENDPROC(x)

PTREGS_SYSCALL_ALL_REGS(sys_fork, r0)
PTREGS_SYSCALL_ALL_REGS(sys_vfork, r0)
PTREGS_SYSCALL_ALL_REGS(sys_clone, r4)
-PTREGS_SYSCALL_ALL_REGS(sys_raise_fpe, r2)
PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)

/*
@@ -1670,12 +1568,12 @@
* we don't allow cmpxchg on the fc000000 memory region, since we only
* validate that the user address is below PAGE_OFFSET.
*
- * We place it in the .text.head section to ensure it is relatively
+ * We place it in the __HEAD section to ensure it is relatively
* near to the intvec_SWINT_1 code (reachable by a conditional branch).
*
* Must match register usage in do_page_fault().
*/
- .section .text.head,"ax"
+ __HEAD
.align 64
/* Align much later jump on the start of a cache line. */
#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
@@ -2040,10 +1938,10 @@
/* Include .intrpt1 array of interrupt vectors */
.section ".intrpt1", "ax"

-#ifndef CONFIG_OPROFILE
#define op_handle_perf_interrupt bad_intr
#define op_handle_aux_perf_interrupt bad_intr
-#endif
+
+#define do_hardwall_trap bad_intr

int_hand INT_ITLB_MISS, ITLB_MISS, \
do_page_fault, handle_interrupt_no_single_step
@@ -2106,6 +2004,3 @@

/* Synthetic interrupt delivered only by the simulator */
int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint
-
-/* Include .data array of syscalls */
-#include "syscall_table.S"
diff -ru tile.old/kernel/irq.c tile/kernel/irq.c
--- tile.old/kernel/irq.c 2010-05-28 18:03:33.416231000 -0400
+++ tile/kernel/irq.c 2010-05-28 23:07:04.949121000 -0400
@@ -31,65 +31,20 @@
INITIAL_INTERRUPTS_ENABLED;
EXPORT_PER_CPU_SYMBOL(interrupts_enabled_mask);

-static void chip_unmask_level(unsigned int irq);
-
/* Define per-tile device interrupt state */
DEFINE_PER_CPU(HV_IntrState, dev_intr_state);

DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
EXPORT_PER_CPU_SYMBOL(irq_stat);

-atomic_t irq_err_count;
-
-struct tile_irq_desc {
- void (*handler)(void *);
- void *dev_id;
-};
-
-struct tile_irq_desc tile_irq_desc[NR_IRQS] __cacheline_aligned;
-
-/**
- * tile_request_irq() - Allocate an interrupt handling instance.
- * @handler: the device driver interrupt handler to be called.
- * @dev_id: a cookie passed back to the handler function.
- * @index: index into the interrupt handler table to set. It's
- * derived from the interrupt bit mask allocated by the HV.
- *
- * Each device should call this function to register its interrupt
- * handler. dev_id must be globally unique. Normally the address of the
- * device data structure is used as the cookie.
- */
-void tile_request_irq(void (*handler)(void *), void *dev_id, int index)
-{
- struct tile_irq_desc *irq_desc;

- BUG_ON(!handler);
- BUG_ON(index < 0 || index >= NR_IRQS);
-
- irq_desc = tile_irq_desc + index;
- irq_desc->handler = handler;
- irq_desc->dev_id = dev_id;
-}
-EXPORT_SYMBOL(tile_request_irq);
-
-void tile_free_irq(int index)
-{
- struct tile_irq_desc *irq_desc;
-
- BUG_ON(index < 0 || index >= NR_IRQS);
-
- irq_desc = tile_irq_desc + index;
- irq_desc->handler = NULL;
- irq_desc->dev_id = NULL;
-}
-EXPORT_SYMBOL(tile_free_irq);

/*
* Interrupt dispatcher, invoked upon a hypervisor device interrupt downcall
*/
void tile_dev_intr(struct pt_regs *regs, int intnum)
{
- int count;
+ int irq;

/*
* Get the device interrupt pending mask from where the hypervisor
@@ -115,18 +70,12 @@
}
#endif

- for (count = 0; pending_dev_intr_mask; ++count) {
+ for (irq = 0; pending_dev_intr_mask; ++irq) {
if (pending_dev_intr_mask & 0x1) {
- struct tile_irq_desc *desc = &tile_irq_desc[count];
- if (desc->handler == NULL) {
- printk(KERN_ERR "Ignoring hv dev interrupt %d;"
- " handler not registered!\n", count);
- } else {
- desc->handler(desc->dev_id);
- }
+ generic_handle_irq(irq);

/* Count device irqs; IPIs are counted elsewhere. */
- if (count > HV_MAX_IPI_INTERRUPT)
+ if (irq > HV_MAX_IPI_INTERRUPT)
__get_cpu_var(irq_stat).irq_dev_intr_count++;
}
pending_dev_intr_mask >>= 1;
@@ -141,8 +90,61 @@
}


+/* Mask an interrupt. */
+static void hv_dev_irq_mask(unsigned int irq)
+{
+ HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
+ hv_disable_intr(p_intr_state, 1 << irq);
+}
+
+/* Unmask an interrupt. */
+static void hv_dev_irq_unmask(unsigned int irq)
+{
+ /* Re-enable the hypervisor to generate interrupts. */
+ HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
+ hv_enable_intr(p_intr_state, 1 << irq);
+}
+
+/*
+ * The HV doesn't latch incoming interrupts while an interrupt is
+ * disabled, so we need to reenable interrupts before running the
+ * handler.
+ *
+ * ISSUE: Enabling the interrupt this early avoids any race conditions
+ * but introduces the possibility of nested interrupt stack overflow.
+ * An imminent change to the HV IRQ model will fix this.
+ */
+static void hv_dev_irq_ack(unsigned int irq)
+{
+ hv_dev_irq_unmask(irq);
+}
+
+/*
+ * Since ack() reenables interrupts, there's nothing to do at eoi().
+ */
+static void hv_dev_irq_eoi(unsigned int irq)
+{
+}
+
+static struct irq_chip hv_dev_irq_chip = {
+ .typename = "hv_dev_irq_chip",
+ .ack = hv_dev_irq_ack,
+ .mask = hv_dev_irq_mask,
+ .unmask = hv_dev_irq_unmask,
+ .eoi = hv_dev_irq_eoi,
+};
+
+static struct irqaction resched_action = {
+ .handler = handle_reschedule_ipi,
+ .name = "resched",
+ .dev_id = handle_reschedule_ipi /* unique token */,
+};
+
void __init init_IRQ(void)
{
+ /* Bind IPI irqs. Does this belong somewhere else in init? */
+ tile_irq_activate(IRQ_RESCHEDULE);
+ BUG_ON(setup_irq(IRQ_RESCHEDULE, &resched_action));
}

void __cpuinit init_per_tile_IRQs(void)
@@ -155,40 +157,26 @@
if (rc != HV_OK)
panic("hv_dev_register_intr_state: error %d", rc);

-#ifdef CONFIG_SMP
- /* Bind the various IPI handlers. */
- tile_request_irq(handle_reschedule_ipi, NULL, IRQ_RESCHEDULE);
-#endif
}

-void tile_enable_irq(int irq)
+void tile_irq_activate(unsigned int irq)
{
- /* Re-enable the hypervisor to generate interrupts. */
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_enable_intr(p_intr_state, 1 << irq);
+ /*
+ * Paravirtualized drivers can call up to the HV to find out
+ * which irq they're associated with. The HV interface
+ * doesn't provide a generic call for discovering all valid
+ * IRQs, so drivers must call this method to initialize newly
+ * discovered IRQs.
+ *
+ * We could also just initialize all 32 IRQs at startup, but
+ * doing so would lead to a kernel fault if an unexpected
+ * interrupt fires and jumps to a NULL action. By defering
+ * the set_irq_chip_and_handler() call, unexpected IRQs are
+ * handled properly by handle_bad_irq().
+ */
+ hv_dev_irq_mask(irq);
+ set_irq_chip_and_handler(irq, &hv_dev_irq_chip, handle_percpu_irq);
}
-EXPORT_SYMBOL(tile_enable_irq);
-
-
-/*
-From struct irq_chip (same as hv_interrupt_type):
- const char name;
- unsigned int startup - has default, calls enable
- void shutdown - has default, calls disable
- void enable - has default, calls unmask
- void disable - has default, calls mask
- void ack - required
- void mask - required
- void mask_ack - optional - calls mask,ack
- void unmask - required - optional for some?
- void eoi - required for for fasteoi, percpu
- void end - not used
- void set_affinity
- int retrigger - optional
- int set_type - optional
- int set_wake - optional
- void release - optional
-*/

void ack_bad_irq(unsigned int irq)
{
@@ -237,123 +225,3 @@
}
return 0;
}
-
-/*
- * Mask a level sensitive interrupt.
- */
-static void chip_mask_ack_level(unsigned int irq)
-{
- /*
- * Nothing to do here because the downcall from the Hypervisor
- * will automatically mask the interrupt.
- */
-}
-
-/*
- * Disable an interrupt. Called, for example, at module unloading.
- */
-static void chip_disable_interrupt(unsigned int irq)
-{
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_disable_intr(p_intr_state, (1 << irq));
-}
-
-/*
- * Unmask a level sensitive interrupt.
- */
-static void chip_unmask_level(unsigned int irq)
-{
- /* Re-enable the hypervisor to generate interrupts. */
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_enable_intr(p_intr_state, (1 << irq));
-}
-
-/*
- * Mask an edge-triggered interrupt.
- */
-static void chip_mask_edge(unsigned int irq)
-{
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_disable_intr(p_intr_state, 1 << irq);
-}
-
-/*
- * Unmask an edge-triggered interrupt.
- */
-static void chip_unmask_edge(unsigned int irq)
-{
- /* Re-enable the hypervisor to generate interrupts. */
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_enable_intr(p_intr_state, 1 << irq);
-}
-
-
-static void chip_ack_edge(unsigned int irq)
-{
- /* Re-enable the hypervisor to generate interrupts. */
- HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
- hv_enable_intr(p_intr_state, 1 << irq);
-}
-
-/*
- * This is used with the handle_level_irq handler for legacy
- * interrupts.
- *
- * These functions can probably be reused with edge sensitive
- * interrupts.
- */
-static struct irq_chip chip_irq_legacy = {
- .typename = "TILE-LEGACY",
- .mask_ack = chip_mask_ack_level,
- .disable = chip_disable_interrupt,
- .eoi = NULL,
- .unmask = chip_unmask_level,
-};
-
-static struct irq_chip chip_irq_edge = {
- .typename = "TILE-EDGE",
- .mask = chip_mask_edge,
- .eoi = NULL,
- .ack = chip_ack_edge,
- .unmask = chip_unmask_edge,
-};
-
-/*
- * Handler for PCI IRQs. This acts as a shim between the IRQ
- * framework at the top of this file and the conventional linux framework.
- * Invoked from tile_dev_intr() as a handler, with interrupts disabled.
- */
-static void tile_irq_shim(void *dev)
-{
- int hv_irq = (int)(unsigned long)dev;
-
-
-
- generic_handle_irq(hv_irq);
-}
-
-/*
- * Set an IRQ to the level handler.
- *
- * This registers the IRQ with both the IRQ handler at the top of this file
- * and the linux IRQ handler, since the interrupts get passed off to
- * the Linux framework in the above shim.
- *
- */
-void tile_irq_request_level(int hv_irq)
-{
- tile_request_irq(tile_irq_shim, (void *)(long)hv_irq, hv_irq);
-
- set_irq_chip_and_handler(hv_irq, &chip_irq_legacy,
- handle_level_irq);
-}
-EXPORT_SYMBOL(tile_irq_request_level);
-
-void tile_irq_request_edge(int hv_irq)
-{
- tile_request_irq(tile_irq_shim, (void *)(long)hv_irq, hv_irq);
-
- set_irq_chip_and_handler(hv_irq, &chip_irq_edge,
- handle_edge_irq);
-}
-EXPORT_SYMBOL(tile_irq_request_edge);
Only in tile.old/kernel: memprof.c
diff -ru tile.old/kernel/module.c tile/kernel/module.c
--- tile.old/kernel/module.c 2010-05-28 18:03:33.480164000 -0400
+++ tile/kernel/module.c 2010-05-28 23:07:05.056022000 -0400
@@ -23,15 +23,15 @@
#include <asm/opcode-tile.h>
#include <asm/pgtable.h>

-
-
-
-
-
+#ifdef __tilegx__
+# define Elf_Rela Elf64_Rela
+# define ELF_R_SYM ELF64_R_SYM
+# define ELF_R_TYPE ELF64_R_TYPE
+#else
# define Elf_Rela Elf32_Rela
# define ELF_R_SYM ELF32_R_SYM
# define ELF_R_TYPE ELF32_R_TYPE
-
+#endif

#ifdef MODULE_DEBUG
#define DEBUGP printk
@@ -111,36 +111,36 @@
return -ENOEXEC;
}

+#ifdef __tilegx__
+/*
+ * Validate that the high 16 bits of "value" is just the sign-extension of
+ * the low 48 bits.
+ */
+static int validate_hw2_last(long value, struct module *me)
+{
+ if (((value << 16) >> 16) != value) {
+ printk("module %s: Out of range HW2_LAST value %#lx\n",
+ me->name, value);
+ return 0;
+ }
+ return 1;
+}

+/*
+ * Validate that "value" isn't too big to hold in a JumpOff relocation.
+ */
+static int validate_jumpoff(long value)
+{
+ /* Determine size of jump offset. */
+ int shift = __builtin_clzl(get_JumpOff_X1(create_JumpOff_X1(-1)));

+ /* Check to see if it fits into the relocation slot. */
+ long f = get_JumpOff_X1(create_JumpOff_X1(value));
+ f = (f << shift) >> shift;

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ return f == value;
+}
+#endif

int apply_relocate_add(Elf_Shdr *sechdrs,
const char *strtab,
@@ -172,7 +172,7 @@

#define MUNGE(func) (*location = ((*location & ~func(-1)) | func(value)))

-
+#ifndef __tilegx__
case R_TILE_32:
*(uint32_t *)location = value;
break;
@@ -193,45 +193,45 @@
value = (long) value >> 3; /* count by instrs */
MUNGE(create_JOffLong_X1);
break;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#else
+ case R_TILEGX_64:
+ *location = value;
+ break;
+ case R_TILEGX_IMM16_X0_HW2_LAST:
+ if (!validate_hw2_last(value, me))
+ return -ENOEXEC;
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X0_HW1:
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X0_HW0:
+ MUNGE(create_Imm16_X0);
+ break;
+ case R_TILEGX_IMM16_X1_HW2_LAST:
+ if (!validate_hw2_last(value, me))
+ return -ENOEXEC;
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X1_HW1:
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X1_HW0:
+ MUNGE(create_Imm16_X1);
+ break;
+ case R_TILEGX_JUMPOFF_X1:
+ value -= (unsigned long) location; /* pc-relative */
+ value = (long) value >> 3; /* count by instrs */
+ if (!validate_jumpoff(value)) {
+ printk("module %s: Out of range jump to"
+ " %#llx at %#llx (%p)\n", me->name,
+ sym->st_value + rel[i].r_addend,
+ rel[i].r_offset, location);
+ return -ENOEXEC;
+ }
+ MUNGE(create_JumpOff_X1);
+ break;
+#endif

#undef MUNGE

diff -ru tile.old/kernel/pci-dma.c tile/kernel/pci-dma.c
--- tile.old/kernel/pci-dma.c 2010-05-28 18:03:33.492152000 -0400
+++ tile/kernel/pci-dma.c 2010-05-28 23:07:04.955126000 -0400
@@ -158,6 +158,26 @@
}
EXPORT_SYMBOL(dma_unmap_page);

+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ unsigned long start = PFN_DOWN(dma_handle);
+ unsigned long end = PFN_DOWN(dma_handle + size - 1);
+ unsigned long i;
+
+ BUG_ON(!valid_dma_direction(direction));
+ for (i = start; i <= end; ++i)
+ homecache_flush_cache(pfn_to_page(i), 0);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
enum dma_data_direction direction)
{
@@ -177,10 +197,35 @@
BUG_ON(!valid_dma_direction(direction));
WARN_ON(nelems == 0 || sg[0].length == 0);

- for (i = 0; i < nelems; i++) {
- struct page *page =
- pfn_to_page(sg[i].dma_address >> PAGE_SHIFT);
- homecache_flush_cache(page, 0);
- }
+ for (i = 0; i < nelems; i++)
+ dma_sync_single_for_device(dev, sg[i].dma_address,
+ sg[i].dma_length, direction);
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_cpu(dev, dma_handle + offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_device(dev, dma_handle + offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+/*
+ * dma_alloc_noncoherent() returns non-cacheable memory, so there's no
+ * need to do any flushing here.
+ */
+void dma_cache_sync(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+}
+EXPORT_SYMBOL(dma_cache_sync);
Only in tile.old/kernel: pci.c
diff -ru tile.old/kernel/proc.c tile/kernel/proc.c
--- tile.old/kernel/proc.c 2010-05-28 18:03:33.515128000 -0400
+++ tile/kernel/proc.c 2010-05-28 23:07:04.965107000 -0400
@@ -89,511 +89,3 @@
.stop = c_stop,
.show = show_cpuinfo,
};
-
-
-/*
- * Support /proc/PID/pgtable
- */
-
-struct addr_marker {
- unsigned long start_address;
- const char *name;
-};
-
-/* Address space markers */
-static struct addr_marker address_markers[] = {
- { PAGE_OFFSET, "Low Kernel Mapping" },
-
-
-
-
-
-
-
-
- { 0, "vmalloc() Area" },
-# if CONFIG_NR_HUGE_VMAPS > 0
- { 0, "Huge vmap() Area" },
-# endif
-# ifdef CONFIG_HIGHMEM
- { 0, "Persistent kmap() Area" },
-# endif
- { 0, "Fixmap Area" },
- { MEM_SV_INTRPT, "Static Kernel Code" },
-
- { -1, NULL } /* End of list */
-};
-
-
-/* Address markers are not compile-time constants on 32-bit platforms. */
-static int __init address_markers_init(void)
-{
- struct addr_marker *marker = &address_markers[1];
- (marker++)->start_address = _VMALLOC_START;
-#if CONFIG_NR_HUGE_VMAPS > 0
- (marker++)->start_address = HUGE_VMAP_BASE;
-#endif
-#ifdef CONFIG_HIGHMEM
- (marker++)->start_address = PKMAP_BASE;
-#endif
- (marker++)->start_address = FIXADDR_START;
-
- return 0;
-}
-arch_initcall(address_markers_init);
-
-
-int arch_proc_pgtable_show(struct seq_file *m, struct mm_struct *mm,
- unsigned long vaddr, pte_t *ptep, void **datap)
-{
- pte_t pte = *ptep;
- struct addr_marker *marker;
-
- /*
- * We use %08 as the format here to match /proc/self/maps,
- * which does this regardless of the underlying size of "long".
- */
- seq_printf(m, "%08lx %c%c%c", vaddr,
- hv_pte_get_readable(pte) ?
- (hv_pte_get_accessed(pte) ? 'R' : 'r') : '-',
- hv_pte_get_writable(pte) ?
- (hv_pte_get_dirty(pte) ? 'W' : 'w') : '-',
- hv_pte_get_executable(pte) ? 'X' : '-');
- seq_printf(m, " PA=%010llx (N%d)",
- ((u64) hv_pte_get_pfn(pte)) << PAGE_SHIFT,
- pfn_to_nid(hv_pte_get_pfn(pte)));
- if (!hv_pte_get_present(pte))
- seq_printf(m, " NotPresent");
- if (pte_huge(pte))
- seq_printf(m, " Huge");
- if (hv_pte_get_migrating(pte))
- seq_printf(m, " Migrating");
- if (hv_pte_get_cached_priority(pte))
- seq_printf(m, " Priority");
- if (hv_pte_get_global(pte))
- seq_printf(m, " Global");
- if (!hv_pte_get_user(pte))
- seq_printf(m, " Kernel");
-
- /*
- * If no caching modes are enabled, show "CacheNone",
- * otherwise show the details of what caching there is.
- */
- if (hv_pte_get_mode(pte) == HV_PTE_MODE_UNCACHED) {
- seq_printf(m, " CacheNone\n");
- return 0;
- }
-
-#if CHIP_HAS_NC_AND_NOALLOC_BITS()
- if (hv_pte_get_no_alloc_l1(pte) && hv_pte_get_no_alloc_l2(pte))
- seq_printf(m, " NoLocal");
- else if (hv_pte_get_no_alloc_l1(pte))
- seq_printf(m, " NoL1");
- else if (hv_pte_get_no_alloc_l2(pte))
- seq_printf(m, " NoL2");
-#endif
-
- switch (hv_pte_get_mode(pte)) {
- case HV_PTE_MODE_CACHE_NO_L3:
- seq_printf(m, " NoHome");
- break;
-
- case HV_PTE_MODE_CACHE_TILE_L3:
- seq_printf(m, " Home=%d", get_remote_cache_cpu(pte));
- if (hv_pte_get_nc(pte))
- seq_printf(m, " NC");
- break;
-
-#if CHIP_HAS_CBOX_HOME_MAP()
- case HV_PTE_MODE_CACHE_HASH_L3:
- seq_printf(m, " HashHome");
- if (hv_pte_get_nc(pte))
- seq_printf(m, " NC");
- break;
-#endif
-
- case 0:
- /* Special case 0, since it often means a cleared PTE. */
- break;
-
- default:
- seq_printf(m, " UnknownMode_%d", hv_pte_get_mode(pte));
- break;
- }
-
- if (vaddr >= PAGE_OFFSET) {
- marker = (struct addr_marker *)*datap;
- if (marker == NULL)
- marker = address_markers;
- if (vaddr >= marker->start_address) {
- while (vaddr >= marker[1].start_address)
- ++marker;
- seq_printf(m, " # %s", marker->name);
- ++marker;
- }
- *datap = marker;
- }
-
- seq_printf(m, "\n");
- return 0;
-}
-
-/*
- * Support /proc/tile directory
- */
-
-struct proc_dir_entry *proc_tile_root;
-
-/* Define a /proc/tile init routine, common to both simple/seq macros. */
-#define PROC_INIT(name) \
-static void proc_tile_##name##_init(void) \
-{ \
- struct proc_dir_entry *entry = \
- create_proc_entry(#name, 0444, proc_tile_root); \
- if (entry) \
- entry->proc_fops = &proc_tile_##name##_fops; \
-}
-
-/* Define a simple /proc/tile file which just returns one string. */
-#define SIMPLE_PROC_ENTRY(name, format, args...) \
-static ssize_t proc_tile_##name##_read(struct file *file, char __user *buf, \
- size_t count, loff_t *ppos) \
-{ \
- char tmpbuf[256]; \
- ssize_t length = scnprintf(tmpbuf, sizeof(tmpbuf), format, ## args); \
- return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); \
-} \
-static const struct file_operations proc_tile_##name##_fops = { \
- .read = proc_tile_##name##_read, \
-}; \
-PROC_INIT(name)
-
-/*
- * Define a /proc/tile file which uses a seq_file to provide a more
- * complex set of data.
- */
-#define SEQ_PROC_ENTRY(name) \
-static int proc_tile_##name##_show(struct seq_file *m, void *v); \
-static int proc_tile_##name##_open(struct inode *inode, struct file *file) \
-{ \
- return single_open(file, proc_tile_##name##_show, NULL); \
-} \
-static const struct file_operations proc_tile_##name##_fops = { \
- .open = proc_tile_##name##_open, \
- .read = seq_read, \
- .llseek = seq_lseek, \
- .release = single_release, \
-}; \
-PROC_INIT(name)
-
-/* Simple /proc/tile files. */
-SIMPLE_PROC_ENTRY(grid, "%u\t%u\n", smp_width, smp_height)
-
-/* More complex /proc/tile files. */
-static void proc_tile_seq_strconf(struct seq_file *sf, char* what,
- uint32_t query)
-{
- char tmpbuf[256];
- char *bufptr = tmpbuf;
- int buflen = sizeof(tmpbuf);
- int len = hv_confstr(query, (HV_VirtAddr) bufptr, buflen);
-
- if (len > buflen) {
- bufptr = kmalloc(len, GFP_KERNEL);
- if (!bufptr)
- return;
- buflen = len;
- len = hv_confstr(query, (HV_VirtAddr) bufptr, buflen);
- }
-
- bufptr[buflen - 1] = 0;
- /* Length includes the trailing null, so if it's 1, it's empty. */
- if (len > 1) {
- if (what)
- seq_printf(sf, "%s: %s\n", what, bufptr);
- else
- seq_printf(sf, "%s", bufptr);
- }
-
- if (bufptr != tmpbuf)
- kfree(bufptr);
-}
-
-SEQ_PROC_ENTRY(environment)
-static int proc_tile_environment_show(struct seq_file *sf, void *v)
-{
- long cpu_temp = hv_sysconf(HV_SYSCONF_CPU_TEMP);
- long board_temp = hv_sysconf(HV_SYSCONF_BOARD_TEMP);
-
- if (cpu_temp < 0)
- seq_printf(sf, "chip_temp: unknown\n");
- else
- seq_printf(sf, "chip_temp: %ld\n",
- cpu_temp - HV_SYSCONF_TEMP_KTOC);
-
- if (board_temp < 0)
- seq_printf(sf, "board_temp: unknown\n");
- else
- seq_printf(sf, "board_temp: %ld\n",
- board_temp - HV_SYSCONF_TEMP_KTOC);
-
- return 0;
-}
-
-SEQ_PROC_ENTRY(hv)
-static int proc_tile_hv_show(struct seq_file *sf, void *v)
-{
- proc_tile_seq_strconf(sf, "version", HV_CONFSTR_HV_SW_VER);
- proc_tile_seq_strconf(sf, "config_version", HV_CONFSTR_HV_CONFIG_VER);
- return 0;
-}
-
-SEQ_PROC_ENTRY(hvconfig)
-static int proc_tile_hvconfig_show(struct seq_file *sf, void *v)
-{
- proc_tile_seq_strconf(sf, NULL, HV_CONFSTR_HV_CONFIG);
- return 0;
-}
-
-SEQ_PROC_ENTRY(board)
-static int proc_tile_board_show(struct seq_file *sf, void *v)
-{
- proc_tile_seq_strconf(sf, "board_part", HV_CONFSTR_BOARD_PART_NUM);
- proc_tile_seq_strconf(sf, "board_serial", HV_CONFSTR_BOARD_SERIAL_NUM);
- proc_tile_seq_strconf(sf, "chip_serial", HV_CONFSTR_CHIP_SERIAL_NUM);
- proc_tile_seq_strconf(sf, "chip_revision", HV_CONFSTR_CHIP_REV);
- proc_tile_seq_strconf(sf, "board_revision", HV_CONFSTR_BOARD_REV);
- proc_tile_seq_strconf(sf, "board_description", HV_CONFSTR_BOARD_DESC);
- proc_tile_seq_strconf(sf, "mezz_part", HV_CONFSTR_MEZZ_PART_NUM);
- proc_tile_seq_strconf(sf, "mezz_serial", HV_CONFSTR_MEZZ_SERIAL_NUM);
- proc_tile_seq_strconf(sf, "mezz_revision", HV_CONFSTR_MEZZ_REV);
- proc_tile_seq_strconf(sf, "mezz_description", HV_CONFSTR_MEZZ_DESC);
- return 0;
-}
-
-SEQ_PROC_ENTRY(switch)
-static int proc_tile_switch_show(struct seq_file *sf, void *v)
-{
- proc_tile_seq_strconf(sf, "control", HV_CONFSTR_SWITCH_CONTROL);
- return 0;
-}
-
-SEQ_PROC_ENTRY(memory)
-static int proc_tile_memory_show(struct seq_file *sf, void *v)
-{
- int node;
- int ctrl;
- HV_Coord coord = { 0, 0 };
- /*
- * We make two passes here; one through our memnodes to display
- * which controllers they correspond with, and one through all
- * controllers to get their speeds. We may not actually have
- * access to all of the controllers whose speeds we retrieve, but
- * we get them because they're useful for mcstat, which provides
- * stats for physical controllers whether we're using them or not.
- */
- for (node = 0; node < MAX_NUMNODES; node++) {
- ctrl = node_controller[node];
- if (ctrl >= 0)
- seq_printf(sf, "controller_%d_node: %d\n", ctrl, node);
- }
- /*
- * Note that we use MAX_NUMNODES as the limit for the controller
- * loop because we don't have anything better.
- */
- for (ctrl = 0; ctrl < MAX_NUMNODES; ctrl++) {
- HV_MemoryControllerInfo info =
- hv_inquire_memory_controller(coord, ctrl);
- if (info.speed)
- seq_printf(sf, "controller_%d_speed: %llu\n",
- ctrl, info.speed);
- }
- return 0;
-}
-
-#ifdef CONFIG_DATAPLANE
-SEQ_PROC_ENTRY(dataplane)
-static int proc_tile_dataplane_show(struct seq_file *sf, void *v)
-{
- int cpu;
- int space = 0;
- for_each_cpu(cpu, &dataplane_map) {
- if (space)
- seq_printf(sf, " ");
- else
- space = 1;
- seq_printf(sf, "%d", cpu);
- }
- if (space)
- seq_printf(sf, "\n");
- return 0;
-}
-#else
-#define proc_tile_dataplane_init() do {} while (0)
-#endif
-
-SEQ_PROC_ENTRY(interrupts)
-static int proc_tile_interrupts_show(struct seq_file *sf, void *v)
-{
- int i;
-
- seq_printf(sf, "%-8s%8s%8s%8s%8s%8s%8s%8s\n", "",
- "timer", "syscall", "resched", "hvflush", "SMPcall",
- "hvmsg", "devintr");
-
- for_each_online_cpu(i) {
- irq_cpustat_t *irq = &per_cpu(irq_stat, i);
- seq_printf(sf, "%-8d%8d%8d%8d%8d%8d%8d%8d\n", i,
- irq->irq_timer_count,
- irq->irq_syscall_count,
- irq->irq_resched_count,
- irq->irq_hv_flush_count,
- irq->irq_call_count,
- irq->irq_hv_msg_count,
- irq->irq_dev_intr_count);
- }
- return 0;
-}
-
-#ifdef CONFIG_FEEDBACK_COLLECT
-
-extern void *__feedback_edges_ptr;
-extern long __feedback_edges_size;
-extern void flush_my_deferred_graph(void *dummy);
-
-ssize_t feedback_read(struct file *file, char __user *buf, size_t size,
- loff_t *ppos)
-{
- void *start = __feedback_section_start;
- size_t avail = __feedback_section_end - __feedback_section_start;
-
- if (*ppos == 0)
- on_each_cpu_mask(flush_my_deferred_graph, NULL,
- 1, cpu_online_mask);
- if (*ppos < avail) {
- /* Return a short read as we cross into edges data. */
- if (*ppos + size > avail)
- size = avail - *ppos;
- } else {
- /* Bias the start to below the actual edges data. */
- start = __feedback_edges_ptr - avail;
- avail += __feedback_edges_size;
- }
-
- return simple_read_from_buffer(buf, size, ppos, start, avail);
-}
-static const struct file_operations proc_tile_feedback_fops = {
- .read = feedback_read
-};
-PROC_INIT(feedback)
-#endif
-
-static int __init proc_tile_init(void)
-{
- proc_tile_root = proc_mkdir("tile", NULL);
- if (!proc_tile_root)
- return 0;
-
- proc_tile_grid_init();
- proc_tile_environment_init();
- proc_tile_board_init();
- proc_tile_switch_init();
- proc_tile_hv_init();
- proc_tile_hvconfig_init();
- proc_tile_memory_init();
- proc_tile_dataplane_init();
- proc_tile_interrupts_init();
-#ifdef CONFIG_FEEDBACK_COLLECT
- proc_tile_feedback_init();
-#endif
-
- return 0;
-}
-
-arch_initcall(proc_tile_init);
-
-/*
- * Support /proc/sys/tile directory
- */
-
-
-static ctl_table unaligned_table[] = {
- {
- .procname = "enabled",
- .data = &unaligned_fixup,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "printk",
- .data = &unaligned_printk,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "count",
- .data = &unaligned_fixup_count,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {}
-};
-
-
-static ctl_table tile_root[] = {
-
- {
- .procname = "unaligned_fixup",
- .mode = 0555,
- unaligned_table
- },
-
- {
- .procname = "crashinfo",
- .data = &show_crashinfo,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {}
-};
-
-#if CHIP_HAS_CBOX_HOME_MAP()
-static ctl_table hash_default_table[] = {
- {
- .procname = "hash_default",
- .data = &hash_default,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {}
-};
-#endif
-
-static struct ctl_path tile_path[] = {
- { .procname = "tile" },
- { }
-};
-
-static int __init proc_sys_tile_init(void)
-{
- (void) register_sysctl_paths(tile_path, tile_root);
-
-#if CHIP_HAS_CBOX_HOME_MAP()
- /*
- * Register this special file (which always has value "1")
- * only if we are actually in this mode, so we just need
- * to "stat" the file to perform the check.
- */
- if (hash_default)
- register_sysctl_paths(tile_path, hash_default_table);
-#endif
-
- return 0;
-}
-
-arch_initcall(proc_sys_tile_init);
diff -ru tile.old/kernel/process.c tile/kernel/process.c
--- tile.old/kernel/process.c 2010-05-28 18:03:33.537105000 -0400
+++ tile/kernel/process.c 2010-05-28 23:07:04.971098000 -0400
@@ -26,7 +26,6 @@
#include <linux/syscalls.h>
#include <asm/system.h>
#include <asm/stack.h>
-#include <asm/hardwall.h>
#include <asm/homecache.h>
#include <arch/chip.h>
#include <arch/abi.h>
@@ -66,28 +65,6 @@
extern void _cpu_idle(void);
int cpu = smp_processor_id();

-#ifdef CONFIG_HOMECACHE
- /*
- * If we enter cpu_idle with our stack still set to be the
- * initial stack, we switch to a new stack page now (and
- * free the initial stack back to the heap).
- * This allows the boot cpu's idle process to run with a
- * stack that has proper homecaching.
- */
- if (current_thread_info() == &init_thread_union.thread_info) {
- struct thread_info *ti = alloc_thread_info(current);
- struct task_struct *p = current;
- struct page *page = virt_to_page(current_thread_info());
- *ti = *current_thread_info();
- p->stack = ti;
- p->thread.ksp = KSTK_TOP(p);
- clear_bit(PG_homecache_nomigrate, &page->flags);
- ClearPageReserved(page);
- cpu_idle_on_new_stack(current_thread_info(), p->thread.ksp,
- next_current_ksp0(p));
- /*NOTREACHED*/
- }
-#endif

current_thread_info()->status |= TS_POLLING;

@@ -121,11 +98,7 @@
local_irq_enable();
current_thread_info()->status |= TS_POLLING;
}
-#ifdef CONFIG_DATAPLANE
- tick_nohz_restart_sched_tick(0);
-#else
tick_nohz_restart_sched_tick();
-#endif
preempt_enable_no_resched();
schedule();
preempt_disable();
@@ -136,25 +109,12 @@
{
struct page *page;
int flags = GFP_KERNEL;
-#ifdef CONFIG_HOMECACHE
- int home;
-#endif

#ifdef CONFIG_DEBUG_STACK_USAGE
flags |= __GFP_ZERO;
#endif

-#ifdef CONFIG_HOMECACHE
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (kstack_hash)
- home = PAGE_HOME_HASH;
- else
-#endif
- home = PAGE_HOME_HERE;
- page = homecache_alloc_pages(flags, THREAD_SIZE_ORDER, home);
-#else
page = alloc_pages(flags, THREAD_SIZE_ORDER);
-#endif
if (!page)
return 0;

@@ -169,16 +129,6 @@
{
struct single_step_state *step_state = info->step_state;

- /*
- * We free a thread_info from the context of the task that has
- * been scheduled next, so the original task is already dead.
- * Calling deactivate here just frees up the data structures.
- * If the task we're freeing held the last reference to a
- * hardwall fd, it would have been released prior to this point
- * anyway via exit_files(), and "hardwall" would be NULL by now.
- */
- if (info->task->thread.hardwall)
- hardwall_deactivate(info->task);

if (step_state) {

@@ -196,10 +146,6 @@
* somehow, or we should associate the buffer(s) with the
* mm itself so we can clean them up that way.
*/
-
-
-
-
kfree(step_state);
}

@@ -289,13 +235,7 @@
p->thread.proc_status = 0;
#endif

- /* New thread does not own any networks. */
- p->thread.hardwall = NULL;

-#ifdef CONFIG_HOMECACHE
- /* New thread gets memory without any homecache overrides. */
- p->thread.homecache_desired_home = PAGE_HOME_UNKNOWN;
-#endif

/*
* Start the new thread with the current architecture state
@@ -546,13 +486,6 @@
}
#endif

- /* Enable or disable access to the network registers appropriately. */
- if (prev->thread.hardwall != NULL) {
- if (next->thread.hardwall == NULL)
- restrict_network_mpls();
- } else if (next->thread.hardwall != NULL) {
- grant_network_mpls();
- }

/*
* Switch kernel SP, PC, and callee-saved registers.
@@ -563,14 +496,14 @@
return __switch_to(prev, next, next_current_ksp0(next));
}

-SYSCALL_DEFINE1(fork, struct pt_regs *, regs)
+int _sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}

-SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
- int __user *, parent_tidptr, int __user *, child_tidptr,
- struct pt_regs *, regs)
+int _sys_clone(unsigned long clone_flags, unsigned long newsp,
+ int __user *parent_tidptr, int __user *child_tidptr,
+ struct pt_regs *regs)
{
if (!newsp)
newsp = regs->sp;
@@ -578,7 +511,7 @@
parent_tidptr, child_tidptr);
}

-SYSCALL_DEFINE1(vfork, struct pt_regs *, regs)
+int _sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
regs, 0, NULL, NULL);
@@ -587,8 +520,8 @@
/*
* sys_execve() executes a new program.
*/
-SYSCALL_DEFINE4(execve, char __user *, path, char __user *__user *, argv,
- char __user *__user *, envp, struct pt_regs *, regs)
+int _sys_execve(char __user *path, char __user *__user *argv,
+ char __user *__user *envp, struct pt_regs *regs)
{
int error;
char *filename;
@@ -604,8 +537,8 @@
}

#ifdef CONFIG_COMPAT
-int compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *regs)
+int _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs *regs)
{
int error;
char *filename;
@@ -683,13 +616,13 @@
/* Nothing */
}

-
-
-
-
+#ifdef __tilegx__
+# define LINECOUNT 3
+# define EXTRA_NL "\n"
+#else
# define LINECOUNT 4
# define EXTRA_NL ""
-
+#endif

void show_regs(struct pt_regs *regs)
{
Only in tile.old/kernel: sections.lds
diff -ru tile.old/kernel/setup.c tile/kernel/setup.c
--- tile.old/kernel/setup.c 2010-05-28 18:03:33.590046000 -0400
+++ tile/kernel/setup.c 2010-05-28 23:07:05.054017000 -0400
@@ -162,7 +162,7 @@
early_param("pci_reserve", setup_pci_reserve);
#endif

-
+#ifndef __tilegx__
/*
* vmalloc=size forces the vmalloc area to be exactly 'size' bytes.
* This can be used to increase (or decrease) the vmalloc area.
@@ -182,7 +182,7 @@
return 0;
}
early_param("vmalloc", parse_vmalloc);
-
+#endif

#ifdef CONFIG_HIGHMEM
/*
@@ -287,7 +287,7 @@
}

hv_store_mapping((HV_VirtAddr)_stext,
- (uint32_t)(_etext - _stext), 0);
+ (uint32_t)(_einittext - _stext), 0);
}

/*
@@ -302,10 +302,10 @@
#ifdef CONFIG_HIGHMEM
long highmem_pages;
#endif
-
+#ifndef __tilegx__
int cap;
-
-#if defined(CONFIG_HIGHMEM)
+#endif
+#if defined(CONFIG_HIGHMEM) || defined(__tilegx__)
long lowmem_pages;
#endif

@@ -325,13 +325,13 @@
continue;
}
#endif
-
+#ifndef __tilegx__
if ((unsigned long)range.start) {
printk("Range not at 4GB multiple: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
-
+#endif
if ((range.start & (HPAGE_SIZE-1)) != 0 ||
(range.size & (HPAGE_SIZE-1)) != 0) {
unsigned long long start_pa = range.start;
@@ -388,14 +388,14 @@
size = range.size >> PAGE_SHIFT;
end = start + size;

-
+#ifndef __tilegx__
if (((HV_PhysAddr)end << PAGE_SHIFT) !=
(range.start + range.size)) {
printk("PAs too high to represent: %#llx..%#llx\n",
range.start, range.start + range.size);
continue;
}
-
+#endif
#ifdef CONFIG_PCI
/*
* Blocks that overlap the pci reserved region must
@@ -433,7 +433,7 @@
node_set(i, node_possible_map);
}

-
+#ifndef __tilegx__
/*
* For 4KB pages, mem_map "struct page" data is 1% of the size
* of the physical memory, so can be quite big (640 MB for
@@ -462,7 +462,7 @@
dropped_pages >> (20 - PAGE_SHIFT));
printk(KERN_WARNING "Consider using a larger page size.\n");
}
-
+#endif

/* Heap starts just above the last loaded address. */
min_low_pfn = PFN_UP((unsigned long)_end - PAGE_OFFSET);
@@ -486,7 +486,7 @@
/* Set max_low_pfn based on what node 0 can directly address. */
max_low_pfn = node_end_pfn[0];

-
+#ifndef __tilegx__
if (node_end_pfn[0] > MAXMEM_PFN) {
printk(KERN_WARNING "Only using %ldMB LOWMEM.\n",
MAXMEM>>20);
@@ -504,17 +504,17 @@
node_end_pfn[i] = 0;
}
high_memory = __va(node_end_pfn[0]);
-
-
-
-
-
-
-
-
-
-
-
+#else
+ lowmem_pages = 0;
+ for (i = 0; i < MAX_NUMNODES; ++i) {
+ int pages = node_end_pfn[i] - node_start_pfn[i];
+ lowmem_pages += pages;
+ if (pages)
+ high_memory = pfn_to_kaddr(node_end_pfn[i]);
+ }
+ printk(KERN_NOTICE "%ldMB memory available.\n",
+ pages_to_mb(lowmem_pages));
+#endif
#endif
}

@@ -556,13 +556,6 @@
crashk_res.end - crashk_res.start + 1, 0);
#endif

-#ifdef CONFIG_HOMECACHE
- /*
- * Ready for homecache page allocation; we don't set this statically
- * just to simplify header inclusion issues.
- */
- current->thread.homecache_desired_home = PAGE_HOME_UNKNOWN;
-#endif
}

void *__init alloc_remap(int nid, unsigned long size)
@@ -884,15 +877,8 @@
*/
__insn_mtspr(SPR_MPL_WORLD_ACCESS_SET_0, 1);

- /*
- * Static network is not restricted for now.
- * It should eventually be tied into hardwalling once
- * we want to implement the static network draining code.
- */
-
-
-
#if CHIP_HAS_SN()
+ /* Static network is not restricted. */
__insn_mtspr(SPR_MPL_SN_ACCESS_SET_0, 1);
#endif
#if CHIP_HAS_SN_PROC()
@@ -1025,7 +1011,7 @@

static void __init validate_va(void)
{
-
+#ifndef __tilegx__ /* FIXME: GX: probably some validation relevant here */
/*
* Similarly, make sure we're only using allowed VAs.
* We assume we can contiguously use MEM_USER_INTRPT .. MEM_HV_INTRPT,
@@ -1064,7 +1050,7 @@
"Reconfigure the kernel with fewer NR_HUGE_VMAPS\n"
"or smaller VMALLOC_RESERVE.\n",
VMALLOC_START);
-
+#endif
}

/*
@@ -1193,19 +1179,11 @@
#endif
}

-#ifdef CONFIG_DATAPLANE
-struct cpumask __write_once dataplane_map;
-EXPORT_SYMBOL(dataplane_map);
-#endif

static int __init dataplane(char *str)
{
-#ifdef CONFIG_DATAPLANE
- return str ? cpulist_parse_crop(str, &dataplane_map) : -EINVAL;
-#else
printk("WARNING: dataplane support disabled in this kernel\n");
return 0;
-#endif
}

early_param("dataplane", dataplane);
@@ -1257,10 +1235,6 @@

setup_cpu_maps();

-#ifdef CONFIG_DATAPLANE
- /* Make sure dataplane is only on valid cpus. */
- cpumask_and(&dataplane_map, &dataplane_map, cpu_possible_mask);
-#endif

#ifdef CONFIG_PCI
/*
@@ -1296,7 +1270,6 @@
zone_sizes_init();
set_page_homes();
setup_mpls();
- reset_network_state();
setup_clock();
load_hv_initrd();
}
@@ -1392,12 +1365,8 @@
virt_to_pte(NULL, (unsigned long)ptr + i);
pte_t pte = *ptep;
BUG_ON(pfn != pte_pfn(pte));
-#ifdef CONFIG_HOMECACHE
- set_page_home(pg, cpu);
-#else
pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
pte = set_remote_cache_cpu(pte, cpu);
-#endif
set_pte(ptep, pte);

/* Update the lowmem mapping for consistency. */
diff -ru tile.old/kernel/signal.c tile/kernel/signal.c
--- tile.old/kernel/signal.c 2010-05-28 18:03:33.644003000 -0400
+++ tile/kernel/signal.c 2010-05-28 23:07:05.059009000 -0400
@@ -39,14 +39,12 @@

#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))

-/* Forward reference. */
-static void dump_mem(unsigned long address);

/* Caller before callee in this file; other callee is in assembler */
void do_signal(struct pt_regs *regs);

-SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
- stack_t __user *, uoss, struct pt_regs *, regs)
+int _sys_sigaltstack(const stack_t __user *uss,
+ stack_t __user *uoss, struct pt_regs *regs)
{
return do_sigaltstack(uss, uoss, regs->sp);
}
@@ -75,7 +73,7 @@
return err;
}

-SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
+int _sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
@@ -245,24 +243,6 @@
{
int ret;

- /*
- * If crashinfo is set to "2", we will report on kernel-generated
- * memory access signals here, even if they are being handled.
- */
- if (show_crashinfo > 1 && info->si_code > 0) {
- switch (info->si_signo) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
- case SIGBUS:
- printk("\nHandling user fault: signal %d, code %#x,"
- " trap %d, address %#lx\n",
- info->si_signo, info->si_code, info->si_trapno,
- (unsigned long)(info->si_addr));
- show_regs(regs);
- dump_mem((unsigned long) (info->si_addr));
- }
- }

/* Are we from a system call? */
if (regs->faultnum == INT_SWINT_1) {
@@ -377,148 +357,3 @@
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
-
-SYSCALL_DEFINE3(raise_fpe, int, code, unsigned long, addr,
- struct pt_regs *, regs)
-{
- struct siginfo info;
-
- /*
- * If we are coming here from kernel level, we must have tried
- * to do a divide-by-zero in kernel code. For now, just panic.
- */
- if (EX1_PL(regs->ex1) != USER_PL)
- panic("Kernel divide by zero");
-
- if (code & __SI_MASK)
- return -EINVAL; /* user space doesn't use the high bits */
-
- /*
- * OR in the kernel value for __SI_FAULT so that the structure
- * gets copied to userspace correctly.
- */
- code |= __SI_FAULT;
-
- /* Only allow raising valid codes */
- switch (code) {
- case FPE_INTDIV:
- case FPE_INTOVF:
- case FPE_FLTDIV:
- case FPE_FLTOVF:
- case FPE_FLTUND:
- case FPE_FLTRES:
- case FPE_FLTINV:
- case FPE_FLTSUB:
- break;
- default:
- return -EINVAL;
- }
-
- memset(&info, 0, sizeof(info));
- info.si_signo = SIGFPE;
- info.si_code = code;
- info.si_addr = (void *)addr;
- info.si_trapno = -1; /* no corresponding hardware trap */
-
- return group_send_sig_info(info.si_signo, &info, current);
-}
-
-
-
-
-int show_crashinfo;
-
-
-static int __init crashinfo(char *str)
-{
- unsigned long val;
- if (str == NULL) {
- show_crashinfo = 1;
- return 0;
- }
- if (strict_strtoul(str, 0, &val) != 0)
- return 0;
- show_crashinfo = val;
- printk("User crash reports will%s be generated on the console\n",
- show_crashinfo ? "" : " not");
- return 1;
-}
-__setup("crashinfo", crashinfo);
-
-static void dump_mem(unsigned long address)
-{
- unsigned long addr;
- enum { region_size = 256, bytes_per_line = 16 };
- int i, j;
- int found_readable_mem = 0;
-
- if (!access_ok(VERIFY_READ, address, 1)) {
- printk("\nNot dumping at address %#lx (kernel address)\n",
- address);
- return;
- }
-
- addr = (address & -bytes_per_line) - region_size/2;
- if (addr > address)
- addr = 0;
- for (i = 0; i < region_size;
- addr += bytes_per_line, i += bytes_per_line) {
- unsigned char buf[bytes_per_line];
- if (copy_from_user(buf, (void *)addr, bytes_per_line))
- continue;
- if (!found_readable_mem) {
- printk("\nDumping memory around address %#lx:\n",
- address);
- found_readable_mem = 1;
- }
- printk("%#08lx:", addr);
- for (j = 0; j < bytes_per_line; ++j)
- printk(" %02x", buf[j]);
- printk("\n");
- }
- if (!found_readable_mem)
- printk("\nNo readable memory around address %#lx\n", address);
-}
-
-void arch_coredump_signal(siginfo_t *info, struct pt_regs *regs)
-{
- int show_mem = 0;
-
- if (!show_crashinfo)
- return;
-
- /* Don't dump anything for what are essentially "requested" cores. */
- switch (info->si_signo) {
- case SIGABRT:
- case SIGQUIT:
- case SIGTRAP:
- return;
- }
-
- /* Only show trapno and addr, and dump memory, for kernel signals. */
- if (info->si_code > 0) {
- switch (info->si_signo) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
- case SIGBUS:
- show_mem = 1;
- break;
- }
- }
-
- if (show_mem) {
- printk("\nUser crash: signal %d, code %#x,"
- " trap %d, address %#lx\n",
- info->si_signo, info->si_code, info->si_trapno,
- (unsigned long)(info->si_addr));
- show_regs(regs);
- dump_mem((unsigned long) (info->si_addr));
- } else {
- printk("\nUser crash: signal %d, code %#x\n",
- info->si_signo, info->si_code);
- show_regs(regs);
- }
-
- printk("\n");
-}
diff -ru tile.old/kernel/single_step.c tile/kernel/single_step.c
--- tile.old/kernel/single_step.c 2010-05-28 18:03:33.654991000 -0400
+++ tile/kernel/single_step.c 2010-05-28 23:07:05.072003000 -0400
@@ -15,7 +15,7 @@
* Derived from iLib's single-stepping code.
*/

-
+#ifndef __tilegx__ /* No support for single-step yet. */

/* These functions are only used on the TILE platform */
#include <linux/slab.h>
@@ -314,8 +314,7 @@
down_write(&current->mm->mmap_sem);
buffer = (void *) do_mmap(0, 0, 64,
PROT_EXEC | PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS |
- MAP_CACHE_HOME_TASK,
+ MAP_PRIVATE | MAP_ANONYMOUS,
0);
up_write(&current->mm->mmap_sem);

@@ -653,3 +652,5 @@
if (regs->faultnum == INT_SWINT_1)
regs->pc += 8;
}
+
+#endif /* !__tilegx__ */
diff -ru tile.old/kernel/smp.c tile/kernel/smp.c
--- tile.old/kernel/smp.c 2010-05-28 18:03:33.658000000 -0400
+++ tile/kernel/smp.c 2010-05-28 23:07:05.090011000 -0400
@@ -179,7 +179,7 @@
* path but instead the faster tile_dev_intr() path for interrupts.
*/

-void handle_reschedule_ipi(void *token)
+irqreturn_t handle_reschedule_ipi(int irq, void *token)
{
/*
* Nothing to do here; when we return from interrupt, the
@@ -188,11 +188,7 @@
*/
__get_cpu_var(irq_stat).irq_resched_count++;

- /*
- * Reenable the IPI before we return; any additional IPIs that
- * arrive before this point will be dropped.
- */
- tile_enable_irq(IRQ_RESCHEDULE);
+ return IRQ_HANDLED;
}

void smp_send_reschedule(int cpu)
diff -ru tile.old/kernel/smpboot.c tile/kernel/smpboot.c
--- tile.old/kernel/smpboot.c 2010-05-28 18:03:33.667981000 -0400
+++ tile/kernel/smpboot.c 2010-05-28 23:07:05.096006000 -0400
@@ -78,13 +78,6 @@

/* Print information about disabled and dataplane cpus. */
print_disabled_cpus();
-#ifdef CONFIG_DATAPLANE
- if (!cpumask_empty(&dataplane_map)) {
- char buf[100];
- cpulist_scnprintf(buf, sizeof(buf), &dataplane_map);
- printk("Linux dataplane CPUs: %s\n", buf);
- }
-#endif

/*
* Tell the messaging subsystem how to respond to the
@@ -232,8 +225,6 @@
/* Set up MPLs for this processor */
setup_mpls();

- /* Reset user network */
- reset_network_state();

/* Set up tile-timer clock-event device on this cpu */
setup_tile_timer();
@@ -280,19 +271,7 @@
/* Reset the response to a (now illegal) MSG_START_CPU IPI. */
start_cpu_function_addr = (unsigned long) &panic_start_cpu;

-#ifdef CONFIG_DATAPLANE
- /*
- * Compute the appropriate initial affinity, based on "dataplane".
- * We want to run generic Linux processes only on the
- * non-dataplane cpus. If someone set dataplane_map too
- * aggressively, we'll allow any cpu on the whole chip.
- */
- cpumask_andnot(&init_affinity, cpu_online_mask, &dataplane_map);
- if (cpumask_empty(&init_affinity))
- cpumask_copy(&init_affinity, cpu_online_mask);
-#else
cpumask_copy(&init_affinity, cpu_online_mask);
-#endif

/*
* Pin ourselves to a single cpu in the initial affinity set
@@ -308,9 +287,6 @@
(next = cpumask_next(cpu, &init_affinity)) < nr_cpu_ids;
cpu = next)
;
-#ifdef CONFIG_DATAPLANE
- singlethread_cpu = cpu;
-#endif
rc = sched_setaffinity(current->pid, cpumask_of(cpu));
if (rc != 0)
printk("Couldn't set init affinity to cpu %d (%d)\n", cpu, rc);
diff -ru tile.old/kernel/stack.c tile/kernel/stack.c
--- tile.old/kernel/stack.c 2010-05-28 18:03:33.670986000 -0400
+++ tile/kernel/stack.c 2010-05-28 23:07:05.106003000 -0400
@@ -28,7 +28,6 @@
#include <asm/sigframe.h>
#include <asm/stack.h>
#include <arch/abi.h>
-#include <arch/sim.h>
#include <arch/interrupts.h>


@@ -107,7 +106,7 @@
/* Return a pt_regs pointer for a valid fault handler frame */
static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
{
-
+#ifndef __tilegx__
const char *fault = NULL; /* happy compiler */
char fault_buf[64];
VirtualAddress sp = kbt->it.sp;
@@ -145,7 +144,7 @@
}
if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
return p;
-
+#endif
return NULL;
}

@@ -351,10 +350,12 @@
kbt->task->pid, kbt->task->tgid, kbt->task->comm,
smp_processor_id(), get_cycles());
}
-
-
-
-
+#ifdef __tilegx__
+ if (kbt->is_current) {
+ __insn_mtspr(SPR_SIM_CONTROL,
+ SIM_DUMP_SPR_ARG(SIM_DUMP_BACKTRACE));
+ }
+#endif
kbt->verbose = 1;
i = 0;
for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) {
diff -ru tile.old/kernel/sys.c tile/kernel/sys.c
--- tile.old/kernel/sys.c 2010-05-28 18:03:33.681954000 -0400
+++ tile/kernel/sys.c 2010-05-28 23:07:05.096009000 -0400
@@ -29,6 +29,8 @@
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/signal.h>
+#include <asm/syscalls.h>

#include <asm/pgtable.h>
#include <asm/homecache.h>
@@ -49,7 +51,7 @@
* any other standard libcs we want to support.
*/

-
+#if !defined(__tilegx__) || defined(CONFIG_COMPAT)

ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count)
{
@@ -70,15 +72,15 @@
((loff_t)len_hi << 32) | len_lo, advice);
}

-
+#endif /* 32-bit syscall wrappers */

/*
* This API uses a 4KB-page-count offset into the file descriptor.
* It is likely not the right API to use on a 64-bit platform.
*/
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
- unsigned long, prot, unsigned long, flags,
- unsigned int, fd, unsigned long, off_4k)
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, unsigned long, off_4k)
{
#define PAGE_ADJUST (PAGE_SHIFT - 12)
if (off_4k & ((1 << PAGE_ADJUST) - 1))
@@ -92,8 +94,8 @@
* It is likely not the right API to use on a 32-bit platform.
*/
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
- unsigned long, prot, unsigned long, flags,
- unsigned int, fd, unsigned long, offset)
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, unsigned long, offset)
{
if (offset & ((1 << PAGE_SHIFT) - 1))
return -EINVAL;
@@ -101,278 +103,20 @@
offset >> PAGE_SHIFT);
}

-#ifdef CONFIG_HOMECACHE

-int arch_vm_area_flags(struct mm_struct *mm, unsigned long flags,
- unsigned long vm_flags,
- pid_t *pid_ptr, pgprot_t *prot_ptr)
-{
- pgprot_t prot = __pgprot(0);
- pid_t pid = 0;
-
-#if CHIP_HAS_NC_AND_NOALLOC_BITS()
- if (flags & MAP_CACHE_NO_L1)
- prot = hv_pte_set_no_alloc_l1(prot);
- if (flags & MAP_CACHE_NO_L2)
- prot = hv_pte_set_no_alloc_l2(prot);
+/* Provide the actual syscall number to call mapping. */
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+#ifndef __tilegx__
+/* See comments at the top of the file. */
+#define sys_fadvise64 sys32_fadvise64
+#define sys_fadvise64_64 sys32_fadvise64_64
+#define sys_readahead sys32_readahead
+#define sys_sync_file_range sys_sync_file_range2
#endif

- if (flags & _MAP_CACHE_HOME)
- prot = pte_set_forcecache(prot);
-
- if ((flags & _MAP_CACHE_MKHOME(_MAP_CACHE_HOME_MASK)) ==
- MAP_CACHE_HOME_NONE) {
-
- /*
- * We special-case setting the home cache to "none".
- * If the user isn't indicating willingness to tolerate
- * incoherence, and is caching locally on the cpu, we
- * fail a writable mapping, or enforce a readonly mapping.
- */
- if (!(flags & _MAP_CACHE_INCOHERENT) &&
- (flags & MAP_CACHE_NO_LOCAL) != MAP_CACHE_NO_LOCAL) {
- if (vm_flags & VM_WRITE)
- return -EINVAL;
- }
- if ((flags & MAP_CACHE_NO_LOCAL) == MAP_CACHE_NO_LOCAL)
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_UNCACHED);
- else
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_NO_L3);
-
- } else if (flags & _MAP_CACHE_HOME) {
-
- /* Extract the cpu (or magic cookie). */
- int cpu = (flags >> _MAP_CACHE_HOME_SHIFT) &
- _MAP_CACHE_HOME_MASK;
-
- switch (cpu) {
-
- case _MAP_CACHE_HOME_SINGLE:
- /*
- * This is the default case; we set "anyhome"
- * and the OS will pick the cpu for us in pfn_pte()
- * by examining the page_home() of the page.
- */
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_TILE_L3);
- prot = pte_set_anyhome(prot);
- break;
-
-#if CHIP_HAS_CBOX_HOME_MAP()
- case _MAP_CACHE_HOME_HASH:
- /* Mark this page for home-map hash caching. */
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3);
- break;
-#endif
-
- case _MAP_CACHE_HOME_TASK:
- pid = current->pid;
- /*FALLTHROUGH*/
-
- case _MAP_CACHE_HOME_HERE:
- cpu = smp_processor_id();
- /*FALLTHROUGH*/
-
- default:
- if (cpu < 0 || cpu >= nr_cpu_ids ||
- !cpu_is_valid_lotar(cpu))
- return -EINVAL;
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_TILE_L3);
- prot = set_remote_cache_cpu(prot, cpu);
- }
- }
-
- /*
- * If we get a request for priority, we have to start checking
- * this mm from now on when we switch to it. We could do things
- * that are more efficient: for example, hack mmap and munmap
- * to reset a more definitive flag saying whether there is or
- * is not a priority mapping by rescanning; or even by tracking
- * the vm_area_structs themselves with a counter. But this
- * technique seems most foolproof, and doesn't involve messing
- * with architecture-independent code at all.
- *
- * Note that if we implement VA<->PA coloring, we could then
- * also usefully implement tracking exactly which priority
- * pages are present, and use the hv_set_caching() argument to
- * only partially flip the cache out of red/black mode.
- * But this is an optimization for another day.
- */
- if (flags & MAP_CACHE_PRIORITY) {
- start_mm_caching(mm);
- prot = hv_pte_set_cached_priority(prot);
- }
-
- *prot_ptr = prot;
- *pid_ptr = pid;
- return 0;
-}
-
-/*
- * If we are setting up a shared-writable mapping that forces homing
- * of part of a file, ensure that there are no other shared-writable
- * mappings that force the homing of an overlapping part of the
- * same file in an incompatible way. This implies that the caching
- * mode matches, and if it is a "tile L3" mode, that the specified
- * remote cpus match (or one of them is an "anyhome" mapping). Note
- * that we don't care about the NO_L1, etc., parts of the pgprot_t,
- * since those may differ without causing re-homecaching.
- */
-int arch_vm_area_validate(struct vm_area_struct *new_vma,
- struct address_space *mapping)
-{
- size_t len = new_vma->vm_end - new_vma->vm_start;
- pgprot_t prot = new_vma->vm_page_prot;
- unsigned long end = new_vma->vm_pgoff + (len >> PAGE_SHIFT);
- struct vm_area_struct *vma;
- struct prio_tree_iter iter;
-
- /* No existing writable mappings means we must be OK. */
- if (mapping->i_mmap_writable == 0)
- return 0;
-
- /* If we're not trying to set up a shared mapping, we're OK. */
- if (!(new_vma->vm_flags & VM_SHARED))
- return 0;
-
- /* If we're not forcing the caching, we're OK. */
- if (!pte_get_forcecache(prot))
- return 0;
-
- vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap,
- new_vma->vm_pgoff, end) {
-
- /* If we are updating our own mapping, ignore it. */
- if (vma == new_vma)
- continue;
-
- /*
- * The prio_tree is apparently conservative and will
- * report a mapping immediately following our proposed
- * new mapping as overlapping with ours, erroneously.
- * Watch for this and discard it.
- */
- if (vma->vm_pgoff == end)
- continue;
-
- /* Ignore other private mappings or non-forcing mappings. */
- if (!(vma->vm_flags & VM_SHARED) ||
- !pte_get_forcecache(vma->vm_page_prot))
- continue;
-
- if (hv_pte_get_mode(vma->vm_page_prot) !=
- hv_pte_get_mode(prot))
- return -EINVAL;
-
- if (hv_pte_get_mode(prot) == HV_PTE_MODE_CACHE_TILE_L3 &&
- !pte_get_anyhome(vma->vm_page_prot) &&
- !pte_get_anyhome(prot) &&
- hv_pte_get_lotar(vma->vm_page_prot) !=
- hv_pte_get_lotar(prot))
- return -EINVAL;
-
- }
-
- return 0;
-}
-
-#if CHIP_HAS_CBOX_HOME_MAP()
-
-#define CACHE_VAR MAP_CACHE_HASH_ENV_VAR "="
-
-void arch_exec_env(char __user *__user *envp)
-{
- char buf[64];
- char *val;
- int i;
- unsigned flags;
-
- /* Clear flags so we have a clean slate. */
- current_thread_info()->status &= ~TS_EXEC_HASH_FLAGS;
-
- for (i = 0; ; ++i) {
- char __user *str;
- int len;
-
- /* Copy in the next env string, with validity checking. */
- if (get_user(str, &envp[i]) || str == NULL)
- return;
- len = strnlen_user(str, sizeof(buf));
- if (len == 0 || _copy_from_user(buf, str, len))
- return;
-
- /* See if it is the one we're interested in. */
- if (len < sizeof(buf) &&
- strncmp(buf, CACHE_VAR, sizeof(CACHE_VAR)-1) == 0)
- break;
- }
-
- val = &buf[sizeof(CACHE_VAR)-1];
-
- /* Set flags based on the environment variable string value. */
- if (strcmp(val, "all") == 0)
- flags = TS_EXEC_HASH_STACK | TS_EXEC_HASH_RW |
- TS_EXEC_HASH_RO | TS_EXEC_HASH_SET;
- else if (strcmp(val, "allbutstack") == 0 || strcmp(val, "static") == 0)
- flags = TS_EXEC_HASH_RW | TS_EXEC_HASH_RO | TS_EXEC_HASH_SET;
- else if (strcmp(val, "ro") == 0)
- flags = TS_EXEC_HASH_RO | TS_EXEC_HASH_SET;
- else if (strcmp(val, "none") == 0)
- flags = TS_EXEC_HASH_SET;
- else
- return; /* could issue a warning, but we don't */
-
- /* Remember for later. */
- current_thread_info()->status |= flags;
-}
-
-void arch_exec_vma(struct vm_area_struct *vma)
-{
- unsigned long flags = current_thread_info()->status;
- unsigned long vm_flags;
- int use_hash, ro = 0;
- pgprot_t prot;
-
- if (!(flags & TS_EXEC_HASH_SET))
- return;
-
- vm_flags = vma->vm_flags;
- if (vm_flags & VM_GROWSDOWN) {
- use_hash = !!(flags & TS_EXEC_HASH_STACK);
- } else if (vm_flags & VM_WRITE) {
- use_hash = !!(flags & TS_EXEC_HASH_RW);
- } else {
- use_hash = !!(flags & TS_EXEC_HASH_RO);
- ro = 1;
- }
- if (hash_default == use_hash)
- return;
-
- prot = vma->vm_page_prot;
- if (use_hash) {
- /* Use hash-for-home caching for this mapping. */
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3);
- } else {
- /*
- * Cache this mapping all on one cpu. For immutable
- * pages (r/o, or r/w pages before they are COW'ed) this
- * will always be homed on the local tile.
- */
- prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_TILE_L3);
- prot = pte_set_anyhome(prot);
- }
-
- prot = pte_set_forcecache(prot);
- vma->vm_page_prot = prot;
- vma->vm_flags |= VM_DONTMERGE;
-}
-
-void arch_exec_map(unsigned long addr)
-{
- struct vm_area_struct *vma = find_vma(current->mm, addr);
- BUG_ON(!vma || addr < vma->vm_start);
- arch_exec_vma(vma);
-}
-
-#endif /* CHIP_HAS_CBOX_HOME_MAP() */
-
-#endif /* CONFIG_HOMECACHE */
+void *sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls-1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
Only in tile.old/kernel: syscall_table.S
diff -ru tile.old/kernel/tile-desc_32.c tile/kernel/tile-desc_32.c
--- tile.old/kernel/tile-desc_32.c 2010-05-28 18:03:33.745888000 -0400
+++ tile/kernel/tile-desc_32.c 2010-05-28 22:57:16.340151000 -0400
@@ -13,12 +13,8 @@
#define TREG_SN 56
#define TREG_ZERO 63

-#if defined(__KERNEL__) || defined(_LIBC)
-// FIXME: Rename this.
+/* FIXME: Rename this. */
#include <asm/opcode-tile.h>
-#else
-#include "tile-desc.h"
-#endif


const struct tile_opcode tile_opcodes[394] =
@@ -13729,41 +13725,6 @@
const int tile_num_sprs = 499;


-#if !defined(__KERNEL__) && !defined(_LIBC)
-
-#include <stdlib.h>
-
-static int
-tile_spr_compare (const void *a_ptr, const void *b_ptr)
-{
- const struct tile_spr *a = (const struct tile_spr *) a_ptr;
- const struct tile_spr *b = (const struct tile_spr *) b_ptr;
- return (a->number - b->number);
-}
-
-const char *
-get_tile_spr_name (int num)
-{
- void *result;
- struct tile_spr key;
-
- key.number = num;
- result = bsearch((const void *) &key, (const void *) tile_sprs,
- tile_num_sprs, sizeof (struct tile_spr),
- tile_spr_compare);
-
- if (result == NULL)
- {
- return (NULL);
- }
- else
- {
- struct tile_spr *result_ptr = (struct tile_spr *) result;
- return (result_ptr->name);
- }
-}
-
-#endif


/* Canonical name of each register. */
diff -ru tile.old/kernel/time.c tile/kernel/time.c
--- tile.old/kernel/time.c 2010-05-28 18:03:33.760877000 -0400
+++ tile/kernel/time.c 2010-05-28 23:07:05.098017000 -0400
@@ -21,6 +21,7 @@
#include <linux/hardirq.h>
#include <linux/sched.h>
#include <linux/smp.h>
+#include <linux/delay.h>
#include <asm/irq_regs.h>
#include <hv/hypervisor.h>
#include <arch/interrupts.h>
@@ -33,45 +34,36 @@

/* How many cycles per second we are running at. */
static cycles_t cycles_per_sec __write_once;
-static u32 cyc2ns_mult __write_once;
-#define cyc2ns_shift 30
-cycles_t get_clock_rate() { return cycles_per_sec; }

/*
- * Called very early from setup_arch() to set cycles_per_sec.
- * Also called, if required, by sched_clock(), which can be even
- * earlier if built with CONFIG_LOCKDEP (during lockdep_init).
- * We initialize it early so we can use it to set up loops_per_jiffy.
+ * We set up shift and multiply values with a minsec of five seconds,
+ * since our timer counter counts down 31 bits at a frequency of
+ * no less than 500 MHz. See @minsec for clocks_calc_mult_shift().
+ * We could use a different value for the 64-bit free-running
+ * cycle counter, but we use the same one for consistency, and since
+ * we will be reasonably precise with this value anyway.
*/
-void setup_clock(void)
-{
- u64 mult;
+#define TILE_MINSEC 5

- if (cyc2ns_mult)
- return;
- cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED);
-
- /*
- * Compute cyc2ns_mult, as used in sched_clock().
- * For efficiency of multiplication we want this to be a
- * 32-bit value, so we validate that here. We want as large a
- * shift value as possible for precision, but too large a
- * shift would make cyc2ns_mult more than 32 bits. We pick a
- * constant value that works well with our typical
- * frequencies, though we could in principle compute the most
- * precise value dynamically instead. We can't make the shift
- * greater than 32 without fixing the algorithm.
- */
- mult = (1000000000ULL << cyc2ns_shift) / cycles_per_sec;
- cyc2ns_mult = (u32) mult;
- BUILD_BUG_ON(cyc2ns_shift > 32);
- BUG_ON(mult != cyc2ns_mult);
+cycles_t get_clock_rate()
+{
+ return cycles_per_sec;
}

#if CHIP_HAS_SPLIT_CYCLE()
cycles_t get_cycles()
{
- return get_cycle_count();
+ unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
+ unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
+ unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
+
+ while (unlikely(high != high2)) {
+ low = __insn_mfspr(SPR_CYCLE_LOW);
+ high = high2;
+ high2 = __insn_mfspr(SPR_CYCLE_HIGH);
+ }
+
+ return (((cycles_t)high) << 32) | low;
}
#endif

@@ -80,7 +72,7 @@
return get_cycles();
}

-static struct clocksource cycle_counter_clocksource = {
+static struct clocksource cycle_counter_cs = {
.name = "cycle counter",
.rating = 300,
.read = clocksource_get_cycles,
@@ -88,73 +80,33 @@
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};

-/* Called fairly late in init/main.c, but before we go smp. */
-void __init time_init(void)
-{
- struct clocksource *src = &cycle_counter_clocksource;
-
- /* Pick an arbitrary time to start us up. */
- xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
- xtime.tv_nsec = 0;
-
- /* Initialize and register the clock source. */
- src->shift = 20; /* arbitrary */
- src->mult = (1000000000ULL << src->shift) / cycles_per_sec;
- clocksource_register(src);
-
- /* Start up the tile-timer interrupt source on the boot cpu. */
- setup_tile_timer();
-}
-
-
/*
- * Provide support for effectively turning the timer interrupt on and
- * off via the interrupt mask. Make sure not to unmask it while we are
- * running the timer interrupt handler, to avoid recursive timer
- * interrupts; these may be OK in some cases, but it's generally cleaner
- * to reset the kernel stack before starting the next timer interrupt.
+ * Called very early from setup_arch() to set cycles_per_sec.
+ * We initialize it early so we can use it to set up loops_per_jiffy.
*/
-
-/* Track some status about the timer interrupt. */
-struct timer_status {
- int enabled; /* currently meant to be enabled? */
- int in_intr; /* currently in the interrupt handler? */
-};
-static DEFINE_PER_CPU(struct timer_status, timer_status);
-
-/* Enable the timer interrupt, unless we're in the handler. */
-static void enable_timer_intr(void)
+void __init setup_clock(void)
{
- struct timer_status *status = &__get_cpu_var(timer_status);
- status->enabled = 1;
- if (status->in_intr)
- return;
- raw_local_irq_unmask_now(INT_TILE_TIMER);
+ cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED);
+ clocksource_calc_mult_shift(&cycle_counter_cs, cycles_per_sec,
+ TILE_MINSEC);
}

-/* Disable the timer interrupt. */
-static void disable_timer_intr(void)
+void __init calibrate_delay(void)
{
- struct timer_status *status = &__get_cpu_var(timer_status);
- status->enabled = 0;
- raw_local_irq_mask_now(INT_TILE_TIMER);
+ loops_per_jiffy = get_clock_rate() / HZ;
+ pr_info("Clock rate yields %lu.%02lu BogoMIPS (lpj=%lu)\n",
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
}

-/* Mark the start of processing for the timer interrupt. */
-static void start_timer_intr(void)
+/* Called fairly late in init/main.c, but before we go smp. */
+void __init time_init(void)
{
- struct timer_status *status = &__get_cpu_var(timer_status);
- status->in_intr = 1;
- disable_timer_intr();
-}
+ /* Initialize and register the clock source. */
+ clocksource_register(&cycle_counter_cs);

-/* Mark end of processing for the timer interrupt, unmasking if necessary. */
-static void end_timer_intr(void)
-{
- struct timer_status *status = &__get_cpu_var(timer_status);
- status->in_intr = 0;
- if (status->enabled)
- enable_timer_intr();
+ /* Start up the tile-timer interrupt source on the boot cpu. */
+ setup_tile_timer();
}


@@ -173,7 +125,7 @@
{
BUG_ON(ticks > MAX_TICK);
__insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
- enable_timer_intr();
+ raw_local_irq_unmask_now(INT_TILE_TIMER);
return 0;
}

@@ -184,13 +136,17 @@
static void tile_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- disable_timer_intr();
+ raw_local_irq_mask_now(INT_TILE_TIMER);
}

+/*
+ * Set min_delta_ns to 1 microsecond, since it takes about
+ * that long to fire the interrupt.
+ */
static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = {
.name = "tile timer",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .min_delta_ns = 1000, /* at least 1000 cycles to fire the interrupt */
+ .min_delta_ns = 1000,
.rating = 100,
.irq = -1,
.set_next_event = tile_timer_set_next_event,
@@ -202,15 +158,14 @@
struct clock_event_device *evt = &__get_cpu_var(tile_timer);

/* Fill in fields that are speed-specific. */
- evt->shift = 20; /* arbitrary */
- evt->mult = (cycles_per_sec << evt->shift) / 1000000000ULL;
- evt->max_delta_ns = (MAX_TICK * 1000000000ULL) / cycles_per_sec;
+ clockevents_calc_mult_shift(evt, cycles_per_sec, TILE_MINSEC);
+ evt->max_delta_ns = clockevent_delta2ns(MAX_TICK, evt);

/* Mark as being for this cpu only. */
evt->cpumask = cpumask_of(smp_processor_id());

/* Start out with timer not firing. */
- disable_timer_intr();
+ raw_local_irq_mask_now(INT_TILE_TIMER);

/* Register tile timer. */
clockevents_register_device(evt);
@@ -222,8 +177,11 @@
struct pt_regs *old_regs = set_irq_regs(regs);
struct clock_event_device *evt = &__get_cpu_var(tile_timer);

- /* Mask timer interrupts in case someone enable interrupts later. */
- start_timer_intr();
+ /*
+ * Mask the timer interrupt here, since we are a oneshot timer
+ * and there are now by definition no events pending.
+ */
+ raw_local_irq_mask(INT_TILE_TIMER);

/* Track time spent here in an interrupt context */
irq_enter();
@@ -240,43 +198,20 @@
*/
irq_exit();

- /*
- * Enable the timer interrupt (if requested) with irqs disabled,
- * so we don't get recursive timer interrupts.
- */
- local_irq_disable();
- end_timer_intr();
-
set_irq_regs(old_regs);
}

/*
* Scheduler clock - returns current time in nanosec units.
- *
- * The normal algorithm computes (cycles * cyc2ns_mult) >> cyc2ns_shift.
- * We can make it potentially more efficient and with a better range
- * by writing "cycles" as two 32-bit components, "(H << 32) + L" and
- * then factoring. Here we use M = cyc2ns_mult and S = cyc2ns_shift.
- *
- * (((H << 32) + L) * M) >> S =
- * (((H << 32) * M) >> S) + ((L * M) >> S) =
- * ((H * M) << (32 - S)) + ((L * M) >> S)
+ * Note that with LOCKDEP, this is called during lockdep_init(), and
+ * we will claim that sched_clock() is zero for a little while, until
+ * we run setup_clock(), above.
*/
unsigned long long sched_clock(void)
{
- u64 cycles;
- u32 cyc_hi, cyc_lo;
-
- if (unlikely(cyc2ns_mult == 0))
- setup_clock();
-
- cycles = get_cycles();
- cyc_hi = (u32) (cycles >> 32);
- cyc_lo = (u32) (cycles);
-
- /* Compiler could optimize the 32x32 -> 64 multiplies here. */
- return ((cyc_hi * (u64)cyc2ns_mult) << (32 - cyc2ns_shift)) +
- ((cyc_lo * (u64)cyc2ns_mult) >> cyc2ns_shift);
+ return clocksource_cyc2ns(get_cycles(),
+ cycle_counter_cs.mult,
+ cycle_counter_cs.shift);
}

int setup_profiling_timer(unsigned int multiplier)
diff -ru tile.old/kernel/traps.c tile/kernel/traps.c
--- tile.old/kernel/traps.c 2010-05-28 18:03:33.764878000 -0400
+++ tile/kernel/traps.c 2010-05-28 23:07:05.099015000 -0400
@@ -98,11 +98,11 @@
#endif /* CHIP_HAS_TILE_DMA() */

/* Defined inside do_trap(), below. */
-
-
-
+#ifdef __tilegx__
+extern tilegx_bundle_bits bpt_code;
+#else
extern tile_bundle_bits bpt_code;
-
+#endif

void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
@@ -177,7 +177,7 @@
address = regs->pc;
break;
case INT_UNALIGN_DATA:
-
+#ifndef __tilegx__ /* FIXME: GX: no single-step yet */
if (unaligned_fixup >= 0) {
struct single_step_state *state =
current_thread_info()->step_state;
@@ -186,7 +186,7 @@
return;
}
}
-
+#endif
signo = SIGBUS;
code = BUS_ADRALN;
address = 0;
@@ -204,16 +204,16 @@
code = ILL_DBLFLT;
address = regs->pc;
break;
-
-
-
-
-
-
-
-
-
-
+#ifdef __tilegx__
+ case INT_ILL_TRANS:
+ signo = SIGSEGV;
+ code = SEGV_MAPERR;
+ if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK)
+ address = regs->pc;
+ else
+ address = 0; /* FIXME: GX: single-step for address */
+ break;
+#endif
default:
panic("Unexpected do_trap interrupt number %d", fault_num);
return;
diff -ru tile.old/kernel/vmlinux.lds.S tile/kernel/vmlinux.lds.S
--- tile.old/kernel/vmlinux.lds.S 2010-05-28 18:03:33.767868000 -0400
+++ tile/kernel/vmlinux.lds.S 2010-05-28 23:07:05.103007000 -0400
@@ -1,12 +1,12 @@
-#define LOAD_OFFSET PAGE_OFFSET
-#define TEXT_OFFSET MEM_SV_INTRPT
-
#include <asm-generic/vmlinux.lds.h>
#include <asm/page.h>
#include <asm/cache.h>
#include <asm/thread_info.h>
#include <hv/hypervisor.h>

+/* Text loads starting from the supervisor interrupt vector address. */
+#define TEXT_OFFSET MEM_SV_INTRPT
+
OUTPUT_ARCH(tile)
ENTRY(_start)
jiffies = jiffies_64;
@@ -16,201 +16,83 @@
intrpt1 PT_LOAD ;
text PT_LOAD ;
data PT_LOAD ;
- note PT_NOTE FLAGS(0);
}
SECTIONS
{
+ /* Text is loaded with a different VA than data; start with text. */
+ #undef LOAD_OFFSET
+ #define LOAD_OFFSET TEXT_OFFSET
+
/* Interrupt vectors */
- .intrpt1 (TEXT_OFFSET) : AT ( 0 ) /* put at the start of physical memory */
+ .intrpt1 (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */
{
_text = .;
_stext = .;
*(.intrpt1)
} :intrpt1 =0

-#include "hvglue.ld"
+ /* Hypervisor call vectors */
+ #include "hvglue.lds"

/* Now the real code */
. = ALIGN(0x20000);
- .text : AT (ADDR(.text) - TEXT_OFFSET) {
- *(.text.head)
+ HEAD_TEXT_SECTION :text =0
+ .text : AT (ADDR(.text) - LOAD_OFFSET) {
SCHED_TEXT
LOCK_TEXT
__fix_text_end = .; /* tile-cpack won't rearrange before this */
-#include "sections.lds"
TEXT_TEXT
*(.text.*)
*(.coldtext*)
*(.fixup)
*(.gnu.warning)
- } :text =0
+ }
+ _etext = .;

+ /* "Init" is divided into two areas with very different virtual addresses. */
+ INIT_TEXT_SECTION(PAGE_SIZE)

- /* will be freed after init */
- . = ALIGN(PAGE_SIZE); /* Init code */
- __init_text_begin = .;
- .init.text : AT(ADDR(.init.text) - TEXT_OFFSET) {
- _sinittext = .;
- INIT_TEXT
- _einittext = .;
- }
+ /* Now we skip back to PAGE_OFFSET for the data. */
+ . = (. - TEXT_OFFSET + PAGE_OFFSET);
+ #undef LOAD_OFFSET
+ #define LOAD_OFFSET PAGE_OFFSET
+
+ . = ALIGN(PAGE_SIZE);
+ VMLINUX_SYMBOL(_sinitdata) = .;
+ .init.page : AT (ADDR(.init.page) - LOAD_OFFSET) {
+ *(.init.page)
+ } :data =0
+ INIT_DATA_SECTION(16)
+ PERCPU(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
- __init_text_end = .;
- _etext = .; /* End of text section */
+ VMLINUX_SYMBOL(_einitdata) = .;

- . = (. - TEXT_OFFSET + LOAD_OFFSET);
_sdata = .; /* Start of data section */

- . = ALIGN(PAGE_SIZE);
+ RO_DATA_SECTION(PAGE_SIZE)

/* initially writeable, then read-only */
. = ALIGN(PAGE_SIZE);
__w1data_begin = .;
-
- __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- } :data
-
- __start___dbe_table = .; /* Exception table for data bus errors */
- __dbe_table : AT(ADDR(__dbe_table) - LOAD_OFFSET) { *(__dbe_table) }
- __stop___dbe_table = .;
-
- . = ALIGN(L2_CACHE_BYTES);
- .w1data : AT(ADDR(.w1data) - LOAD_OFFSET) { *(.w1data) }
-
- . = ALIGN(PAGE_SIZE); /* align to page size */
- __w1data_end = .;
-
- NOTES :note
-
- BUG_TABLE :data
-
- . = ALIGN(4);
- __tracedata_start = .;
- .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
- *(.tracedata)
+ .w1data : AT(ADDR(.w1data) - LOAD_OFFSET) {
+ VMLINUX_SYMBOL(__w1data_begin) = .;
+ *(.w1data)
+ VMLINUX_SYMBOL(__w1data_end) = .;
}
- __tracedata_end = .;

- RO_DATA(PAGE_SIZE)
+ RW_DATA_SECTION(L2_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)

- /* writeable */
- . = ALIGN(PAGE_SIZE); /* align to page size */
- .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
- PAGE_ALIGNED_DATA(PAGE_SIZE)
- CACHELINE_ALIGNED_DATA(64)
- DATA_DATA
- CONSTRUCTORS
- READ_MOSTLY_DATA(64)
- }
+ _edata = .;

-#ifdef CONFIG_FEEDBACK_COLLECT
- .feedback : {
- *(.feedback.start)
- __feedback_functions_start = .;
- *(.feedback.functions)
- __feedback_functions_end = .;
- *(.feedback.strings)
- *(.feedback.data)
- __feedback_section_end = .;
- }
-#endif
+ EXCEPTION_TABLE(L2_CACHE_BYTES)
+ NOTES

- _edata = .; /* End of data section */
-
- /* These sections are pretty big, and not used at all. */
- /DISCARD/ : { *(.eh_frame) }
-
- /* will be freed after init (note that init_task is freed separately) */
- . = ALIGN(THREAD_SIZE); /* align to thread_union size */
- .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) {
- INIT_TASK_DATA(THREAD_SIZE)
- __init_data_begin = .;
- *(.init.data.page_aligned)
- INIT_DATA
- }
- . = ALIGN(16);
- .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) {
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- }
- .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
- __initcall_start = .;
- INITCALLS
- __initcall_end = .;
- }
- .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- }
- SECURITY_INIT
- . = ALIGN(8);
- .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
- EXIT_TEXT
- }
- .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) {
- EXIT_DATA
- }
-#if defined(CONFIG_BLK_DEV_INITRD)
- . = ALIGN(PAGE_SIZE);
- .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) {
- __initramfs_start = .;
- *(.init.ramfs)
- __initramfs_end = .;
- }
-#endif
- PERCPU(PAGE_SIZE)
- . = ALIGN(PAGE_SIZE);
- /* freed after init ends here */
- __init_data_end = .;
- /* freed after init ends here */
-
- __bss_start = .; /* BSS */
- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
- . = ALIGN(PAGE_SIZE);
- *(.bss.page_aligned)
- *(.bss)
- *(COMMON)
- __bss_stop = .;
- }

+ BSS_SECTION(8, PAGE_SIZE, 1)
_end = . ;

- /* Sections to be discarded */
- /DISCARD/ : {
- *(.exit.text)
- *(.exit.data)
- *(.exitcall.exit)
-
- /* ABI crap starts here */
- *(.comment)
- *(.MIPS.options)
- *(.note)
- *(.options)
- *(.pdr)
- *(.reginfo)
- *(.mdebug*)
- }
+ STABS_DEBUG
+ DWARF_DEBUG

- /*
- * DWARF debug sections.
- * Symbols in the .debug DWARF section are relative to the beginning of the
- * section so we begin .debug at 0. It's not clear yet what needs to happen
- * for the others.
- */
- .debug 0 : { *(.debug) }
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- .line 0 : { *(.line) }
- /* These must appear regardless of . */
- .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
- .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
- .comment : { *(.comment) }
- .note : { *(.note) }
+ DISCARDS
}
diff -ru tile.old/lib/__invalidate_icache.S tile/lib/__invalidate_icache.S
--- tile.old/lib/__invalidate_icache.S 2010-05-28 18:03:33.790851000 -0400
+++ tile/lib/__invalidate_icache.S 2010-05-28 23:14:24.668719000 -0400
@@ -26,21 +26,21 @@
#include <asm/page.h>
#endif

+#ifdef __tilegx__
+/* Share code among Tile family chips but adjust opcodes appropriately. */
+#define slt cmpltu
+#define bbst blbst
+#define bnezt bnzt
+#endif

-
-
-
-
-
-
-
-
-
-
-
+#if defined(__tilegx__) && __SIZEOF_POINTER__ == 4
+/* Force 32-bit ops so pointers wrap around appropriately. */
+#define ADD_PTR addx
+#define ADDI_PTR addxi
+#else
#define ADD_PTR add
#define ADDI_PTR addi
-
+#endif

.section .text.__invalidate_icache, "ax"
.global __invalidate_icache
diff -ru tile.old/lib/atomic_32.c tile/lib/atomic_32.c
--- tile.old/lib/atomic_32.c 2010-05-28 18:03:33.793842000 -0400
+++ tile/lib/atomic_32.c 2010-05-28 23:14:24.673697000 -0400
@@ -122,25 +122,6 @@

#endif /* CONFIG_SMP */

-int __tns_atomic_acquire(atomic_t *lock)
-{
- int ret;
- u32 iterations = 0;
-
- BUG_ON(__insn_mfspr(SPR_INTERRUPT_CRITICAL_SECTION));
- __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
-
- while ((ret = __insn_tns((void *)&lock->counter)) == 1)
- delay_backoff(iterations++);
- return ret;
-}
-
-void __tns_atomic_release(atomic_t *p, int v)
-{
- p->counter = v;
- __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
-}
-
static inline int *__atomic_setup(volatile void *v)
{
/* Issue a load to the target to bring it into cache. */
diff -ru tile.old/lib/checksum.c tile/lib/checksum.c
--- tile.old/lib/checksum.c 2010-05-28 18:03:33.814826000 -0400
+++ tile/lib/checksum.c 2010-05-28 23:14:24.675696000 -0400
@@ -1,41 +1,35 @@
/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
*
- * IP/TCP/UDP checksumming routines
- *
- * Authors: Jorge Cwik, <jorge@xxxxxxxxxxxxxxxxx>
- * Arnt Gulbrandsen, <agulbra@xxxxxxxxxxx>
- * Tom May, <ftom@xxxxxxxxxx>
- * Andreas Schwab, <schwab@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
- * Lots of code moved from tcp.c and ip.c; see those files
- * for more names.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * This program is 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, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * Support code for the main lib/checksum.c.
*/

#include <net/checksum.h>
-#include <asm/checksum.h>
#include <linux/module.h>

static inline unsigned int longto16(unsigned long x)
{
unsigned long ret;
-
-
-
-
+#ifdef __tilegx__
+ ret = __insn_v2sadu(x, 0);
+ ret = __insn_v2sadu(ret, 0);
+#else
ret = __insn_sadh_u(x, 0);
ret = __insn_sadh_u(ret, 0);
-
+#endif
return ret;
}

-static __wsum do_csum(const unsigned char *buff, int len)
+__wsum do_csum(const unsigned char *buff, int len)
{
int odd, count;
unsigned long result = 0;
@@ -58,16 +52,16 @@
}
count >>= 1; /* nr of 32-bit words.. */
if (count) {
-
-
-
-
-
-
-
-
-
-
+#ifdef __tilegx__
+ if (4 & (unsigned long) buff) {
+ unsigned int w = *(const unsigned int *)buff;
+ result = __insn_v2sadau(result, w, 0);
+ count--;
+ len -= 4;
+ buff += 4;
+ }
+ count >>= 1; /* nr of 64-bit words.. */
+#endif

/*
* This algorithm could wrap around for very
@@ -79,19 +73,19 @@
unsigned long w = *(const unsigned long *)buff;
count--;
buff += sizeof(w);
-
-
-
+#ifdef __tilegx__
+ result = __insn_v2sadau(result, w, 0);
+#else
result = __insn_sadah_u(result, w, 0);
-
+#endif
}
-
-
-
-
-
-
-
+#ifdef __tilegx__
+ if (len & 4) {
+ unsigned int w = *(const unsigned int *)buff;
+ result = __insn_v2sadau(result, w, 0);
+ buff += 4;
+ }
+#endif
}
if (len & 2) {
result += *(const unsigned short *) buff;
@@ -106,87 +100,3 @@
out:
return result;
}
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-__wsum csum_partial(const void *buff, int len, __wsum sum)
-{
- __wsum result = do_csum(buff, len);
-
- /* add in old sum, and carry.. */
- result += sum;
- if (sum > result)
- result += 1;
- return result;
-}
-EXPORT_SYMBOL(csum_partial);
-
-/*
- * copy from user space while checksumming, otherwise like csum_partial
- */
-__wsum csum_partial_copy_from_user(const void __user *src,
- void *dst, int len, __wsum sum,
- int *csum_err)
-{
- int left = copy_from_user(dst, src, len);
- if (csum_err)
- *csum_err = left ? -EFAULT : 0;
- return csum_partial(dst, len, sum);
-}
-
-/*
- * copy from ds while checksumming, otherwise like csum_partial
- */
-__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
-{
- memcpy(dst, src, len);
- return csum_partial(dst, len, sum);
-}
-
-/*
- * This is a version of ip_compute_csum() optimized for IP headers,
- * which always checksum on 4 octet boundaries.
- *
- * By Jorge Cwik <jorge@xxxxxxxxxxxxxxxxx>, adapted for linux by
- * Arnt Gulbrandsen.
- */
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
- unsigned int *word = (unsigned int *)iph;
- unsigned int *stop = word + ihl;
- unsigned int csum;
- int carry;
-
- csum = word[0];
- csum += word[1];
- carry = (csum < word[1]);
- csum += carry;
-
- csum += word[2];
- carry = (csum < word[2]);
- csum += carry;
-
- csum += word[3];
- carry = (csum < word[3]);
- csum += carry;
-
- word += 4;
- do {
- csum += *word;
- carry = (csum < *word);
- csum += carry;
- word++;
- } while (word != stop);
-
- return csum_fold(csum);
-}
diff -ru tile.old/lib/delay.c tile/lib/delay.c
--- tile.old/lib/delay.c 2010-05-28 18:03:33.832807000 -0400
+++ tile/lib/delay.c 2010-05-28 23:14:24.679699000 -0400
@@ -32,33 +32,3 @@

/* FIXME: should be declared in a header somewhere. */
EXPORT_SYMBOL(__delay);
-
-/* Perform bounded exponential backoff.*/
-void delay_backoff(int iterations)
-{
- u32 exponent, loops;
-
- /*
- * 2^exponent is how many times we go around the loop,
- * which takes 8 cycles. We want to start with a 16- to 31-cycle
- * loop, so we need to go around minimum 2 = 2^1 times, so we
- * bias the original value up by 1.
- */
- exponent = iterations + 1;
-
- /*
- * Don't allow exponent to exceed 7, so we have 128 loops,
- * or 1,024 (to 2,047) cycles, as our maximum.
- */
- if (exponent > 8)
- exponent = 8;
-
- loops = 1 << exponent;
-
- /* Add a randomness factor so two cpus never get in lock step. */
- loops += __insn_crc32_32(stack_pointer, get_cycle_count_low()) &
- (loops - 1);
-
- relax(1 << exponent);
-}
-EXPORT_SYMBOL(delay_backoff);
diff -ru tile.old/lib/exports.c tile/lib/exports.c
--- tile.old/lib/exports.c 2010-05-28 18:03:33.853786000 -0400
+++ tile/lib/exports.c 2010-05-28 23:14:24.707666000 -0400
@@ -66,12 +66,13 @@
EXPORT_SYMBOL(__umoddi3);
int64_t __moddi3(int64_t dividend, int64_t divisor);
EXPORT_SYMBOL(__moddi3);
-
+#ifndef __tilegx__
uint64_t __ll_mul(uint64_t n0, uint64_t n1);
EXPORT_SYMBOL(__ll_mul);
-
-
+#endif
+#ifndef __tilegx__
int64_t __muldi3(int64_t, int64_t);
EXPORT_SYMBOL(__muldi3);
uint64_t __lshrdi3(uint64_t, unsigned int);
EXPORT_SYMBOL(__lshrdi3);
+#endif
diff -ru tile.old/lib/memchr_32.c tile/lib/memchr_32.c
--- tile.old/lib/memchr_32.c 2010-05-28 18:03:33.879756000 -0400
+++ tile/lib/memchr_32.c 2010-05-28 23:14:25.050325000 -0400
@@ -12,18 +12,9 @@
* more details.
*/

-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
-EXPORT_SYMBOL(memchr);
-#else
-#include <string.h>
-#include <stdint.h>
-#ifdef _LIBC
-libc_hidden_proto(memchr)
-#endif
-#endif

void *memchr(const void *s, int c, size_t n)
{
@@ -55,9 +46,6 @@

if (__builtin_expect(n == 0, 0)) {
/* Don't dereference any memory if the array is empty. */
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
return NULL;
}

@@ -68,9 +56,6 @@
*/
return NULL;
}
-#ifdef __TILECC__
-#pragma frequency_hint FREQUENT
-#endif
v = *++p;
}

@@ -80,7 +65,4 @@
ret = ((char *)p) + (__insn_ctz(bits) >> 3);
return (ret <= last_byte_ptr) ? ret : NULL;
}
-
-#ifdef _LIBC
-libc_hidden_def(memchr)
-#endif
+EXPORT_SYMBOL(memchr);
diff -ru tile.old/lib/memcpy_32.S tile/lib/memcpy_32.S
--- tile.old/lib/memcpy_32.S 2010-05-28 18:03:33.894741000 -0400
+++ tile/lib/memcpy_32.S 2010-05-28 23:14:25.037347000 -0400
@@ -21,7 +21,6 @@
#define MEMCPY_USE_WH64
#endif

-#ifdef __KERNEL__

#include <linux/linkage.h>

@@ -94,21 +93,6 @@
memcpy_common:
/* On entry, r29 holds one of the IS_* macro values from above. */

-#else /* !__KERNEL__ */
-
-#include <feedback.h>
-
- .section .text.memcpy, "ax"
- .global memcpy
- .type memcpy, @function
- .align 64
-memcpy:
- FEEDBACK_ENTER(memcpy)
-
-// Create a bogus unused local label.
-#define EX 9
-
-#endif /* !__KERNEL__ */

/* r0 is the dest, r1 is the source, r2 is the size. */

@@ -118,11 +102,9 @@
/* Check for an empty size. */
{ bz r2, .Ldone; andi r4, r4, 3 }

-#ifdef __KERNEL__
/* Save aside original values in case of a fault. */
{ move r24, r1; move r25, r2 }
move r27, lr
-#endif

/* Check for an unaligned source or dest. */
{ bnz r4, .Lcopy_unaligned_maybe_many; addli r4, r2, -256 }
@@ -158,12 +140,8 @@
{ bnz r2, .Lcopy_unaligned_few }

.Ldone:
-#ifdef __KERNEL__
/* For memcpy return original dest address, else zero. */
{ mz r0, r29, r23; jrp lr }
-#else
- { move r0, r23; jrp lr }
-#endif


/*
@@ -577,18 +555,6 @@
{ bnzt r2, .Lcopy_unaligned_few }

.Lcopy_unaligned_done:
-#ifndef __KERNEL__
-
- { move r0, r23; jrp lr }
-
-.Lend_memcpy:
- .size memcpy, .Lend_memcpy - memcpy
-
-#ifdef _LIBC
-libc_hidden_def(memcpy)
-#endif
-
-#else /* KERNEL */

/* For memcpy return original dest address, else zero. */
{ mz r0, r29, r23; jrp lr }
@@ -660,5 +626,3 @@
.section __ex_table,"a"
.word .Lcfu, .Lcopy_from_user_fixup_zero_remainder
.word .Lctu, .Lcopy_to_user_fixup_done
-
-#endif /* __KERNEL__ */
diff -ru tile.old/lib/memmove_32.c tile/lib/memmove_32.c
--- tile.old/lib/memmove_32.c 2010-05-28 18:03:33.900732000 -0400
+++ tile/lib/memmove_32.c 2010-05-28 23:16:26.765512000 -0400
@@ -12,18 +12,9 @@
* more details.
*/

-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
-EXPORT_SYMBOL(memmove);
-#else
-#include <string.h>
-#include <stdint.h>
-#ifdef _LIBC
-libc_hidden_proto(memmove)
-#endif
-#endif

void *memmove(void *dest, const void *src, size_t n)
{
@@ -51,15 +42,12 @@
in = (const uint8_t *)src;
out = (uint8_t *)dest;
stride = 1;
- }
+ }

/* Manually software-pipeline this loop. */
x = *in;
in += stride;

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
while (--n != 0) {
*out = x;
out += stride;
@@ -72,7 +60,4 @@

return dest;
}
-
-#ifdef _LIBC
-libc_hidden_def(memmove)
-#endif
+EXPORT_SYMBOL(memmove);
diff -ru tile.old/lib/memset_32.c tile/lib/memset_32.c
--- tile.old/lib/memset_32.c 2010-05-28 18:03:33.903730000 -0400
+++ tile/lib/memset_32.c 2010-05-28 23:14:25.222244000 -0400
@@ -14,22 +14,9 @@

#include <arch/chip.h>

-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
-EXPORT_SYMBOL(memset);
-#else
-#include <string.h>
-#include <stdint.h>
-#ifndef __TILECC__
-#define __insn_prefetch(addr)
-#define __insn_wh64(addr)
-#endif
-#ifdef _LIBC
-libc_hidden_proto(memset)
-#endif
-#endif


void *memset(void *s, int c, size_t n)
@@ -61,9 +48,6 @@
* write this loop.
*/
if (n != 0) {
-#ifdef __TILECC__
-#pragma unroll 0
-#endif
do {
/* Strangely, combining these into one line
* performs worse.
@@ -91,18 +75,12 @@
#endif /* !CHIP_HAS_WH64() */


-#ifdef __TILECC__
-#pragma unroll 0
-#endif
/* Align 'out8'. We know n >= 3 so this won't write past the end. */
while (((uintptr_t) out8 & 3) != 0) {
*out8++ = c;
--n;
}

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
/* Align 'n'. */
while (n & 3)
out8[--n] = c;
@@ -137,18 +115,12 @@
if (ahead32 > MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS)
ahead32 = MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS;

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
for (i = CACHE_LINE_SIZE_IN_WORDS;
i < ahead32; i += CACHE_LINE_SIZE_IN_WORDS)
__insn_prefetch(&out32[i]);
}

if (n32 > ahead32) {
-#ifdef __TILECC__
-#pragma unroll 0
-#endif
while (1) {
int j;

@@ -176,9 +148,6 @@

n32 -= CACHE_LINE_SIZE_IN_WORDS;

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
/* Save icache space by only partially unrolling
* this loop.
*/
@@ -250,9 +219,6 @@

/* Align out32 mod the cache line size so we can use wh64. */
n32 -= to_align32;
-#ifdef __TILECC__
-#pragma unroll 0
-#endif
for (; to_align32 != 0; to_align32--) {
*out32 = v32;
out32++;
@@ -261,9 +227,6 @@
/* Use unsigned divide to turn this into a right shift. */
lines_left = (unsigned)n32 / CACHE_LINE_SIZE_IN_WORDS;

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
do {
/* Only wh64 a few lines at a time, so we don't
* exceed the maximum number of victim lines.
@@ -277,19 +240,12 @@

lines_left -= x;

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
do {
__insn_wh64(wh);
wh += CACHE_LINE_SIZE_IN_WORDS;
} while (--i);

-#ifdef __TILECC__
-#pragma unroll 0
-#endif
- for (j = x * (CACHE_LINE_SIZE_IN_WORDS / 4);
- j != 0; j--) {
+ for (j = x * (CACHE_LINE_SIZE_IN_WORDS / 4); j != 0; j--) {
*out32++ = v32;
*out32++ = v32;
*out32++ = v32;
@@ -307,9 +263,6 @@

/* Now handle any leftover values. */
if (n32 != 0) {
-#ifdef __TILECC__
-#pragma unroll 0
-#endif
do {
*out32 = v32;
out32++;
@@ -318,7 +271,4 @@

return s;
}
-
-#ifdef _LIBC
-libc_hidden_def(memset)
-#endif
+EXPORT_SYMBOL(memset);
diff -ru tile.old/lib/spinlock_32.c tile/lib/spinlock_32.c
--- tile.old/lib/spinlock_32.c 2010-05-28 18:03:33.915730000 -0400
+++ tile/lib/spinlock_32.c 2010-05-28 23:14:24.719659000 -0400
@@ -14,9 +14,9 @@

#include <linux/spinlock.h>
#include <linux/module.h>
-#include <linux/delay.h>
#include <asm/processor.h>

+#include "spinlock_common.h"

void arch_spin_lock(arch_spinlock_t *lock)
{
@@ -98,9 +98,6 @@
for (;;) {
u32 val = __insn_tns((int *)&rwlock->lock);
if (unlikely(val & 1)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
delay_backoff(iterations++);
continue;
}
@@ -128,9 +125,6 @@
{
u32 eq, mask = 1 << WR_CURR_SHIFT;
while (unlikely(val & 1)) {
-#ifdef __TILECC__
-#pragma frequency_hint NEVER
-#endif
/* Limited backoff since we are the highest-priority task. */
relax(4);
val = __insn_tns((int *)&rwlock->lock);
@@ -206,3 +200,22 @@
}
}
EXPORT_SYMBOL(arch_write_lock_slow);
+
+int __tns_atomic_acquire(atomic_t *lock)
+{
+ int ret;
+ u32 iterations = 0;
+
+ BUG_ON(__insn_mfspr(SPR_INTERRUPT_CRITICAL_SECTION));
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
+
+ while ((ret = __insn_tns((void *)&lock->counter)) == 1)
+ delay_backoff(iterations++);
+ return ret;
+}
+
+void __tns_atomic_release(atomic_t *p, int v)
+{
+ p->counter = v;
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+}
--- /dev/null 2010-03-18 09:49:04.311688576 -0400
+++ tile/lib/spinlock_common.h 2010-05-28 23:14:24.716655000 -0400
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * 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, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * This file is included into spinlock_32.c or _64.c.
+ */
+
+/*
+ * The mfspr in __spinlock_relax() is 5 or 6 cycles plus 2 for loop
+ * overhead.
+ */
+#ifdef __tilegx__
+#define CYCLES_PER_RELAX_LOOP 7
+#else
+#define CYCLES_PER_RELAX_LOOP 8
+#endif
+
+/*
+ * Idle the core for CYCLES_PER_RELAX_LOOP * iterations cycles.
+ */
+static inline void
+relax(int iterations)
+{
+ for (/*above*/; iterations > 0; iterations--)
+ __insn_mfspr(SPR_PASS);
+ barrier();
+}
+
+/* Perform bounded exponential backoff.*/
+void delay_backoff(int iterations)
+{
+ u32 exponent, loops;
+
+ /*
+ * 2^exponent is how many times we go around the loop,
+ * which takes 8 cycles. We want to start with a 16- to 31-cycle
+ * loop, so we need to go around minimum 2 = 2^1 times, so we
+ * bias the original value up by 1.
+ */
+ exponent = iterations + 1;
+
+ /*
+ * Don't allow exponent to exceed 7, so we have 128 loops,
+ * or 1,024 (to 2,047) cycles, as our maximum.
+ */
+ if (exponent > 8)
+ exponent = 8;
+
+ loops = 1 << exponent;
+
+ /* Add a randomness factor so two cpus never get in lock step. */
+ loops += __insn_crc32_32(stack_pointer, get_cycles_low()) &
+ (loops - 1);
+
+ relax(1 << exponent);
+}
diff -ru tile.old/lib/strchr_32.c tile/lib/strchr_32.c
--- tile.old/lib/strchr_32.c 2010-05-28 18:03:33.918727000 -0400
+++ tile/lib/strchr_32.c 2010-05-28 23:14:25.226239000 -0400
@@ -12,18 +12,9 @@
* more details.
*/

-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
-EXPORT_SYMBOL(strchr);
-#else
-#include <string.h>
-#include <stdint.h>
-#ifdef _LIBC
-libc_hidden_proto(strchr)
-#endif
-#endif

#undef strchr

@@ -60,9 +51,6 @@
if (__builtin_expect(zero_matches | goal_matches, 0))
break;

-#ifdef __TILECC__
-#pragma frequency_hint FREQUENT
-#endif
v = *++p;
}

@@ -75,9 +63,4 @@
*/
return (g <= z) ? ((char *)p) + (g >> 3) : NULL;
}
-
-#ifdef _LIBC
-#undef index
-weak_alias(strchr, index)
-libc_hidden_def(strchr)
-#endif
+EXPORT_SYMBOL(strchr);
diff -ru tile.old/lib/strlen_32.c tile/lib/strlen_32.c
--- tile.old/lib/strlen_32.c 2010-05-28 18:03:33.922713000 -0400
+++ tile/lib/strlen_32.c 2010-05-28 23:14:25.231237000 -0400
@@ -12,18 +12,9 @@
* more details.
*/

-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
#include <linux/module.h>
-EXPORT_SYMBOL(strlen);
-#else
-#include <string.h>
-#include <stdint.h>
-#ifdef _LIBC
-libc_hidden_proto(strlen)
-#endif
-#endif

size_t strlen(const char *s)
{
@@ -42,7 +33,4 @@

return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
}
-
-#ifdef _LIBC
-libc_hidden_def(strlen)
-#endif
+EXPORT_SYMBOL(strlen);
diff -ru tile.old/lib/uaccess.c tile/lib/uaccess.c
--- tile.old/lib/uaccess.c 2010-05-28 18:03:33.924714000 -0400
+++ tile/lib/uaccess.c 2010-05-28 23:14:24.751622000 -0400
@@ -15,11 +15,6 @@
#include <linux/uaccess.h>
#include <linux/module.h>

-
-
-
-
-
int __range_ok(unsigned long addr, unsigned long size)
{
unsigned long limit = current_thread_info()->addr_limit.seg;
diff -ru tile.old/mm/elf.c tile/mm/elf.c
--- tile.old/mm/elf.c 2010-05-28 18:03:33.948698000 -0400
+++ tile/mm/elf.c 2010-05-28 22:57:15.180141000 -0400
@@ -91,10 +91,10 @@
{
if (vma->vm_private_data == vdso_pages)
return "[vdso]";
-
+#ifndef __tilegx__
if (vma->vm_start == MEM_USER_INTRPT)
return "[intrpt]";
-
+#endif
return NULL;
}

@@ -130,7 +130,7 @@
VM_ALWAYSDUMP,
vdso_pages);

-
+#ifndef __tilegx__
/*
* Set up a user-interrupt mapping here; the user can't
* create one themselves since it is above TASK_SIZE.
@@ -146,7 +146,7 @@
if (addr > (unsigned long) -PAGE_SIZE)
retval = (int) addr;
}
-
+#endif

up_write(&mm->mmap_sem);

diff -ru tile.old/mm/fault.c tile/mm/fault.c
--- tile.old/mm/fault.c 2010-05-28 18:03:33.953695000 -0400
+++ tile/mm/fault.c 2010-05-28 22:57:15.212108000 -0400
@@ -42,8 +42,6 @@

#include <arch/interrupts.h>

-#include "../oprofile/op_impl.h"
-
/*
* Unlock any spinlocks which will prevent us from getting the
* message out
@@ -86,14 +84,13 @@
force_sig_info(si_signo, &info, tsk);
}

-
+#ifndef __tilegx__
/*
* Synthesize the fault a PL0 process would get by doing a word-load of
* an unaligned address or a high kernel address. Called indirectly
* from sys_cmpxchg() in kernel/intvec.S.
*/
-SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
- struct pt_regs *, regs)
+int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *regs)
{
if (address >= PAGE_OFFSET)
force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
@@ -118,7 +115,7 @@

return 0;
}
-
+#endif

static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
@@ -574,7 +571,7 @@
return 0;
}

-
+#ifndef __tilegx__

extern char sys_cmpxchg[], __sys_cmpxchg_end[];
extern char __sys_cmpxchg_grab_lock[];
@@ -710,7 +707,7 @@
return state;
}

-
+#endif /* !__tilegx__ */

/*
* This routine handles page faults. It determines the address, and the
@@ -869,10 +866,10 @@

void vmalloc_sync_all(void)
{
-
-
-
-
+#ifdef __tilegx__
+ /* Currently all L1 kernel pmd's are static and shared. */
+ BUG_ON(pgd_index(VMALLOC_END) != pgd_index(VMALLOC_START));
+#else
/*
* Note that races in the updates of insync and start aren't
* problematic: insync can only get set bits added, and updates to
@@ -904,5 +901,5 @@
if (address == start && test_bit(pgd_index(address), insync))
start = address + PGDIR_SIZE;
}
-
+#endif
}
diff -ru tile.old/mm/homecache.c tile/mm/homecache.c
--- tile.old/mm/homecache.c 2010-05-28 18:03:33.964669000 -0400
+++ tile/mm/homecache.c 2010-05-28 23:19:31.752709000 -0400
@@ -36,36 +36,8 @@
#include <asm/pgalloc.h>
#include <asm/homecache.h>

-#include <arch/sim.h>
-
#include "migrate.h"

-#ifdef CONFIG_HOMECACHE
-
-/* Forward declarations. */
-static int homecache_get_desired_home(int home, pgprot_t, int writable);
-
-/* Various statistics exposed through /proc/sys/tile/homecache/. */
-
-/* Pages sequestered at "free" time (e.g. immutable). */
-static int homecache_proc_sequestered_free;
-
-/* Pages sequestered at "alloc" time (e.g. homed on a dataplane tile). */
-static int homecache_proc_sequestered_alloc;
-
-/* Times we have done a chip-wide flush and unsequestered everything. */
-static int homecache_proc_sequestered_purge;
-
-/* Number of unmapped pages migrated (i.e. no PTEs yet). */
-static int homecache_proc_migrated_unmapped;
-
-/* Number of mapped pages we have migrated. */
-static int homecache_proc_migrated_mapped;
-
-/* Number of tasks that have been migrated. */
-static int homecache_proc_migrated_tasks;
-
-#endif /* CONFIG_HOMECACHE */

#if CHIP_HAS_COHERENT_LOCAL_CACHE()

@@ -89,155 +61,13 @@
#endif


-#ifdef CONFIG_HOMECACHE
-
-/*
- * We manage a per-cpu word that says when the last full cache
- * eviction was, and a per-free-page timestamp that says when it was
- * freed, so we can know when we re-allocate that page whether or not
- * we have to go flush it off its old home.
- */
-
-/* Define a global "time" for cache eviction events */
-static atomic_t cache_flush_counter;
-
-/*
- * At what "time" was the cache fully evicted on a given processor?
- * Using -1 here means that all pages initially in the heap (with
- * free_time zero) will report that they are not in cache, even before
- * we do any flushes on any cpus.
- */
-DEFINE_PER_CPU(int, last_cache_flush) = -1;
-
-/*
- * Gather a timestamp to use before we start doing our cache evict.
- * The increment will mean any pages freed later than this time do
- * not assume they are clean based on the eviction we are about to do.
- */
-static inline int mark_caches_evicted_start(void)
-{
- return atomic_inc_return(&cache_flush_counter);
-}
-
-/*
- * Publish the timestamp for cache eviction on the cpus we evicted.
- * Doing it after the eviction is complete means any pages re-allocated
- * prior to this time will not assume they are clean based on an
- * ongoing eviction.
- */
-static inline void mark_caches_evicted_finish(const struct cpumask *mask,
- int timestamp)
-{
- int i;
- for_each_cpu(i, mask)
- per_cpu(last_cache_flush, i) = timestamp;
-}
-
-/* Mark this group of pages as freed at this "time". */
-static inline void mark_pages_free_time(struct page *page, int order)
-{
- int timestamp = atomic_read(&cache_flush_counter);
- int pages = 1 << order;
- int i;
- for (i = 0; i < pages; ++i)
- page[i].free_time = timestamp;
-}
-
-/* Report whether this page might still be in the cache on this cpu. */
-static inline int is_free_page_in_cache(int cpu, struct page *page)
-{
- /*
- * Compute an explicit delta so that even after we wrap
- * the counters, as long as everything stays within 2 billion
- * eviction calls of each other, we will still get correct
- * comparative results. (Though -fwrapv may be an issue.)
- */
- int delta = page->free_time - per_cpu(last_cache_flush, cpu);
- return delta >= 0;
-}
-
-/* Remove any cpus that must have already flushed this page's data. */
-static void clear_flushed_cpus(struct cpumask *mask, struct page *page)
-{
- int cpu;
- for_each_cpu(cpu, mask)
- if (!is_free_page_in_cache(cpu, page))
- cpumask_clear_cpu(cpu, mask);
-}
-
-#else

/* Provide no-op versions of these routines to keep flush_remote() cleaner. */
#define mark_caches_evicted_start() 0
#define mark_caches_evicted_finish(mask, timestamp) do {} while (0)

-#endif /* CONFIG_HOMECACHE */
-
-
-#ifdef CONFIG_DATAPLANE
-
-/* State of TLB deferral on a dataplane cpu. */
-static DEFINE_PER_CPU(atomic_t, dataplane_tlb_state);
-
-/* Provide constants for dataplane TLB deferral. */
-#define TLB_DEFER_KERNEL 0 /* in kernel space */
-/* Note: can't use value "1" since we are using tns-atomic routines. */
-#define TLB_DEFER_USER 2 /* in user space */
-#define TLB_DEFER_PENDING 3 /* in user space with a TLB flush pending */
-
-/*
- * This routine is called on kernel entry from userspace for dataplane
- * tiles, so we can properly adjust our state to be TLB_DEFER_KERNEL,
- * and run a TLB flush if necessary.
- *
- * This routine is only called with interrupts disabled, so we don't
- * need any special handling around the tns atomic call.
- */
-void homecache_tlb_defer_enter(void)
-{
- atomic_t *state = &__get_cpu_var(dataplane_tlb_state);
- if (tns_atomic_xchg(state, TLB_DEFER_KERNEL) == TLB_DEFER_PENDING) {
- unsigned long size = KERNEL_HIGH_VADDR - PAGE_OFFSET;
- int rc = hv_flush_pages(PAGE_OFFSET, PAGE_SIZE, size);
- rc |= hv_flush_pages(PAGE_OFFSET, HPAGE_SIZE, size);
- BUG_ON(rc != 0);
- }
-}
-
-/*
- * This routine is called on kernel exit to userspace for dataplane
- * tiles, so we can properly adjust our state to be TLB_DEFER_USER.
- *
- * This routine is only called with interrupts disabled, so we don't
- * need any special handling around the tns atomic call.
- */
-void homecache_tlb_defer_exit(void)
-{
- atomic_t *state = &__get_cpu_var(dataplane_tlb_state);
-
- /*
- * Note that we could write directly to state->counter here
- * instead of using the normal serializing tns_atomic_set(),
- * since we shouldn't be able to race with the other deferral
- * routines any more than we already do. But it makes it easier
- * to reason about this code to use the serializing version,
- * and I'm not concerned about performance in this context.
- */
- tns_atomic_set(state, TLB_DEFER_USER);
-}

-/*
- * This routine determines if we can defer a TLB flush.
- * It must be called with interrupts disabled.
- */
-static int homecache_tlb_can_defer(int cpu)
-{
- atomic_t *state = &per_cpu(dataplane_tlb_state, cpu);
- int old = tns_atomic_cmpxchg(state, TLB_DEFER_USER, TLB_DEFER_PENDING);
- return (old != TLB_DEFER_KERNEL);
-}

-#endif /* CONFIG_DATAPLANE */

/*
* Update the irq_stat for cpus that we are going to interrupt
@@ -256,35 +86,6 @@
if (cache_cpumask)
cpumask_or(&mask, &mask, cache_cpumask);
if (tlb_cpumask && tlb_length) {
-#ifdef CONFIG_DATAPLANE
- /*
- * If we are doing TLB flushes to kernel addresses we
- * check to see if there are any dataplane tiles that
- * are currently running user code and if so, mark
- * them as pending a TLB flush, and remove them from
- * tlb_cpumask. We only proceed with the flush on
- * such tiles if they are in the kernel.
- */
- if (tlb_va >= PAGE_OFFSET &&
- tlb_va + tlb_length < KERNEL_HIGH_VADDR) {
- struct cpumask maybe_defer;
- cpumask_and(&maybe_defer, tlb_cpumask, &dataplane_map);
- if (!cpumask_empty(&maybe_defer)) {
- /*
- * We save and restore interrupts here since
- * tns-atomic calls in homecache_tlb_can_defer
- * require interrupts to be disabled.
- */
- unsigned long flags;
- local_irq_save(flags);
- for_each_cpu(cpu, &maybe_defer)
- if (homecache_tlb_can_defer(cpu))
- cpumask_clear_cpu(cpu,
- tlb_cpumask);
- local_irq_restore(flags);
- }
- }
-#endif
cpumask_or(&mask, &mask, tlb_cpumask);
}

@@ -430,7 +231,8 @@
/* On the simulator, confirm lines have been evicted everywhere. */
static void validate_lines_evicted(unsigned long pfn, size_t length)
{
- sim_validate_lines_evicted((HV_PhysAddr)pfn << PAGE_SHIFT, length);
+ sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
+ (HV_PhysAddr)pfn << PAGE_SHIFT, length);
}

/* Flush a page out of whatever cache(s) it is in. */
@@ -559,8 +361,6 @@
return pte;
}

-#ifndef CONFIG_HOMECACHE
-
/*
* The routines in this section are the "static" versions of the normal
* dynamic homecaching routines; they just set the home cache
@@ -643,2069 +443,3 @@
__free_page(page++);
}
}
-
-
-#else /* dynamic homecaching support hooked into the Linux internals */
-
-
-
-/*
- * When we free a page, in addition to marking the pages as free,
- * we check the homing to determine what to do with it.
- *
- * Pages that are compatible with the buddy allocator get freed
- * normally. With hash_default, this means hash-for-home pages only,
- * since we expect most pages to come back that way. Otherwise, we
- * do all pages that are "cheap" to re-home (i.e. pages cached on
- * a single cpu, plus uncached pages).
- *
- * Pages that are potentially cached on every cpu are put onto
- * a special global "sequestered" list, since we don't anticipate
- * being able to easily reuse them for anything without doing
- * a global round of cache flushing first.
- *
- * Other pages (the kind that didn't go in the buddy allocator)
- * are stored on a special per-zone free list and checked whenever
- * we do an allocation from that zone that requests a home override,
- * so we can re-use them without having to do a remote flush
- * on a page that we pulled from the buddy allocator.
- */
-
-static spinlock_t homecache_free_lock =
- __SPIN_LOCK_UNLOCKED(&homecache_free_lock);
-
-static struct list_head homecache_free_list =
- LIST_HEAD_INIT(homecache_free_list);
-
-/* Do we want to free this page back to the buddy allocator? */
-static int home_is_freeable(int home)
-{
- /* For hash-default heap, we only free back hash pages. */
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (hash_default)
- return home == PAGE_HOME_HASH;
-#endif
-
- /* Otherwise, we only free back things that are easy to re-home. */
- return (home == PAGE_HOME_UNCACHED || home >= 0);
-}
-
-/*
- * When resetting a page's homecache (e.g. when freshly allocating the
- * page, flushing out the homecache free list, or converting an
- * immutable page) what home should we reset it to?
- */
-static int default_page_home(void)
-{
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (hash_default)
- return PAGE_HOME_HASH;
-#endif
- /* Arbitrarily home the page back on this cpu. */
- return smp_processor_id();
-}
-
-/* When true, the homecache checker passes all pages to the buddy allocator. */
-static DEFINE_PER_CPU(int, homecache_is_unsequestering);
-
-int homecache_check_free_page(struct page *page, int order)
-{
- int pages, i;
- unsigned long flags;
- int home = page_home(page);
- spinlock_t *lock; /* lock for "list" (below) */
- struct list_head *list;
-
- mark_pages_free_time(page, order);
-
- /*
- * Clear the homecache_nomigrate bit; it would only have been
- * set if we had vmapped the page and now have unmapped it and
- * are freeing it.
- */
- pages = (1 << order);
- for (i = 0; i < pages; ++i)
- __ClearPageHomecacheNomigrate(&page[i]);
-
- /* Validate that the whole allocation was identically homed. */
- for (i = 1; i < pages; ++i)
- BUG_ON(page_home(&page[i]) != home);
-
- /* Huge pages always go back to the allocator. */
- if (order == HUGETLB_PAGE_ORDER)
- return 0;
-
- /*
- * In kdata=huge mode, any lowmem page mapped by a small
- * kernel PTE goes onto the per-zone freelists, unless the
- * "homecache_is_unsequestering" flag is set, in which case we
- * have to put them all back into the buddy allocator anyway.
- */
- if (__get_cpu_var(homecache_is_unsequestering) ||
- ((!kdata_huge ||
- PageHighMem(page) ||
- pte_huge(*virt_to_pte(NULL, (ulong)page_address(page)))) &&
- home_is_freeable(home)))
- return 0;
-
- /*
- * Duplicate some code from __free_one_page(), in particular
- * unmarking compund pages.
- */
- if (unlikely(PageCompound(page))) {
- __ClearPageHead(page);
- for (i = 1; i < pages; i++)
- __ClearPageTail(page + i);
- }
-
- /*
- * Otherwise queue the individual pages and tell the buddy free code
- * that it doesn't need to deal with them.
- */
- if (home == PAGE_HOME_IMMUTABLE || home == PAGE_HOME_INCOHERENT) {
- /* We can't easily reuse these, so sequester them away. */
- lock = &homecache_free_lock;
- list = &homecache_free_list;
- } else {
- struct zone *zone = page_zone(page);
- lock = &zone->lock;
- list = &zone->homecache_list;
- }
- spin_lock_irqsave(lock, flags);
- homecache_proc_sequestered_free += pages;
- for (i = 0; i < pages; ++i)
- list_add(&page[i].lru, list);
- spin_unlock_irqrestore(lock, flags);
- return 1;
-}
-
-/* Check that the page was allocated properly. */
-static void check_page_home(struct page *page, int home)
-{
- pte_t pte;
- if (home == PAGE_HOME_UNKNOWN)
- return;
-#ifdef CONFIG_PREEMPT
-#warning Consider just testing that the page is not hfh here?
-#else
- if (home == PAGE_HOME_HERE)
- home = smp_processor_id();
-#endif
- if (page_home(page) != home)
- panic("Allocated page PFN %#lx should have home %d, has %d\n",
- page_to_pfn(page), home, page_home(page));
- if (PageHighMem(page))
- return;
- pte = *virt_to_pte(NULL, (unsigned long)page_address(page));
- BUG_ON(pte_to_home(pte) != home);
-}
-
-static inline int homecache_set_desired_home(int home)
-{
- int oldhome = current->thread.homecache_desired_home;
- current->thread.homecache_desired_home = home;
- return oldhome;
-}
-
-struct page *homecache_alloc_pages(gfp_t gfp_mask,
- unsigned int order, int home)
-{
- struct page *page;
- int oldhome = homecache_set_desired_home(home);
- page = alloc_pages(gfp_mask, order);
- homecache_set_desired_home(oldhome);
- if (page)
- check_page_home(page, home);
- return page;
-}
-
-struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask,
- unsigned int order, int home)
-{
- struct page *page;
- int oldhome = homecache_set_desired_home(home);
- page = alloc_pages_node(nid, gfp_mask, order);
- homecache_set_desired_home(oldhome);
- if (page)
- check_page_home(page, home);
- return page;
-}
-
-struct page *homecache_alloc_page_vma(gfp_t gfp_mask,
- struct vm_area_struct *vma,
- unsigned long addr)
-{
- pgprot_t prot = vma->vm_page_prot;
- if (!pte_get_forcecache(prot)) {
- return alloc_page_vma(gfp_mask, vma, addr);
- } else {
- struct page *page;
- int oldhome, home = default_page_home();
-
- home = homecache_get_desired_home(home, prot, 1);
- oldhome = homecache_set_desired_home(home);
- page = alloc_page_vma(gfp_mask, vma, addr);
- homecache_set_desired_home(oldhome);
- if (page == NULL)
- return NULL;
- check_page_home(page, home);
-
-#if CHIP_HAS_NC_AND_NOALLOC_BITS()
- /*
- * If we are allocating a page with noalloc attributes,
- * we should ensure it starts with a clean local cache.
- * Normal coherence won't necessarily have flushed the
- * local cache.
- */
- if (hv_pte_get_no_alloc_l2(prot) ||
- hv_pte_get_no_alloc_l1(prot)) {
- void *addr = kmap_atomic(page, KM_USER0);
- flush_buffer(addr, PAGE_SIZE);
- kunmap_atomic(addr, KM_USER0);
- }
-#endif
-
- return page;
- }
-}
-
-/**
- * shatter_huge_page() - ensure a given address is mapped by a small page.
- *
- * This function converts a huge PTE mapping kernel LOWMEM into a bunch
- * of small PTEs with the same caching. No cache flush required, but we
- * must do a global TLB flush.
- *
- * Any caller that wishes to modify a kernel mapping that might
- * have been made with a huge page should call this function,
- * since doing so properly avoids race conditions with installing the
- * newly-shattered page and then flushing all the TLB entries.
- *
- * @addr: Address at which to shatter any existing huge page.
- */
-static void shatter_huge_page(unsigned long addr)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- unsigned long flags = 0; /* happy compiler */
-#ifdef __PAGETABLE_PMD_FOLDED
- struct list_head *pos;
-#endif
-
- /* Get a pointer to the pmd entry that we need to change. */
- addr &= HPAGE_MASK;
- BUG_ON(pgd_addr_invalid(addr));
- BUG_ON(addr < PAGE_OFFSET); /* only for kernel LOWMEM */
- pgd = swapper_pg_dir + pgd_index(addr);
- pud = pud_offset(pgd, addr);
- BUG_ON(!pud_present(*pud));
- pmd = pmd_offset(pud, addr);
- BUG_ON(!pmd_present(*pmd));
- if (!pmd_huge_page(*pmd))
- return;
-
- /*
- * Grab the pgd_lock, since we may need it to walk the pgd_list,
- * and since we need some kind of lock here to avoid races.
- */
- spin_lock_irqsave(&pgd_lock, flags);
- if (!pmd_huge_page(*pmd)) {
- /* Lost the race to convert the huge page. */
- spin_unlock_irqrestore(&pgd_lock, flags);
- return;
- }
-
- /* Shatter the huge page into the preallocated L2 page table. */
- pmd_populate_kernel(&init_mm, pmd,
- get_prealloc_pte(pte_pfn(*(pte_t *)pmd)));
-
-#ifdef __PAGETABLE_PMD_FOLDED
- /* Walk every pgd on the system and update the pmd there. */
- list_for_each(pos, &pgd_list) {
- pmd_t *copy_pmd;
- pgd = list_to_pgd(pos) + pgd_index(addr);
- pud = pud_offset(pgd, addr);
- copy_pmd = pmd_offset(pud, addr);
- *copy_pmd = *pmd;
- }
-#endif
-
- /* Tell every cpu to notice the change. */
- flush_remote(0, 0, NULL, addr, HPAGE_SIZE, HPAGE_SIZE,
- cpu_possible_mask, NULL, 0);
-
- /* Hold the lock until the TLB flush is finished to avoid races. */
- spin_unlock_irqrestore(&pgd_lock, flags);
-
- printk(KERN_DEBUG "homecache: info: shattered huge page %#lx\n", addr);
-}
-
-/* Called with interrupts disabled but the zone unlocked. */
-struct page *homecache_get_cached_page(struct zone *zone, int gfp_flags)
-{
- struct page *page;
- int home = current->thread.homecache_desired_home;
- int require_homecache = kdata_huge && !is_highmem(zone);
- int order;
-
- /* Safe to convert here since we have interrupts disabled. */
- if (home == PAGE_HOME_HERE)
- home = smp_processor_id();
-
- /*
- * The __GFP_HIGHMEM flag is a hint to this code that, if it
- * is in a "require_homecache" zone (lowmem with kdata_huge)
- * it should go to the homecache free list even if the request
- * does not appear to merit homecaching. This is because
- * such pages are for user space or the page cache, both of
- * which are prone to homecache adjustment.
- */
- if (!((gfp_flags & __GFP_HIGHMEM) && require_homecache)) {
-
- /* Don't bother looking on the list if there's no override. */
- if (home == PAGE_HOME_UNKNOWN)
- return NULL;
-
- /* Don't bother for types that match the allocator. */
- if (home_is_freeable(home))
- return NULL;
-
- }
-
- /*
- * Walk the list looking for a match of homecache.
- * NOTE: we could have NR_CPUS+5 (or so) lists per zone and
- * just do lookups in constant time when the right type was on
- * the list to begin with. But if we miss we then have
- * to check every list to see if there is some other small
- * page we can re-homecache. So for now, keep it simple.
- */
- spin_lock(&zone->lock);
- list_for_each_entry(page, &zone->homecache_list, lru) {
- if (page_home(page) == home) {
- check_page_home(page, home);
- list_del(&page->lru);
- goto unlock;
- }
- }
-
- /*
- * If we are using huge pages in the buddy allocator, and this
- * is a LOWMEM zone, we would rather re-homecache an existing
- * small page than shatter a new huge page. So see if we
- * have anything that is usable if we re-homecache it.
- * We ignore the "migratetype", which is basically about
- * defragmentation, and segregating the homecache pages is
- * too, so it's plausible to ignore migratetype if necessary.
- */
- if (require_homecache) {
- if (!list_empty(&zone->homecache_list)) {
- page = list_first_entry(&zone->homecache_list, \
- struct page, lru);
- list_del(&page->lru);
- goto unlock;
- }
-
- /*
- * We need to shatter a new huge page. Ideally we get
- * an entire huge page and shatter it. But we work
- * our way down to order-0 anyway, to be robust.
- */
- for (order = HUGETLB_PAGE_ORDER; order >= 0; --order) {
- extern struct page *__rmqueue(struct zone *,
- unsigned int order,
- int migratetype);
- int migratetype = allocflags_to_migratetype(gfp_flags);
- page = __rmqueue(zone, order, migratetype);
- if (page)
- break;
- }
- if (page) {
- int i, pages = 1 << order;
- unsigned long kaddr =
- (unsigned long)page_address(page);
- shatter_huge_page(kaddr);
- printk(KERN_DEBUG "homecache: info: added page range"
- " at %p (%d pages)\n",
- page_address(page), pages);
- for (i = 1; i < pages; ++i)
- list_add(&page[i].lru, &zone->homecache_list);
- goto unlock;
- }
-
- }
-
- /* No luck; just get something from the buddy allocator. */
- page = NULL;
-
- unlock:
- spin_unlock(&zone->lock);
- return page;
-}
-
-/*
- * If this page is cached on a dataplane tile, don't allow the allocator
- * to return it to any other cpu, since it will induce cache flushes
- * on the dataplane tile.
- *
- * We could set a per-cpu word whenever we place a page on the list
- * that is cached on a single cpu. Then, whenever a dataplane cpu
- * enters the kernel, it checks its per-cpu word to see if it is
- * non-zero, and if so it takes out the homecache free list lock,
- * frees all the pages cached on its own cpu, flushes its own cache,
- * resets the flag word to zero, then releases the lock. Note that we
- * don't need to check the word under the lock, since if we miss it,
- * it's benign (we do need to modify the word under the lock, though).
- *
- * For now, we don't try to shield dataplane tiles from huge pages
- * being freed on a dataplane tile and reused on a different tile
- * later; huge pages are a very scarce resource and we don't really
- * want to try to sequester them, and in any case, real applications
- * tend to settle down into their final use of huge pages very quickly.
- */
-static int homecache_check_alloced_page(struct page *page, int order)
-{
-#ifdef CONFIG_DATAPLANE
- int i, pages, cpu, home, rc;
- unsigned long flags;
-
- /* If no dataplane tiles or this is a huge page, take an early exit. */
- if (cpumask_empty(&dataplane_map) || order == HUGETLB_PAGE_ORDER)
- return 0;
-
- /* Don't worry about any of this until we finish boot. */
- if (system_state != SYSTEM_RUNNING)
- return 0;
-
- /* Check each page; exit the loop if we find a bad page. */
- pages = (1 << order);
- cpu = default_page_home();
- for (i = 0; ; ++i) {
- /* If we've checked all the pages, we can use this memory. */
- if (i == pages)
- return 0;
-
- /*
- * If this page is already homed correctly, or is
- * uncached, it won't cause any trouble.
- */
- home = page_home(&page[i]);
- if (home == cpu || home == PAGE_HOME_UNCACHED)
- continue;
-
- /*
- * Any other kind of unusually-cached page is presumed
- * to cause trouble to some dataplane cache. (In fact
- * it's possible that hash-for-home cpus might not overlap
- * dataplane cpus, but we ignore that for now.)
- */
- if (home < 0)
- break;
-
- /*
- * The page is homed on a single cpu. If it's not a
- * dataplane cpu, we don't have a problem.
- */
- if (!cpumask_test_cpu(home, &dataplane_map))
- continue;
-
- /*
- * The page is on a dataplane cpu; if it might be in its
- * cache, we can't use this allocation.
- */
- if (is_free_page_in_cache(home, &page[i]))
- break;
- }
-
- /*
- * Bad page(s); just put them onto the homecache sequestered list.
- * If we put them on the zone free list, we'll probably get them
- * back again when we loop back to get a new page, which is bad.
- */
- rc = put_page_testzero(page);
- BUG_ON(!rc);
- spin_lock_irqsave(&homecache_free_lock, flags);
- homecache_proc_sequestered_alloc += pages;
- for (i = 0; i < pages; ++i)
- list_add(&page[i].lru, &homecache_free_list);
- spin_unlock_irqrestore(&homecache_free_lock, flags);
- return 1;
-#else
- return 0;
-#endif
-}
-
-static int count_pages(struct list_head *list, spinlock_t *lock)
-{
- struct list_head *pos;
- int npages = 0;
-
- spin_lock(lock);
- list_for_each(pos, list)
- ++npages;
- spin_unlock(lock);
-
- return npages;
-}
-
-long homecache_count_sequestered_pages()
-{
- struct zone *zone;
- unsigned long flags;
- int npages;
-
- local_irq_save(flags);
- npages = count_pages(&homecache_free_list, &homecache_free_lock);
- for_each_zone(zone)
- npages += count_pages(&zone->homecache_list, &zone->lock);
- local_irq_restore(flags);
-
- return npages;
-}
-
-static int homecache_do_free(struct list_head *list, spinlock_t *lock,
- unsigned long *low_kaddr,
- unsigned long *high_kaddr, int flush_whole_chip)
-{
- struct list_head work_list;
- int npages = 0;
- struct pagevec pvec = { .nr = 1, .cold = 1 };
-
- /* Capture list onto a local copy */
- INIT_LIST_HEAD(&work_list);
- spin_lock(lock);
- list_splice_init(list, &work_list);
- spin_unlock(lock);
-
- /* Re-inject the pages back into the buddy allocator */
- while (!list_empty(&work_list)) {
- struct page *page =
- list_entry(work_list.prev, struct page, lru);
- int home = page_home(page);
-
- /*
- * If the cpu where this page is cached isn't a cpu
- * the hypervisor can flush, we can't return it to the
- * allocator. Just put it back on the homecache
- * freelist and continue.
- */
- if (home >= 0 && !cpu_cacheable(home)) {
- spin_lock(lock);
- list_add(&page->lru, list);
- spin_unlock(lock);
- continue;
- }
-
- if (flush_whole_chip) {
- unsigned long kva = (unsigned long) page_address(page);
- set_page_home(page, default_page_home());
- if (kva != 0) {
- /*
- * Flush the TLB for the kernel so we
- * can rewrite the PTE to align with
- * the newly-chosen home.
- */
- pte_t *pte = virt_to_pte(NULL, kva);
- BUG_ON(pte == NULL || pte_huge(*pte));
- set_pte(pte, mk_pte(page, PAGE_KERNEL));
- if (kva < *low_kaddr)
- *low_kaddr = kva;
- if (kva + PAGE_SIZE > *high_kaddr)
- *high_kaddr = kva + PAGE_SIZE;
- }
- }
- list_del(&page->lru);
- pvec.pages[0] = page;
- __pagevec_free(&pvec); /* free page as a cold page */
- ++npages;
- }
-
- /* TODO: this would be an obvious point to unshatter any huge pages. */
-
- return npages;
-}
-
-int homecache_recover_free_pages()
-{
- int npages;
- unsigned long flags;
- unsigned long low_kaddr = ~0UL, high_kaddr = 0;
- int flush_whole_chip;
- static int verbose_message;
- struct zone *zone;
-
- /* Disable interrupts so we don't uselessly re-enter this routine. */
- local_irq_save(flags);
- __get_cpu_var(homecache_is_unsequestering) = 1;
-
- /*
- * If the per-zone freelists have sufficient pages, just free
- * them back to the allocator without resetting their homes
- * and without doing a disruptive whole-chip cache flush.
- * We can safely return pages from the per-zone lists with no
- * need to do anything else for now, since the per-zone pages
- * will be homed on single cpus anyway, and we can flush them
- * as we start re-allocating them.
- *
- * We pick an arbitrary threshold number of pages that will trigger
- * us to try to go back into the main kernel page allocator.
- */
- flush_whole_chip = 1;
- npages = 0;
- for_each_zone(zone) {
- struct page *page;
- spin_lock(&zone->lock);
- list_for_each_entry(page, &zone->homecache_list, lru) {
- if (++npages > 256) {
- flush_whole_chip = 0;
- break;
- }
- }
- spin_unlock(&zone->lock);
- if (!flush_whole_chip)
- break;
- }
-
- /* Now go and actually free the per-zone lists to the allocator. */
- npages = 0;
- for_each_zone(zone)
- npages += homecache_do_free(&zone->homecache_list, &zone->lock,
- &low_kaddr, &high_kaddr,
- flush_whole_chip);
- if (!flush_whole_chip) {
- __get_cpu_var(homecache_is_unsequestering) = 0;
- local_irq_restore(flags);
- printk(KERN_DEBUG "Returned %d per-zone homecache pages"
- " to the buddy allocator\n", npages);
- return 1;
- }
-
- /* Add the incoherent pages, and now we have to flush everything. */
- npages += homecache_do_free(&homecache_free_list, &homecache_free_lock,
- &low_kaddr, &high_kaddr, 1);
- __get_cpu_var(homecache_is_unsequestering) = 0;
-
- if (npages == 0) {
- local_irq_restore(flags);
- return 0;
- }
-
- ++homecache_proc_sequestered_purge;
-
- if (low_kaddr > high_kaddr) {
- low_kaddr = 0;
- high_kaddr = 0;
- }
-
- /* Flush caches and probably TLBs everywhere */
- flush_remote(0, HV_FLUSH_EVICT_L2, &cpu_cacheable_map,
- low_kaddr, high_kaddr - low_kaddr, PAGE_SIZE,
- cpu_online_mask, NULL, 0);
-
- local_irq_restore(flags);
-
-#ifdef CONFIG_DATAPLANE
- if (!cpus_empty(dataplane_map)) {
- /*
- * If running dataplane tiles, warn on the console about this,
- * since we potentially just interrupted a dataplane tile.
- */
- printk(KERN_INFO "cpu %d (%s/%d): homecache freed"
- " %d sequestered pages.\n", smp_processor_id(),
- current->comm, current->pid, npages);
- if (!verbose_message) {
- verbose_message = 1;
- printk(KERN_INFO
-"The homecache subsystem of the kernel sequesters certain kinds of pages\n"
-"when they are freed, and requires a cache flush on all cpus to reuse them.\n"
-"This may cause unexpected, unavoidable glitches on dataplane cpus.\n"
-"This problem may be caused by running and deleting many executables,\n"
-"as for example is done over a FUSE connection. It is also commonly seen\n"
-"when the page cache is in heavy use, which we anticipate correcting in a\n"
-"future MDE release. Note that the cpu and the process that trigger this\n"
-"message may not be responsible for causing the page sequestering.\n"
- );
- }
- }
-#endif
-
- /* Tell the buddy allocator to jump back and try again. */
- return 1;
-}
-
-
-/*
- * Provide a lock and two accessors to lock when we are doing
- * page migration and when we are trying to add new kernel mappings.
- */
-
-static spinlock_t kpte_lock = __SPIN_LOCK_UNLOCKED(&kpte_lock);
-
-unsigned long homecache_kpte_lock(void)
-{
- unsigned long flags;
- spin_lock_irqsave(&kpte_lock, flags);
- return flags;
-}
-
-void homecache_kpte_unlock(unsigned long flags)
-{
- spin_unlock_irqrestore(&kpte_lock, flags);
-}
-
-
-/*
- * Find the kernel PTE mapping this page (either lowmem or kmap) and
- * adjust it as follows. If "finished" is false, we mark it as
- * migrating; otherwise, we rebuild it "from scratch". In
- * the normal migration model (mark PTEs migrating; flush TLBs; flush
- * caches; rewrite PTEs) the finished=0 and finished=1 modes
- * correspond to the first and last phases, respectively.
- *
- * FIXME: ptrace writes on huge pages will create temporary mappings
- * of sub-pages within the huge page, and we will not see it since we
- * are only checking for the vaddr of the beginning of the huge page.
- * We could loop calling kmap_fix_kpte() or pass "pages" to kmap_fix_kpte,
- * but either way is still likely pretty inefficient, and we might end
- * up with a set of unrelated kernel VAs that we need to flush.
- */
-static unsigned long homecache_fix_kpte(struct page *page, int pages,
- int finished)
-{
- int i, pfn;
- int home = page->home;
- unsigned long vaddr;
- pte_t *ptep;
- pgprot_t prot;
-
-#ifdef CONFIG_HIGHMEM
- if (PageHighMem(page)) {
- kmap_atomic_fix_kpte(page, finished);
- vaddr = (unsigned long) kmap_fix_kpte(page, finished);
- return vaddr;
- }
-#endif
- pfn = page_to_pfn(page);
- vaddr = (unsigned long) lowmem_page_address(page);
- shatter_huge_page((unsigned long)vaddr);
- ptep = virt_to_pte(NULL, (unsigned long) vaddr);
- BUG_ON(ptep == NULL || pte_huge(*ptep));
- prot = (home == PAGE_HOME_IMMUTABLE) ? PAGE_KERNEL_RO : PAGE_KERNEL;
- prot = (pgprot_t) pte_set_home((pte_t) prot, home);
- for (i = 0; i < pages; ++i, ++pfn, ++ptep) {
- if (!finished) {
- pte_t pte = *ptep;
- set_pte(ptep, pte_mkmigrate(pte));
- BUG_ON(!pte_same(pte, pfn_pte(pfn, prot)));
- } else {
- set_pte(ptep, pfn_pte(pfn, prot));
- }
- }
- return vaddr;
-}
-
-/* Mark a group of pages with their new homecache. */
-static void set_pages_home(struct page *page, int pages, int home)
-{
- int i;
- for (i = 0; i < pages; ++i)
- set_page_home(&page[i], home);
-}
-
-/*
- * Remember that we allocated this page on this processor,
- * so that we can set up our PTEs to always reference that home.
- * Arguably we might want to be able to batch page allocations
- * here so we can avoid multiple IPI round-trips. TBD.
- * However, note that we have per-cpu freelists, so that it is
- * at least plausible that we will get mostly same-cpu homed
- * pages once we get into a steady state.
- *
- * Locking requirements are substantially eased in this code
- * because we are guaranteeing that the page(s) are not mapped
- * into user-space anywhere.
- *
- * The "home" argument is the requested new setting for the
- * specified block of pages; the "is_free" argument indicates whether
- * it may be legal to skip cache flushing for the page, which is only
- * true if its data has not been read or written since it was freed.
- */
-static void homecache_home_unmapped_page(struct page *page, int order,
- int new_home, int is_free)
-{
- int pages = 1 << order;
- int length = pages * PAGE_SIZE;
- struct cpumask home_mask;
- const struct cpumask *tlb_mask;
- unsigned long pfn = page_to_pfn(page);
- unsigned long vaddr;
- int i;
-
- /*
- * Validate the assumption that the page is unmapped
- * and is available for migration.
- */
- for (i = 0; i < pages; ++i) {
- BUG_ON(page_mapcount(&page[i]) != 0);
- BUG_ON(PageHomecacheNomigrate(&page[i]));
- }
-
- /* Do a quick check if migration is needed at all. */
- for (i = 0; i < pages; ++i) {
- if (page_home(&page[i]) != new_home)
- break;
- }
- if (i == pages)
- return;
-
- /*
- * We do need to migrate, so build up the mask to flush.
- * For pages that are free, we can refine the set of
- * cpus to cache-flush, since we don't have to re-flush
- * the cache for pages that were freed before the last
- * cache evict on that page's cpu.
- */
- cpumask_clear(&home_mask);
- for (i = 0; i < pages; ++i) {
- int home = page_home(&page[i]);
- struct cpumask page_home_mask;
- if (page_home(&page[i]) == new_home)
- continue;
- if (home == PAGE_HOME_UNCACHED)
- continue;
- if (home == PAGE_HOME_IMMUTABLE ||
- home == PAGE_HOME_INCOHERENT)
- cpumask_copy(&page_home_mask, &cpu_possible_map);
-#if CHIP_HAS_CBOX_HOME_MAP()
- else if (home == PAGE_HOME_HASH)
- cpumask_copy(&page_home_mask, &hash_for_home_map);
-#endif
- else {
- BUG_ON(home < 0 || home >= NR_CPUS);
- cpumask_copy(&page_home_mask, cpumask_of(home));
- }
- if (is_free)
- clear_flushed_cpus(&page_home_mask, page);
- cpumask_or(&home_mask, &home_mask, &page_home_mask);
- if (i < pages && cpumask_equal(&home_mask, &cpu_cacheable_map))
- break;
- }
-
- homecache_proc_migrated_unmapped += pages;
-
- set_pages_home(page, pages, new_home);
-
- vaddr = homecache_fix_kpte(page, pages, 1);
- tlb_mask = vaddr ? cpu_online_mask : NULL;
-
- if (cpumask_empty(&home_mask) && tlb_mask == NULL)
- return;
-
- flush_remote(pfn, cache_flush_length(length), &home_mask,
- vaddr, length, PAGE_SIZE, tlb_mask, NULL, 0);
-
- /*
- * Don't try to validate for multi-page allocations, since
- * some subpages might have the right home to begin with,
- * and thus not be flushed at all.
- */
- if (pages == 1)
- validate_lines_evicted(pfn, length);
-}
-
-void homecache_change_page_home(struct page *page, int order, int home)
-{
- homecache_home_unmapped_page(page, order, home, 0);
-}
-
-int homecache_new_kernel_page(struct page *page, int order)
-{
- int rc = homecache_check_alloced_page(page, order);
- if (rc == 0) {
- int home = current->thread.homecache_desired_home;
- if (home == PAGE_HOME_UNKNOWN)
- home = default_page_home();
- if (home == PAGE_HOME_HERE)
- home = smp_processor_id();
- homecache_home_unmapped_page(page, order, home, 1);
- }
- return rc;
-}
-
-void homecache_update_migrating_pte(struct page *page, pte_t *ptep,
- struct vm_area_struct *vma,
- unsigned long address)
-{
- pte_t oldpte = *ptep;
- unsigned long pfn = pte_pfn(oldpte);
- pte_t pte = pfn_pte(pfn, vma->vm_page_prot);
- pte.val = (pte.val & ~_PAGE_ALL) | (oldpte.val & _PAGE_ALL);
- pte = hv_pte_clear_nc(pte_donemigrate(pte));
- pte = pte_set_home(pte, page_home(page));
- set_pte_at(vma->vm_mm, address, ptep, pte);
-}
-
-/*
- * Change the homing of a mapped page, flushing any stale PTEs.
- * The page must be locked on entry.
- */
-static void homecache_home_mapped_page(struct page *page, int order,
- int new_home)
-{
- int pages = 1 << order;
- int length = pages * PAGE_SIZE;
- void *vaddr;
- int cleared_home = 0;
- int ttu_flags = TTU_IGNORE_MLOCK | TTU_IGNORE_ACCESS;
- unsigned long pfn = page_to_pfn(page);
- unsigned long flags;
- struct cpumask home_mask;
-
- /* Check some requirements. */
- BUG_ON(!PageLocked(page));
- BUG_ON(PageHomecacheNomigrate(page));
-
- /* Check if we need to do anything. */
- if (page_home(page) == new_home)
- return;
-
- homecache_proc_migrated_mapped += pages;
-
- /*
- * Get the set of cpus we need to flush the cache on.
- * No need to flush the cache of the cpu that will be the new home.
- * This is obvious in the normal case of transitioning from a
- * read-only, non-homed page that was widely cached to a coherently
- * cached page, and we'll claim it makes sense for incoherent pages
- * too: the new coherence point gets to be the "master" in that case.
- */
- homecache_mask(page, pages, &home_mask);
- if (new_home >= 0) {
- BUG_ON(new_home >= NR_CPUS);
- cleared_home = cpumask_test_cpu(new_home, &home_mask);
- if (cleared_home)
- cpumask_clear_cpu(new_home, &home_mask);
- }
-
- /*
- * Now, find all the places where this PTE used to be set,
- * mark them all as migrating, and flush the page out of
- * TLB in all the mm's that are referencing the page,
- * and out of the kernel lowmem or kmap area (if any).
- * We flip anonymous PTEs to "migrating" (resetting them below),
- * but just clear file PTEs outright.
- */
- if (pages == 1) {
- int rc = try_to_unmap(page, ttu_flags | TTU_HOMECACHE_START);
- BUG_ON(!PageAnon(page) && rc != SWAP_SUCCESS);
- }
-
- /*
- * Lock out any new kmaps so no new kernel PTEs can be created until
- * we have finished migration; this also disables interrupts
- * while the spinlock is held, to avoid self-deadlock.
- */
- flags = homecache_kpte_lock();
- vaddr = (void *)homecache_fix_kpte(page, pages, 0);
- if (vaddr) {
- flush_remote(0, 0, NULL,
- (HV_VirtAddr) vaddr, pages * PAGE_SIZE, PAGE_SIZE,
- cpu_online_mask, NULL, 0);
- }
-
- /*
- * Flush the caches, since no cpu can touch the caches that we
- * are migrating away from now.
- */
- flush_remote(pfn, cache_flush_length(length), &home_mask,
- 0, 0, 0, NULL, NULL, 0);
-
- /* We expect dirty cache lines if "cleared_home" is true. */
- if (!cleared_home)
- validate_lines_evicted(pfn, length);
-
- /* Mark the pages with their new cache info. */
- set_pages_home(page, pages, new_home);
-
- /* Release the kpte lock since new kmaps can be created now. */
- homecache_kpte_unlock(flags);
-
- /* Make any anonymous user PTEs assume their correct value. */
- if (PageAnon(page) && pages == 1)
- try_to_unmap(page, ttu_flags | TTU_HOMECACHE_FINISH);
-
- /* Fix the kernel PTE. */
- homecache_fix_kpte(page, pages, 1);
-}
-
-/*
- * This method checks the given home against the passed pgprot (and
- * whether we intend to write to it) and returns an appropriate new home.
- */
-static int homecache_get_desired_home(int home, pgprot_t prot, int writable)
-{
- if (home == PAGE_HOME_IMMUTABLE) {
- /*
- * Immutable pages are treated specially. If we are
- * writing to them, we convert them to normal pages
- * following the pgprot. Otherwise, we do nothing,
- * since any pgprot is compatible with an immutable page.
- */
- if (!writable)
- return home;
- home = default_page_home();
- }
-
- /* If the pgprot isn't intended to force the mapping, we're done. */
- if (!pte_get_forcecache(prot))
- return home;
-
- switch (hv_pte_get_mode(prot)) {
- case HV_PTE_MODE_UNCACHED:
- home = PAGE_HOME_UNCACHED;
- break;
- case HV_PTE_MODE_CACHE_NO_L3:
- /*
- * If we are just caching locally, we must be
- * either incoherent or immutable. Tolerate a
- * read-only mapping of incoherent memory.
- */
- if (home != PAGE_HOME_INCOHERENT)
- home = writable ? PAGE_HOME_INCOHERENT :
- PAGE_HOME_IMMUTABLE;
- break;
- case HV_PTE_MODE_CACHE_TILE_L3:
- /* Set the page home if requested by the pgprot. */
- if (!pte_get_anyhome(prot)) {
- /*
- * Get requested CPU. Note that users can't
- * mmap() with a hypervisor lotar, so if one were
- * in the pgprot, we would correctly assert
- * in get_remote_cache_cpu().
- */
- home = get_remote_cache_cpu(prot);
- } else {
- /* A lotar with anyhome is confused. */
- BUG_ON(hv_pte_get_lotar(prot));
- if (home < 0)
- home = smp_processor_id();
- }
- /* Writable pages can't be immutable. */
- if (!writable && hv_pte_get_nc(prot))
- home = PAGE_HOME_IMMUTABLE;
- break;
-#if CHIP_HAS_CBOX_HOME_MAP()
- case HV_PTE_MODE_CACHE_HASH_L3:
- home = PAGE_HOME_HASH;
- BUG_ON(hv_pte_get_lotar(prot) != 0);
- /* Writable pages can't be immutable. */
- if (!writable && hv_pte_get_nc(prot))
- home = PAGE_HOME_IMMUTABLE;
- break;
-#endif
- default:
- panic("Invalid mode in pte %#llx", hv_pte_val(prot));
- break;
- }
- return home;
-}
-
-void homecache_home_page_here(struct page *page, int order, pgprot_t prot)
-{
- int home = page_home(page);
-
- /*
- * If this pgprot forces the page to be homed somewhere specific,
- * just return and don't try to move it around.
- */
- if (home != PAGE_HOME_IMMUTABLE &&
- pte_get_forcecache(prot) &&
- (hv_pte_get_mode(prot) == HV_PTE_MODE_UNCACHED ||
- hv_pte_get_mode(prot) == HV_PTE_MODE_CACHE_NO_L3 ||
-#if CHIP_HAS_CBOX_HOME_MAP()
- hv_pte_get_mode(prot) == HV_PTE_MODE_CACHE_HASH_L3 ||
-#endif
- !pte_get_anyhome(prot)))
- return;
-
- /* Make sure the page is actually homed on a single cpu. */
- if (home < 0 && home != PAGE_HOME_IMMUTABLE)
- return;
-
- /* Change this page to be coherently cached on this cpu. */
- home = homecache_get_desired_home(default_page_home(), prot, 1);
-
- /* Re-home the page. */
- homecache_home_mapped_page(page, order, home);
-}
-
-void homecache_update_page(struct page *page, int order,
- struct vm_area_struct *vma, int writable)
-{
- int home = page_home(page);
- pgprot_t prot = vma->vm_page_prot;
-
- /*
- * If there is already a shared writable mapping for this file, it
- * will own the caching of its pages, so just return early.
- *
- * FIXME: walk through the vmas with vma_prio_tree_foreach()
- * and if we overlap with a shared one, force its homing here,
- * and if not, use our requested homing. This would also give
- * us better granularity, since there might be a non-overlapping
- * shared-writable mapping that this mapping could then ignore.
- */
- if (!(vma->vm_flags & VM_SHARED) &&
- vma->vm_file && vma->vm_file->f_mapping->i_mmap_writable > 0)
- return;
-
- /*
- * If we are setting up a shared writable mapping, we may not
- * come into this path via an actual write, but we still want
- * to set up the mapping as writable.
- */
- if (hv_pte_get_writable(prot))
- writable = 1;
-
- /*
- * If the access is for read, and the mapping is private,
- * and the page is from a file and is not shared writably,
- * we ignore "prot" and make it immutable instead.
- *
- * If noallocl2 is set, we never cache pages locally, so
- * there's no point in claiming they are immutable.
- */
- if (!writable && !(vma->vm_flags & VM_SHARED) && !noallocl2 &&
- vma->vm_file && vma->vm_file->f_mapping->i_mmap_writable == 0) {
- home = PAGE_HOME_IMMUTABLE;
- } else {
- home = homecache_get_desired_home(home, prot, writable);
- }
-
- homecache_home_mapped_page(page, order, home);
-}
-
-void homecache_make_writable(struct page *page, int order)
-{
- int home = page_home(page);
- if (home == PAGE_HOME_IMMUTABLE) {
- home = homecache_get_desired_home(home, PAGE_KERNEL, 1);
- homecache_home_mapped_page(page, order, home);
- }
-}
-
-void homecache_new_user_page(struct page *page, int order,
- pgprot_t prot, int writable)
-{
- int home = page_home(page);
-
-
- home = homecache_get_desired_home(home, prot, writable);
- homecache_home_unmapped_page(page, order, home, 0);
-}
-
-
-/* Information needed to migrate user-space PTEs. */
-struct migrating_pte {
- pte_t pteval; /* copy of PTE (with migrating bit set) */
- spinlock_t *ptl; /* non-NULL if this entry locked the PTE */
- pmd_t *pmd; /* PMD that this pte is on */
- unsigned long va; /* address for this PTE */
- struct page *page_lock; /* non-NULL if this entry locked the page */
-};
-
-/*
- * State for the migration algorithm that is passed among processes.
- * This structure is always placed at the beginning of a dedicated page.
- */
-struct migrate_state {
- cpumask_t cache_cpumask; /* cpus to flush cache on */
- cpumask_t tlb_cpumask; /* cpus to flush TLB on */
- int num_rem_asids; /* remote ASID count */
- HV_Remote_ASID rem_asids[NR_CPUS]; /* remote ASIDs */
- unsigned long low_kaddr, high_kaddr; /* bounds of kaddrs to flush */
- int migrating_index; /* next entry in migrating[] */
- struct migrating_pte migrating[]; /* PTEs we are migrating */
- /* Note that the migrating[] array extends to the end of the page. */
-};
-
-/* Number of entries we can put in the migrate_state.migrating[] array. */
-#define MIGRATING_COUNT \
- ((PAGE_SIZE - sizeof(struct migrate_state)) / sizeof(struct migrating_pte))
-
-/* Add information for a new migrating_pte to the list. */
-static void add_migrating_pte(struct migrate_state *ms, pte_t pteval,
- spinlock_t *ptl, pmd_t *pmd, unsigned long va,
- struct page *page_lock)
-{
- struct migrating_pte *mpte;
- BUG_ON(ms->migrating_index >= MIGRATING_COUNT);
- mpte = &ms->migrating[ms->migrating_index++];
- mpte->pteval = pteval;
- mpte->ptl = ptl;
- mpte->pmd = pmd;
- mpte->va = va;
- mpte->page_lock = page_lock;
-}
-
-/* Check to see if we're already locked a given page. */
-static int is_page_locked(struct migrate_state *ms, struct page *page)
-{
- int i, count = ms->migrating_index;
- for (i = 0; i < count; ++i)
- if (ms->migrating[i].page_lock == page)
- return 1;
- return 0;
-}
-
-/* Check to see if we're already locked a given page table lock. */
-static int is_page_table_locked(struct migrate_state *ms, spinlock_t *ptl)
-{
- int i, count = ms->migrating_index;
- for (i = 0; i < count; ++i)
- if (ms->migrating[i].ptl == ptl)
- return 1;
- return 0;
-}
-
-/*
- * Add information on a region of kernel VAs that we need to flush.
- * Right now we end up just passing a single (start,size) argument to
- * the hypervisor, but we structure it as an API here so that we
- * can use a modified hypervisor API more easily at a later date.
- */
-static void add_kaddr_flush(struct migrate_state *ms,
- unsigned long kaddr, unsigned long size)
-{
- unsigned long end = kaddr + size;
- if (kaddr < ms->low_kaddr)
- ms->low_kaddr = kaddr;
- if (end > ms->high_kaddr)
- ms->high_kaddr = end;
-}
-
-/*
- * Get a PTE pointer for a small or huge page in the current process
- * from a PMD and address. Note that this relies on the tile
- * architecture using the same format for PTEs and PGDs (and thus PMDs).
- */
-static pte_t *map_pte(pmd_t *pmd, unsigned long address)
-{
- if (pmd_huge_page(*pmd))
- return (pte_t *) pmd;
- else
- return pte_offset_map(pmd, address);
-}
-
-/* Unmap a small or huge PTE (only necessary for small PTEs). */
-static inline void unmap_pte(pmd_t *pmd, pte_t *ptep)
-{
- if (!pmd_huge_page(*pmd))
- pte_unmap(ptep);
-}
-
-/*
- * Set the migrating bit on the page and PTE (and any kernel PTE),
- * and update the TLB flush info and cache flush info in the migrate_state.
- * Return the pteval that we should expect to find when we finish migrating.
- */
-static pte_t migrate_start_page(struct migrate_state *ms,
- pte_t *ptep, struct page *page,
- unsigned long va)
-{
- pte_t pteval = *ptep;
-
- /*
- * Rewrite the PTE as migrating so any attempt to use it will
- * cause a hang. We use ptep_get_and_clear() to avoid racing
- * with the hypervisor's dirty/accessed bit setting. Note that
- * there is a brief window of vulnerability where the pte is
- * zero-valued, but this is true elsewhere too, e.g. mprotect.
- */
- pteval = pte_mkmigrate(ptep_get_and_clear(current->mm, va, ptep));
- set_pte_at(current->mm, va, ptep, pteval);
-
- /* Record that we need to flush the old cpu's cache. */
- cpumask_set_cpu(page_home(page), &ms->cache_cpumask);
-
- return pteval;
-}
-
-/* Poison any kernel PTEs for the page and track any TLB flushes. */
-static void migrate_start_kpte(struct migrate_state *ms,
- struct migrating_pte *mpte)
-{
- pte_t pteval = mpte->pteval;
- struct page *page = pfn_to_page(pte_pfn(pteval));
- int npages = pte_huge(pteval) ? (1 << HUGETLB_PAGE_ORDER) : 1;
- unsigned long kva = homecache_fix_kpte(page, npages, 0);
- if (kva != 0)
- add_kaddr_flush(ms, kva, npages * PAGE_SIZE);
-}
-
-/* Adjust the page so it is ready to go with its new cpu home. */
-static void migrate_finish_page(struct migrating_pte *mpte)
-{
- pte_t pteval = mpte->pteval;
- struct page *page = pfn_to_page(pte_pfn(pteval));
- int cpu = smp_processor_id();
- int npages = pte_huge(pteval) ? (1 << HUGETLB_PAGE_ORDER) : 1;
- int i;
-
- /* Fix the page attributes. */
- for (i = 0; i < npages; i++)
- set_page_home(&page[i], cpu);
-}
-
-/*
- * Adjust the pte(s) so they are ready to go with their new cpu home.
- * On exit, any cpus that were spinning in page fault are now
- * released, get the updated pte and reset their TLBs appropriately.
- */
-static void migrate_finish_pte(struct migrating_pte *mpte)
-{
- pmd_t *pmd = mpte->pmd;
- pte_t pteval = mpte->pteval;
- struct page *page = pfn_to_page(pte_pfn(pteval));
- pte_t *ptep;
- int cpu = smp_processor_id();
- int npages = pte_huge(pteval) ? (1 << HUGETLB_PAGE_ORDER) : 1;
-
- /* Adjust the user PTE. */
- ptep = map_pte(pmd, mpte->va);
- pteval = pte_donemigrate(set_remote_cache_cpu(pteval, cpu));
- set_pte_at(current->mm, mpte->va, ptep, pteval);
- unmap_pte(pmd, ptep);
-
- /* Adjust any kernel PTEs referencing this page. */
- homecache_fix_kpte(page, npages, 1);
-}
-
-/*
- * Given a PTE, inspect it to see if it's one we can migrate; if
- * so, return a pointer to the page so we can try to lock it.
- */
-static struct page *pte_to_migratable_page(pte_t pteval)
-{
- struct page *page;
- int home;
-
- if (!pte_present(pteval))
- return NULL;
-
- /* Only migrate pages that are coherently cached on a single cpu. */
- if (hv_pte_get_mode(pteval) != HV_PTE_MODE_CACHE_TILE_L3 ||
- hv_pte_get_nc(pteval))
- return NULL;
-
- /* Sanity-check the PTE against the page info. */
- page = pfn_to_page(pte_pfn(pteval));
- home = page_home(page);
- if (home != get_remote_cache_cpu(pteval))
- panic("Candidate PTE %#llx (home %d) has PFN %#lx (home %d)",
- pteval.val, get_remote_cache_cpu(pteval),
- pte_pfn(pteval), home);
-
- /* If we're already homed on this cpu, no need to migrate! */
- if (home == smp_processor_id())
- return NULL;
-
- /* If the cpu is not one the hypervisor can cache-flush, skip it. */
- BUG_ON(home < 0 || home >= NR_CPUS);
- if (!cpu_cacheable(home))
- return NULL;
-
- return page;
-}
-
-/* Check that the page is one that we want to migrate. */
-static int page_migrates_with_process(pte_t pteval, struct page *page)
-{
- int mapcount;
-
- /*
- * If the page is mapped into multiple mm's, we don't migrate
- * it, since we don't provide try_to_unmap() functionality.
- *
- * NOTE: This also excludes pages that are mapped twice into
- * the same mm, but this is a rare case, so we don't worry.
- * We actually do support migrating a page mapped more than once
- * (see the is_page_locked() calls in maybe_migrate(), below)
- * so if we do need to do this later it may not be that hard.
- */
- if (pte_huge(pteval)) {
- /*
- * Mapcount apparently isn't tracked, but we know a huge
- * page always has a count for each mapping.
- */
- BUG_ON(page_mapcount(page) != 0);
- mapcount = page_count(page);
- } else {
- mapcount = page_mapcount(page);
- }
- BUG_ON(mapcount <= 0);
- if (mapcount != 1)
- return 0;
-
- /* Unlikely to map one of these, but might as well check. */
- if (PageHomecacheNomigrate(page))
- return 0;
-
- return 1;
-}
-
-/*
- * We enter with a candidate VA and a flag indicating whether we should
- * use "trylock" instead of lock, and no locks held (other than the
- * mmap_sem held for read). We return 0 if things went OK, and 1 if
- * we were in "trylock" mode and failed to acquire a lock.
- *
- * First we validate that the PTE is plausible, and return early if not.
- * Then we try to get a lock on the page, and then map and lock the page
- * table. This is a bit tricky because we have to lock the page before
- * the page table to respect the ordering in mm/rmap.c. This means we
- * get a tentative page from the pte, then lock it, lock the page table,
- * and validate the PTE. If the PTE has changed (perhaps because
- * another thread upgraded a zero-page ref to writable while we were
- * working) we try again until the PTE value is stable. Once we have a
- * stable, migratable PTE, we call migrate_start_page() on it, and return.
- *
- * Prior to taking any page or page table locks, we scan the list of
- * locks we are currently holding to avoid double-taking any locks.
- * Note that this means that if we already have a page table lock for
- * some page, we will end up trying to take the page lock after the page
- * table lock, in violation of the rmap.c ordering; but since at that
- * point we must already be in trylock mode, and have already made some
- * progress, it doesn't matter.
- *
- * Note that we must have interrupts enabled during this routine
- * since we are acquiring the page lock and the page table lock.
- */
-static int maybe_migrate(struct migrate_state *ms,
- unsigned long va, int try_lock)
-{
- pte_t *ptep;
- pte_t pteval;
- spinlock_t *ptl; /* page table lock for "va" */
- struct page *page;
- struct mm_struct *mm = current->mm;
- int took_page_lock, took_page_table_lock;
-
- /* Map in the PTE. */
- pmd_t *pmd = pmd_offset(pud_offset(pgd_offset(mm, va), va), va);
- pmd_t pmdval = *pmd;
- if (!pmd_present(pmdval))
- return 0;
- ptep = map_pte(pmd, va);
-
- /*
- * Lock the page table (unless we locked it for a previous page).
- * We have to do this so it's safe to examine the PTE's page struct.
- */
- took_page_table_lock = 0;
- if (pmd_huge_page(pmdval))
- ptl = &mm->page_table_lock;
- else
- ptl = pte_lockptr(mm, pmd);
- if (!is_page_table_locked(ms, ptl)) {
- if (!spin_trylock(ptl)) {
- if (try_lock) {
- unmap_pte(pmd, ptep);
- return 1;
- }
- spin_lock(ptl);
- }
- took_page_table_lock = 1;
- }
-
- retry:
- /* See if we are interested in this PTE. */
- pteval = *ptep;
- page = pte_to_migratable_page(pteval);
- if (page == NULL || !page_migrates_with_process(pteval, page)) {
- if (took_page_table_lock)
- spin_unlock(ptl);
- unmap_pte(pmd, ptep);
- return 0;
- }
-
- /* Now try to take the page lock. */
- took_page_lock = 0;
- if (!is_page_locked(ms, page)) {
- if (TestSetPageLocked(page)) {
- if (try_lock) {
- if (took_page_table_lock)
- spin_unlock(ptl);
- unmap_pte(pmd, ptep);
- return 1;
- }
-
- /*
- * This is the first page we're trying to acquire,
- * so we have to take the page lock first to avoid
- * deadlock with (e.g.) the swapper. But this
- * means we have to drop the existing page table
- * lock, which means we have to bump up the
- * reference count on the page beforehand, so we
- * can still validly look at it when we try to lock
- * it. Then we have to check the PTE to make sure
- * it didn't change while we had the PTL dropped.
- */
- BUG_ON(!took_page_table_lock);
- get_page(page);
- spin_unlock(ptl);
- lock_page(page);
- spin_lock(ptl);
- if (unlikely(!pte_same(*ptep, pteval))) {
- unlock_page(page);
- put_page(page);
- goto retry;
- }
-
- /*
- * Drop the extra refcount; we don't need it since
- * we will leave the PTL locked from now on.
- */
- put_page(page);
- }
-
- /* Now that we have the lock, recheck the page. */
- if (!page_migrates_with_process(pteval, page)) {
- unlock_page(page);
- if (took_page_table_lock)
- spin_unlock(ptl);
- unmap_pte(pmd, ptep);
- return 0;
- }
-
- took_page_lock = 1;
- }
-
- /* Mark the page for migrating and unmap the PTE. */
- pteval = migrate_start_page(ms, ptep, page, va);
- unmap_pte(pmd, ptep);
-
- /* Record what we migrated and what locks we took out. */
- if (!took_page_lock)
- page = NULL;
- if (!took_page_table_lock)
- ptl = NULL;
- add_migrating_pte(ms, pteval, ptl, pmd, va, page);
- if (page)
- ++homecache_proc_migrated_mapped;
-
- return 0;
-}
-
-/*
- * Walk the user pages and try to start migrating the ones that need
- * it. We enter holding the mmap_sem for read. We return 0 if we
- * were able to migrate every page we were interested in, and the VA
- * to restart at if we need to complete this migration pass and then
- * try again. On exit, the passed migrate_state structure is updated
- * with the list of user PTEs chosen to migrate, and the kernel VA
- * range is updated with any kernel addresses that have to be
- * explicitly flushed.
- *
- * Marking all the pages for migrating is tricky since we have to
- * worry about ABBA deadlock. If we've already locked some pages and
- * marked them as migrating, then try to lock a new page or a page
- * table, it's possible that some other thread already holds that
- * lock, but is blocked trying to lock, or create a PTE for, a page
- * that we have already started to migrate. This would be a deadlock,
- * but instead maybe_migrate() bails out (returning a non-zero start
- * va), we short-circuit this routine, complete the whole migration
- * pass for the pages we've already marked for migration, then loop
- * back in homecache_migrate() and retry. This way we allow the other
- * task to make forward progress, thus allowing us to eventually be
- * able to acquire the lock that we need as well.
- */
-static unsigned long migrate_start_user(struct migrate_state *ms,
- unsigned long start_va)
-{
- struct task_struct *p = current;
- struct mm_struct *mm = p->mm;
- int is_threaded = (atomic_read(&mm->mm_users) > 1);
- pid_t mypid = current->pid;
- unsigned long usp0 = p->thread.usp0;
- struct vm_area_struct *vm;
-
- /* Walk user pages and discover which should be migrated. */
- for (vm = mm->mmap; vm != NULL; vm = vm->vm_next) {
- unsigned long va;
- int page_size = (vm->vm_flags & VM_HUGETLB) ?
- HPAGE_SIZE : PAGE_SIZE;
-
- /* Handle MAP_CACHE_HOME_TASK regions. */
- if (vm->vm_pid != 0) {
- /* Skip regions owned by another task. */
- if (vm->vm_pid != mypid)
- continue;
-
- /* Update vm_page_prot for subsequent faults. */
- vm->vm_page_prot = (pgprot_t)
- set_remote_cache_cpu((pte_t)(vm->vm_page_prot),
- smp_processor_id());
- } else {
- /* Don't try to migrate regions with explicit homes */
- if (pte_get_forcecache(vm->vm_page_prot) &&
- !pte_get_anyhome(vm->vm_page_prot))
- continue;
-
- /* If threaded, we only migrate the stack. */
- if (is_threaded &&
- (usp0 < vm->vm_start || usp0 >= vm->vm_end))
- continue;
- }
-
- /* Walk each page in the region. */
- va = vm->vm_start > start_va ? vm->vm_start : start_va;
- for (; va < vm->vm_end; va += page_size) {
- int try_lock;
-
- /* If we can't store any more PTE info, retry. */
- if (ms->migrating_index >= MIGRATING_COUNT)
- return va;
-
- /*
- * Check this address to see if it needs to
- * migrate. If we've already marked page(s) for
- * migration, use "trylock" to avoid deadlock.
- * If we get a trylock failure notification,
- * give up and indicate we should retry.
- */
- try_lock = (ms->migrating_index != 0);
- if (maybe_migrate(ms, va, try_lock) != 0)
- return va;
- }
- }
-
- return 0;
-}
-
-/*
- * Kernel tasks only migrate their stack, at most. So for kernel
- * tasks, we run a minimal version of homecache_trymigrate(), which
- * doesn't involve allocating any memory. This is convenient if we
- * are low on memory.
- */
-void homecache_migrate_kthread(void)
-{
- /*
- * We require a single-page stack for now since our assembly
- * helper only supports one PTE. See also similar code in
- * homecache_trymigrate().
- */
-#if THREAD_SIZE > PAGE_SIZE
-# error Add some code
-#endif
- struct thread_info *ti = current_thread_info();
- struct task_struct *p = current;
- unsigned long stack_va = (unsigned long) p->stack;
- unsigned long stack_pfn = kaddr_to_pfn((void *)stack_va);
- pte_t *stack_ptep = virt_to_pte(NULL, stack_va);
- pte_t stack_pte = *stack_ptep;
- struct page *stack_page = pfn_to_page(stack_pfn);
- int stack_home = page_home(stack_page);
- const struct cpumask *stack_cachemask;
- struct cpumask *stack_tlbmask;
- int cpu = smp_processor_id();
- int rc, timestamp;
-
- /* Set the homecache_cpu to reflect that we have migrated. */
- ti->homecache_cpu = cpu;
-
- /* See if we actually need to do anything. */
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (unlikely(stack_home == PAGE_HOME_HASH)) {
- /*
- * Possible only for the boot idle task during init
- * before we move it to a properly-homed stack.
- */
- return;
- }
-#endif
- if (unlikely(stack_home == cpu))
- return;
-
- BUG_ON(stack_home != pte_to_home(stack_pte));
- BUG_ON(stack_home < 0 || stack_home > NR_CPUS);
- stack_cachemask = &cpumask_of_cpu(stack_home);
- stack_pte = set_remote_cache_cpu(stack_pte, cpu);
- BUILD_BUG_ON(sizeof(p->thread.homecache_tlb_flush) !=
- sizeof(cpu_online_map));
- stack_tlbmask = (cpumask_t *) p->thread.homecache_tlb_flush;
- memcpy(stack_tlbmask, cpu_online_map.bits, sizeof(cpu_online_map));
- hv_flush_update(stack_cachemask, stack_tlbmask,
- stack_va, THREAD_SIZE, NULL, 0);
- timestamp = mark_caches_evicted_start();
- rc = homecache_migrate_stack_and_flush(stack_pte, stack_va,
- THREAD_SIZE, stack_ptep,
- stack_cachemask, stack_tlbmask,
- NULL, 0);
- BUG_ON(rc != 0);
- mark_caches_evicted_finish(stack_cachemask, timestamp);
- set_page_home(stack_page, cpu);
- homecache_proc_migrated_mapped++;
- homecache_proc_migrated_tasks++;
-}
-
-/*
- * Migrate the caching of the current task's pages to its new cpu.
- * Return 0 if we completed successfully, otherwise the VA we should
- * restart at if we faced possible deadlock and gave up part way through.
- * The first invocation must be passed start_va as "0", because this
- * indicates the invocation that will migrate the kernel stack as well.
- */
-static unsigned long homecache_trymigrate(unsigned long start_va)
-{
- struct task_struct *p = current;
- struct migrate_state *ms;
- struct page *stack_page;
- pte_t *stack_ptep;
- pte_t stack_pte;
- int stack_home;
- int cpu = smp_processor_id();
- unsigned long end_va;
- unsigned long flags;
- int rc, i, other_cpu;
- int migrate_stack;
- int timestamp;
-
- /*
- * For vfork'ed children, just return immediately; the parent
- * still owns the pages, so we don't want to move any of them.
- */
- if (p->vfork_done != NULL)
- return 0;
-
- /*
- * Allocate a page that isn't being migrated to store state
- * that we can't pass in registers to our helper routine.
- * The migrate_state structure is sized to a full page to
- * avoid having to bail out of homecache_trymigrate early.
- */
- ms = (struct migrate_state *)__get_free_page(__GFP_NOWARN|GFP_KERNEL);
- if (ms == NULL) {
- printk("%s/%d: out of memory: not migrating to cpu %d\n",
- current->comm, current->pid, cpu);
- return 0;
- }
-
- /* Initialize the migrating_state */
- cpumask_clear(&ms->cache_cpumask);
- cpumask_clear(&ms->tlb_cpumask);
- ms->num_rem_asids = 0;
- ms->migrating_index = 0;
- ms->high_kaddr = 0;
- ms->low_kaddr = -1UL;
-
- /*
- * This should only ever be called just before returning
- * a task to user-space, but be paranoid and check.
- */
- BUG_ON(in_interrupt());
-
- /* Mark user PTEs for migration. */
- down_read(&p->mm->mmap_sem);
- end_va = migrate_start_user(ms, start_va);
- up_read(&p->mm->mmap_sem);
-
- if (ms->migrating_index == 0) {
-#if CHIP_HAS_CBOX_HOME_MAP()
- /*
- * In kstack_hash mode, we won't migrate any
- * kernel pages, and if we didn't find any
- * user pages to migrate either, we're done.
- */
- if (kstack_hash)
- goto done;
-#endif
- } else {
- /*
- * Construct the cpu/ASID vector to flush,
- * based on what other threads are sharing
- * this mm. Once we have real ASID support we
- * will probably have something like a
- * cpu/ASID vector in the mm. For now, we
- * just construct one manually.
- */
- for_each_cpu_mask(other_cpu, p->mm->cpu_vm_mask) {
- int index = ms->num_rem_asids++;
- HV_Remote_ASID *rem_asid =
- &ms->rem_asids[index];
- rem_asid->x = other_cpu % smp_width;
- rem_asid->y = other_cpu / smp_width;
- rem_asid->asid =
- per_cpu(current_asid, other_cpu);
- }
- }
-
- /*
- * On our first pass, mark kernel stack for migration.
- * For kstack_hash, the kernel stack is hash-for-home,
- * so we never migrate it.
- */
-#if CHIP_HAS_CBOX_HOME_MAP()
- if (kstack_hash)
- migrate_stack = 0;
- else
-#endif
- migrate_stack = (start_va == 0);
-
- if (migrate_stack) {
- /* See comments above in homecache_migrate_kthread(). */
- unsigned long stack_va = (unsigned long)(p->stack);
- unsigned long stack_pfn = kaddr_to_pfn(p->stack);
- stack_ptep = virt_to_pte(NULL, stack_va);
- stack_pte = *stack_ptep;
- stack_page = pfn_to_page(stack_pfn);
- stack_home = page_home(stack_page);
- BUG_ON(stack_home != pte_to_home(stack_pte));
- if (unlikely(stack_home == cpu)) {
- migrate_stack = 0;
- } else {
- cpumask_set_cpu(stack_home, &ms->cache_cpumask);
- stack_pte = set_remote_cache_cpu(stack_pte, cpu);
- homecache_proc_migrated_mapped++;
- add_kaddr_flush(ms, stack_va, THREAD_SIZE);
- }
- } else {
- /* Provide something for the assembly helper to scribble on. */
- stack_ptep = &stack_pte;
- __pte_clear(stack_ptep); /* avoid uninitialized data */
- }
-
- /*
- * Take out the kpte lock, and disable interrupts, to avoid
- * any new kernel PTEs being created while we run this code.
- * Then poison any kernel ptes. Note that we do this after
- * migrate_start_page(), in case we need kmaps for HIGHPTE.
- * Also note that we need interrupts disabled around the call
- * to homecache_migrate_stack_and_flush(), if migrate_stack is true,
- * since we are them marking this task's own stack as migrating.
- */
- flags = homecache_kpte_lock();
- for (i = 0; i < ms->migrating_index; ++i)
- migrate_start_kpte(ms, &ms->migrating[i]);
-
- /*
- * Call homecache_migrate_stack_and_flush() to ensure the pages that
- * we're migrating are flushed from all TLBs and caches,
- * then finally write the revised stack_pte to *stack_ptep.
- */
- if (ms->low_kaddr > ms->high_kaddr) {
- ms->low_kaddr = 0;
- ms->high_kaddr = 0;
- } else {
- cpumask_copy(&ms->tlb_cpumask, cpu_online_mask);
- }
- hv_flush_update(&ms->cache_cpumask, &ms->tlb_cpumask,
- ms->low_kaddr,
- ms->high_kaddr - ms->low_kaddr,
- ms->rem_asids,
- ms->num_rem_asids);
- timestamp = mark_caches_evicted_start();
- rc = homecache_migrate_stack_and_flush(stack_pte, ms->low_kaddr,
- ms->high_kaddr - ms->low_kaddr,
- stack_ptep, &ms->cache_cpumask,
- &ms->tlb_cpumask, ms->rem_asids,
- ms->num_rem_asids);
- if (rc != 0)
- panic("homecache_migrate_stack_and_flush: %d", rc);
- mark_caches_evicted_finish(&ms->cache_cpumask, timestamp);
-
- if (migrate_stack)
- set_page_home(stack_page, cpu);
-
- /* Mark all the page structures as finished migrating. */
- for (i = 0; i < ms->migrating_index; ++i)
- migrate_finish_page(&ms->migrating[i]);
-
- /*
- * Release the kpte lock, now that we can safely create new kmaps.
- * In particular note that we need the kpte lock released so we
- * can map in user PTEs to update them (if enabled by HIGHPTE).
- */
- homecache_kpte_unlock(flags);
-
- /*
- * Finish migrating. We loop in reverse
- * order since that way we release any shared locks
- * after all the PTEs that referenced them.
- */
- for (i = ms->migrating_index - 1; i >= 0; --i) {
- struct migrating_pte *mpte = &ms->migrating[i];
-
- /* Validate that we really evicted the page. */
- unsigned long pfn = pte_pfn(mpte->pteval);
- int length = pte_huge(mpte->pteval) ?
- HPAGE_SIZE : PAGE_SIZE;
- validate_lines_evicted(pfn, length);
-
- /* Write the new PTE (and kernel PTE). */
- migrate_finish_pte(mpte);
-
- /* Unlock the page and the page table, if necessary. */
- if (mpte->page_lock)
- unlock_page(mpte->page_lock);
- if (mpte->ptl)
- spin_unlock(mpte->ptl);
- }
-
- done:
- free_page((unsigned long)ms);
- return end_va;
-}
-
-/*
- * The migration locks essentially require only one task at a time to
- * migrate away from any given cpu. This avoids clobbering the source
- * cpu with multiple simultaneous cpu and TLB flushes. In practice we
- * find that forking many processes and immediately setting their
- * affinity to other cpus runs noticeably faster with this approach.
- */
-static struct mutex migration_lock[NR_CPUS];
-
-static int __init init_migration_locks(void)
-{
- int i;
- for (i = 0; i < NR_CPUS; ++i)
- mutex_init(&migration_lock[i]);
- return 1;
-}
-arch_initcall(init_migration_locks);
-
-
-/*
- * Called to migrate the home cache of any pages associated with the
- * task if the cpu has changed and we are resuming back to userspace.
- */
-void homecache_migrate(void)
-{
- struct thread_info *ti;
- unsigned long start_va, next_va;
- int cpu, old_cpu;
-
- /* kthreadd takes this path, so redirect it to kernel task path. */
- if (current->mm == NULL) {
- homecache_migrate_kthread();
- return;
- }
-
- /*
- * Check and set homecache_cpu with interrupts disabled,
- * to avoid potential re-entrancy bugs after any interrupts.
- */
- BUG_ON(!irqs_disabled());
- cpu = smp_processor_id();
- ti = current_thread_info();
- old_cpu = ti->homecache_cpu;
- BUG_ON(cpu == old_cpu);
- ti->homecache_cpu = cpu;
-
- /*
- * Disable preemption but enable interrupts; we need
- * interrupts enabled throughout the actual migration process,
- * in particular so we can handle IPIs to avoid deadlocks
- * while we are trying to acquire page table locks.
- */
- preempt_disable();
- local_irq_enable();
- mutex_lock(&migration_lock[old_cpu]);
- homecache_proc_migrated_tasks++;
-
- /*
- * If we hit a potential deadlock (a page or page table locked
- * while we had other pages marked for migration) we just
- * complete migrating the pages we were holding, then go back
- * and rescan and try to pick up some more pages.
- */
- start_va = 0;
- while ((next_va = homecache_trymigrate(start_va)) != 0) {
- BUG_ON(next_va <= start_va);
- start_va = next_va;
- }
-
- mutex_unlock(&migration_lock[old_cpu]);
- local_irq_disable();
- preempt_enable();
-
- if (unlikely(current->ptrace & PT_TRACE_MIGRATE)) {
- current->ptrace_message = cpu;
- ptrace_notify((PTRACE_EVENT_MIGRATE << 8) | SIGTRAP);
- }
-}
-
-static ctl_table homecache_table[] = {
- {
- .procname = "migrated_tasks",
- .data = &homecache_proc_migrated_tasks,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "migrated_mapped_pages",
- .data = &homecache_proc_migrated_mapped,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "migrated_unmapped_pages",
- .data = &homecache_proc_migrated_unmapped,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "sequestered_pages_at_free",
- .data = &homecache_proc_sequestered_free,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "sequestered_pages_at_alloc",
- .data = &homecache_proc_sequestered_alloc,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {
- .procname = "sequestered_purges",
- .data = &homecache_proc_sequestered_purge,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = &proc_dointvec
- },
- {}
-};
-
-static ctl_table tile_table[] = {
- {
- .procname = "homecache",
- .mode = 0555,
- .child = homecache_table,
- },
- {0, },
-};
-
-static ctl_table root[] = {
- {
- .procname = "tile",
- .child = tile_table,
- },
- {0, },
-};
-
-static int __init homecache_proc_init(void)
-{
- register_sysctl_table(root);
- return 0;
-}
-subsys_initcall(homecache_proc_init);
-
-#endif /* CONFIG_HOMECACHE */
diff -ru tile.old/mm/init.c tile/mm/init.c
--- tile.old/mm/init.c 2010-05-28 18:03:33.980675000 -0400
+++ tile/mm/init.c 2010-05-28 22:57:15.239079000 -0400
@@ -141,24 +141,24 @@
BUG();
}

+#ifdef __tilegx__

+#if HV_L1_SIZE != HV_L2_SIZE
+# error Rework assumption that L1 and L2 page tables are same size.
+#endif

+/* Since pmd_t arrays and pte_t arrays are the same size, just use casts. */
+static inline pmd_t *alloc_pmd(void)
+{
+ return (pmd_t *)alloc_pte();
+}

+static inline void assign_pmd(pud_t *pud, pmd_t *pmd)
+{
+ assign_pte((pmd_t *)pud, (pte_t *)pmd);
+}

-
-
-
-
-
-
-
-
-
-
-
-
-
-
+#endif /* __tilegx__ */

/* Replace the given pmd with a full PTE table. */
void __init shatter_pmd(pmd_t *pmd)
@@ -206,113 +206,7 @@
static int __initdata kdata_hash = 1; /* .data and .bss pages */
int __write_once hash_default = 1; /* kernel allocator pages */
EXPORT_SYMBOL(hash_default);
-#ifndef CONFIG_HOMECACHE
int __write_once kstack_hash = 1; /* if no homecaching, use h4h */
-#else
-int __write_once kstack_hash; /* kernel stacks */
-
-/*
- * This function is the primary driver for caching modes set up
- * for kernel text and data. The "ktext" and "kdata" boot options
- * are relevant only if we are using page-at-a-time caching modes.
- */
-static int __init setup_kcache_hash(char *str)
-{
- if (str == NULL)
- return -EINVAL;
-
- if (strcmp(str, "all") == 0) {
- ktext_hash = 1;
- kdata_hash = 1;
- hash_default = 1;
- kstack_hash = 1;
- } else if (strcmp(str, "allbutstack") == 0) {
- ktext_hash = 1;
- kdata_hash = 1;
- hash_default = 1;
- kstack_hash = 0;
- } else if (strcmp(str, "static") == 0) {
- ktext_hash = 1;
- kdata_hash = 1;
- hash_default = 0;
- kstack_hash = 0;
- } else if (strcmp(str, "ro") == 0) {
- ktext_hash = 1;
- kdata_hash = 0;
- hash_default = 0;
- kstack_hash = 0;
- } else if (strcmp(str, "none") == 0) {
- ktext_hash = 0;
- kdata_hash = 0;
- hash_default = 0;
- kstack_hash = 0;
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-early_param("kcache_hash", setup_kcache_hash);
-
-static int __init set_hash_default(char *str)
-{
- hash_default = 1;
- printk("Warning: \"hash_default\" is obsolete and now the default\n.");
- return 0;
-}
-early_param("hash_default", set_hash_default);
-
-/* From init/main.c */
-extern char *envp_init[CONFIG_INIT_ENV_ARG_LIMIT+2];
-
-static int __init set_ld_cache_hash(const char* env)
-{
- int i;
-
- for (i = 0; envp_init[i]; i++) {
- BUG_ON(i == CONFIG_INIT_ENV_ARG_LIMIT);
- if (!strncmp(MAP_CACHE_HASH_ENV_VAR "=", envp_init[i],
- sizeof(MAP_CACHE_HASH_ENV_VAR))) {
- return 0;
- }
- }
- if (i == CONFIG_INIT_ENV_ARG_LIMIT) {
- printk("Warning: can't set default " MAP_CACHE_HASH_ENV_VAR
- " since the boot env limit has been reached.\n");
- } else {
- envp_init[i] = (char *)env;
- }
- return 0;
-}
-
-/*
- * This is hacky, but less so than the alternatives. We want to make
- * sure we map in the init process suitably, which means we want to
- * have LD_CACHE_HASH set in the initial environment.
- */
-static int __init ld_cache_hash_init(void)
-{
- return set_ld_cache_hash(MAP_CACHE_HASH_ENV_VAR "=allbutstack");
-}
-late_initcall(ld_cache_hash_init);
-
-/*
- * This is a combo function that both has the effect of kcache_hash
- * and also sets LD_CACHE_HASH to the specified value.
- */
-static int __init setup_cache_hash(char *str)
-{
- static char env[64] = MAP_CACHE_HASH_ENV_VAR "=";
- if (str == NULL)
- return -EINVAL;
- set_ld_cache_hash(strcat(env, str));
- return setup_kcache_hash(str);
-}
-
-early_param("cache_hash", setup_cache_hash);
-
-#endif /* CONFIG_HOMECACHE */
#endif /* CHIP_HAS_CBOX_HOME_MAP */

/*
@@ -324,48 +218,7 @@
static __initdata struct cpumask kdata_mask;
static __initdata int kdata_arg_seen;

-#ifndef CONFIG_HOMECACHE
int __write_once kdata_huge; /* if no homecaching, small pages */
-#else
-int __write_once kdata_huge = CHIP_HAS_CBOX_HOME_MAP(); /* kernel huge pages */
-
-static int __init setup_kdata(char *str)
-{
- char buf[NR_CPUS * 5];
-
- if (str == NULL)
- return -EINVAL;
-
- if (strcmp(str, "huge") == 0) {
-#if CHIP_HAS_CBOX_HOME_MAP()
- kdata_huge = 1;
-#else
- printk("kdata=huge: only supported on TILEPro and later.\n");
-#endif
- return 0;
- }
-
- if (strcmp(str, "small") == 0) {
- kdata_huge = 0;
- str += strlen("small");
- if (*str == ',')
- ++str;
- if (*str == '\0')
- return 0;
- }
-
- if (cpulist_parse(str, &kdata_mask) != 0)
- return -EINVAL;
-
- kdata_arg_seen = 1;
- cpulist_scnprintf(buf, sizeof(buf), &kdata_mask);
- printk("kdata: using caching neighborhood %s\n", buf);
- return 0;
-}
-
-early_param("kdata", setup_kdata);
-
-#endif /* CONFIG_HOMECACHE */


/* Combine a generic pgprot_t with cache home to get a cache-aware pgprot. */
@@ -400,7 +253,7 @@
#endif

/* We map the aliased pages of permanent text inaccessible. */
- if (address < (ulong) __init_text_begin - CODE_DELTA)
+ if (address < (ulong) _sinittext - CODE_DELTA)
return PAGE_NONE;

/*
@@ -418,20 +271,20 @@
address < (ulong)&init_thread_union + THREAD_SIZE)
return construct_pgprot(PAGE_KERNEL, smp_processor_id());

-
+#ifndef __tilegx__
#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
/* Force the atomic_locks[] array page to be hash-for-home. */
if (address == (ulong) atomic_locks)
return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
#endif
-
+#endif

/*
* Everything else that isn't data or bss is heap, so mark it
* with the initial heap home (hash-for-home, or this cpu). This
* includes any addresses after the loaded image; any address before
- * __init_text_end (since we already captured the case of text before
- * __init_text_begin); and any init-data pages.
+ * _einittext (since we already captured the case of text before
+ * _sinittext); and any init-data pages.
*
* All the LOWMEM pages that we mark this way will get their
* struct page homecache properly marked later, in set_page_homes().
@@ -440,8 +293,8 @@
* do a flush action the first time we use them, either.
*/
if (address >= (ulong) _end || address < (ulong) _sdata ||
- (address >= (ulong) __init_data_begin &&
- address < (ulong) __init_data_end))
+ (address >= (ulong) _sinitdata &&
+ address < (ulong) _einitdata))
return construct_pgprot(PAGE_KERNEL, initial_heap_home());

#if CHIP_HAS_CBOX_HOME_MAP()
@@ -457,7 +310,7 @@
* the requested address, while walking cpu home around kdata_mask.
* This is typically no more than a dozen or so iterations.
*/
- BUG_ON(__init_data_end != __bss_start);
+ BUG_ON(_einitdata != __bss_start);
for (page = (ulong)_sdata, cpu = NR_CPUS; ; ) {
cpu = cpumask_next(cpu, &kdata_mask);
if (cpu == NR_CPUS)
@@ -469,16 +322,16 @@
page = (ulong)__end_rodata;
if (page == (ulong)&init_thread_union)
page += THREAD_SIZE;
- if (page == (ulong)__init_data_begin)
- page = (ulong)__init_data_end;
+ if (page == (ulong)_sinitdata)
+ page = (ulong)_einitdata;
if (page == (ulong)empty_zero_page)
page += PAGE_SIZE;
-
+#ifndef __tilegx__
#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
if (page == (ulong)atomic_locks)
page += PAGE_SIZE;
#endif
-
+#endif

}
return construct_pgprot(PAGE_KERNEL, cpu);
@@ -537,14 +390,6 @@
printk("ktext: using maximal caching neighborhood\n");
}

-#ifdef CONFIG_DATAPLANE
- /* Neighborhood cache ktext pages on all non-dataplane cpus. */
- else if (strcmp(str, "nondataplane") == 0) {
- ktext_small = 1;
- ktext_nondataplane = 1;
- printk("ktext: caching on all non-dataplane tiles\n");
- }
-#endif

/* Neighborhood ktext pages on specified mask */
else if (cpulist_parse(str, &ktext_mask) == 0) {
@@ -580,24 +425,24 @@
return prot;
}

-
+#ifndef __tilegx__
static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
{
return pmd_offset(pud_offset(&pgtables[pgd_index(va)], va), va);
}
-
-
-
-
-
-
-
-
-
+#else
+static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
+{
+ pud_t *pud = pud_offset(&pgtables[pgd_index(va)], va);
+ if (pud_none(*pud))
+ assign_pmd(pud, alloc_pmd());
+ return pmd_offset(pud, va);
+}
+#endif

/* Temporary page table we use for staging. */
static pgd_t pgtables[PTRS_PER_PGD]
- __attribute__((section(".init.data.page_aligned")));
+ __attribute__((section(".init.page")));

/*
* This maps the physical memory to kernel virtual address space, a total
@@ -649,11 +494,6 @@
* the whole chip too.
*/
cpumask_copy(&kstripe_mask, cpu_possible_mask);
-#ifdef CONFIG_DATAPLANE
- cpumask_andnot(&kstripe_mask, &kstripe_mask, &dataplane_map);
- if (cpumask_empty(&kstripe_mask))
- cpumask_copy(&kstripe_mask, cpu_possible_mask);
-#endif
if (!kdata_arg_seen)
kdata_mask = kstripe_mask;

@@ -752,7 +592,7 @@
BUG_ON(address != (unsigned long)_stext);
pfn = 0; /* code starts at PA 0 */
pte = alloc_pte();
- for (pte_ofs = 0; address < (unsigned long)_etext;
+ for (pte_ofs = 0; address < (unsigned long)_einittext;
pfn++, pte_ofs++, address += PAGE_SIZE) {
if (!ktext_local) {
prot = set_remote_cache_cpu(prot, cpu);
@@ -829,9 +669,9 @@
{
return pagenr < kaddr_to_pfn(_end) &&
!(pagenr >= kaddr_to_pfn(&init_thread_union) ||
- pagenr < kaddr_to_pfn(__init_data_end)) &&
- !(pagenr >= kaddr_to_pfn(__init_text_begin) ||
- pagenr < kaddr_to_pfn(__init_text_end));
+ pagenr < kaddr_to_pfn(_einitdata)) &&
+ !(pagenr >= kaddr_to_pfn(_sinittext) ||
+ pagenr <= kaddr_to_pfn(_einittext-1));
}

#ifdef CONFIG_HIGHMEM
@@ -936,9 +776,9 @@
#ifdef CONFIG_HIGHMEM
unsigned long vaddr, end;
#endif
-
-
-
+#ifdef __tilegx__
+ pud_t *pud;
+#endif
pgd_t *pgd_base = swapper_pg_dir;

kernel_physical_mapping_init(pgd_base);
@@ -954,34 +794,20 @@
permanent_kmaps_init(pgd_base);
#endif

-
-
-
-
-
-
-
-
-
-
-
-
-}
-
-#ifdef CONFIG_HOMECACHE
-/* Return the PAGE_HOME_xxx value based on the kernel PTE. */
-static int get_page_home(pte_t pte)
-{
- if (!hv_pte_get_writable(pte))
- return PAGE_HOME_IMMUTABLE;
-#if CHIP_HAS_CBOX_HOME_MAP()
- else if (hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_HASH_L3)
- return PAGE_HOME_HASH;
+#ifdef __tilegx__
+ /*
+ * Since GX allocates just one pmd_t array worth of vmalloc space,
+ * we go ahead and allocate it statically here, then share it
+ * globally. As a result we don't have to worry about any task
+ * changing init_mm once we get up and running, and there's no
+ * need for e.g. vmalloc_sync_all().
+ */
+ BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END));
+ pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START);
+ assign_pmd(pud, alloc_pmd());
#endif
- else
- return get_remote_cache_cpu(pte);
}
-#endif
+

/*
* Walk the kernel page tables and derive the page_home() from
@@ -990,40 +816,6 @@
*/
void __init set_page_homes(void)
{
-#ifdef CONFIG_HOMECACHE
- struct zone *zone;
- int home = initial_heap_home();
- unsigned long address;
-
- /*
- * First walk the zones and set the pages to all have
- * the default heap caching.
- */
- for_each_zone(zone) {
- unsigned long pfn = zone->zone_start_pfn;
- unsigned long end_pfn = pfn + zone->spanned_pages;
- struct page *page = pfn_to_page(pfn);
- for (; pfn < end_pfn; ++pfn, ++page)
- set_page_home(page, home);
- }
-
- /*
- * Now walk through the loaded pages, update the page homecache,
- * and mark all pages as non-migrateable. (Init pages that
- * are freed back to the heap are unmarked when we free them.)
- */
- for (address = PAGE_OFFSET; address < (unsigned long) _end;
- address += PAGE_SIZE) {
- enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET };
- struct page *pg = virt_to_page((void *)address);
- pte_t pte = *virt_to_pte(NULL, address);
-
- /* Adjust page.home on all loaded pages. */
- BUG_ON(!pte_present(pte));
- set_page_home(pg, get_page_home(pte));
- __SetPageHomecacheNomigrate(pg);
- }
-#endif
}

static void __init set_max_mapnr_init(void)
@@ -1037,9 +829,9 @@
{
int codesize, datasize, initsize;
int i;
-
+#ifndef __tilegx__
void *last;
-
+#endif

#ifdef CONFIG_FLATMEM
if (!mem_map)
@@ -1066,16 +858,10 @@
/* count all remaining LOWMEM and give all HIGHMEM to page allocator */
set_non_bootmem_pages_init();

- codesize = (unsigned long) &__init_text_begin -
- (unsigned long) &_text;
- initsize = (unsigned long) &__init_text_end -
- (unsigned long) &__init_text_begin;
- datasize = (unsigned long) &__init_data_begin -
- (unsigned long) &_sdata;
- initsize += (unsigned long) &__init_data_end -
- (unsigned long) &__init_data_begin;
- datasize += (unsigned long) &_end -
- (unsigned long) &__bss_start;
+ codesize = (unsigned long)&_etext - (unsigned long)&_text;
+ datasize = (unsigned long)&_end - (unsigned long)&_sdata;
+ initsize = (unsigned long)&_einittext - (unsigned long)&_sinittext;
+ initsize += (unsigned long)&_einitdata - (unsigned long)&_sinitdata;

printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
@@ -1095,23 +881,25 @@
printk(KERN_DEBUG " PKMAP %#lx - %#lx\n",
PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP) - 1);
#endif
+#ifdef CONFIG_HUGEVMAP
printk(KERN_DEBUG " HUGEMAP %#lx - %#lx\n",
HUGE_VMAP_BASE, HUGE_VMAP_END - 1);
+#endif
printk(KERN_DEBUG " VMALLOC %#lx - %#lx\n",
_VMALLOC_START, _VMALLOC_END - 1);
-
-
-
-
-
-
-
-
-
-
-
-
-
+#ifdef __tilegx__
+ for (i = MAX_NUMNODES-1; i >= 0; --i) {
+ struct pglist_data *node = &node_data[i];
+ if (node->node_present_pages) {
+ unsigned long start = (unsigned long)
+ pfn_to_kaddr(node->node_start_pfn);
+ unsigned long end = start +
+ (node->node_present_pages << PAGE_SHIFT);
+ printk(KERN_DEBUG " MEM%d %#lx - %#lx\n",
+ i, start, end - 1);
+ }
+ }
+#else
last = high_memory;
for (i = MAX_NUMNODES-1; i >= 0; --i) {
if ((unsigned long)vbase_map[i] != -1UL) {
@@ -1121,15 +909,15 @@
last = vbase_map[i];
}
}
+#endif

-
-
+#ifndef __tilegx__
/*
* Convert from using one lock for all atomic operations to
* one per cpu.
*/
__init_atomic_per_cpu();
-
+#endif
}

/*
@@ -1178,15 +966,11 @@
/* Loop over page table entries */
unsigned long addr = (unsigned long)__w1data_begin;
BUG_ON((addr & (PAGE_SIZE-1)) != 0);
- BUG_ON((((unsigned long)__w1data_end) & (PAGE_SIZE-1)) != 0);
- for (; addr < (unsigned long)__w1data_end; addr += PAGE_SIZE) {
+ for (; addr <= (unsigned long)__w1data_end - 1; addr += PAGE_SIZE) {
unsigned long pfn = kaddr_to_pfn((void *)addr);
struct page *page = pfn_to_page(pfn);
pte_t *ptep = virt_to_pte(NULL, addr);
BUG_ON(pte_huge(*ptep)); /* not relevant for kdata_huge */
-#ifdef CONFIG_HOMECACHE
- set_page_home(page, PAGE_HOME_IMMUTABLE);
-#endif
set_pte_at(&init_mm, addr, ptep, pfn_pte(pfn, PAGE_KERNEL_RO));
}
}
@@ -1209,9 +993,6 @@

static void free_init_pages(char *what, unsigned long begin, unsigned long end)
{
-#ifdef CONFIG_HOMECACHE
- int home = initial_heap_home();
-#endif
unsigned long addr = (unsigned long) begin;

if (kdata_huge && !initfree) {
@@ -1219,6 +1000,7 @@
" incompatible with kdata=huge\n");
initfree = 1;
}
+ end = (end + PAGE_SIZE - 1) & PAGE_MASK;
local_flush_tlb_pages(NULL, begin, PAGE_SIZE, end - begin);
for (addr = begin; addr < end; addr += PAGE_SIZE) {
/*
@@ -1240,10 +1022,6 @@
pte_clear(&init_mm, addr, ptep);
continue;
}
-#ifdef CONFIG_HOMECACHE
- set_page_home(page, home);
- __clear_bit(PG_homecache_nomigrate, &page->flags);
-#endif
__ClearPageReserved(page);
init_page_count(page);
if (pte_huge(*ptep))
@@ -1274,16 +1052,16 @@

/* Free the data pages that we won't use again after init. */
free_init_pages("unused kernel data",
- (unsigned long)__init_data_begin,
- (unsigned long)__init_data_end);
+ (unsigned long)_sinitdata,
+ (unsigned long)_einitdata);

/*
* Free the pages mapped from 0xc0000000 that correspond to code
* pages from 0xfd000000 that we won't use again after init.
*/
free_init_pages("unused kernel text",
- (unsigned long)__init_text_begin - text_delta,
- (unsigned long)__init_text_end - text_delta);
+ (unsigned long)_sinittext - text_delta,
+ (unsigned long)_einittext - text_delta);

#if !CHIP_HAS_COHERENT_LOCAL_CACHE()
/*
diff -ru tile.old/mm/migrate_32.S tile/mm/migrate_32.S
--- tile.old/mm/migrate_32.S 2010-05-28 18:03:34.021619000 -0400
+++ tile/mm/migrate_32.S 2010-05-28 22:57:15.246070000 -0400
@@ -43,208 +43,6 @@
#define FRAME_SIZE 32


-#ifdef CONFIG_HOMECACHE
-/*
- * On entry:
- *
- * r0 low word of the new stack PTE to use (moved to r_stack_pte_lo)
- * r1 high word of the new stack PTE to use (moved to r_stack_pte_hi)
- * r2 low virtual address
- * r3 length of virtual address range
- * r4 pointer to stack PTE to use (moved to r_stack_ptep)
- * r5 cache cpumask pointer
- * r6 tlb cpumask pointer
- * r7 HV_Remote_ASID array pointer
- * r8 HV_Remote_ASID count
- */
-
-/* Arguments (caller-save) */
-#define r_stack_pte_lo_in r0
-#define r_stack_pte_hi_in r1
-#define r_va r2
-#define r_length r3
-#define r_stack_ptep_in r4
-#define r_cache_cpumask_in r5
-#define r_tlb_cpumask r6
-#define r_rem_asids r7
-#define r_num_rem_asids r8
-
-/* Locals (callee-save); must not be more than FRAME_xxx above. */
-#define r_save_ics r30
-#define r_cache_cpumask r31
-#define r_stack_ptep r32
-#define r_stack_pte_lo r33
-#define r_stack_pte_hi r34
-
-STD_ENTRY(homecache_migrate_stack_and_flush)
-
- /*
- * Create a stack frame; we can't touch it once we set the
- * migrating bit on the stack PTE until we clear it at the end.
- */
- {
- move r_save_sp, sp
- sw sp, lr
- addi sp, sp, -FRAME_SIZE
- }
- addi r_tmp, sp, FRAME_SP
- {
- sw r_tmp, r_save_sp
- addi r_tmp, sp, FRAME_R30
- }
- {
- sw r_tmp, r30
- addi r_tmp, sp, FRAME_R31
- }
- {
- sw r_tmp, r31
- addi r_tmp, sp, FRAME_R32
- }
- {
- sw r_tmp, r32
- addi r_tmp, sp, FRAME_R33
- }
- {
- sw r_tmp, r33
- addi r_tmp, sp, FRAME_R34
- }
- sw r_tmp, r34
-
- /* Move some arguments to callee-save registers. */
- {
- move r_cache_cpumask, r_cache_cpumask_in
- move r_stack_ptep, r_stack_ptep_in
- }
- {
- move r_stack_pte_lo, r_stack_pte_lo_in
- move r_stack_pte_hi, r_stack_pte_hi_in
- }
-
- /* Make sure our stack writes have reached the remote cache. */
- mf
-
- /* Disable interrupts, since we can't use our stack. */
- {
- mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
- movei r_tmp, 1
- }
- mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
-
- /* Clear the present bit and set the migrating bit on the stack. */
-#if HV_PTE_INDEX_MIGRATING >= 32 || HV_PTE_INDEX_PRESENT >= 32
-# error Fix code that assumes the present and migrating bits are in low word
-#endif
- lw r_tmp, r_stack_ptep
- andi r_tmp, r_tmp, ~HV_PTE_PRESENT
- ori r_tmp, r_tmp, HV_PTE_MIGRATING
- sw r_stack_ptep, r_tmp
- mf
-
- /*
- * Now we do a global TLB flush:
- *
- * hv_flush_remote(0ULL, 0, NULL,
- * va, length, PAGE_SIZE, tlb_cpumask,
- * rem_asids, num_rem_asids);
- *
- */
- {
- move r9, r_num_rem_asids
- move r8, r_rem_asids
- }
- {
- move r7, r_tlb_cpumask
- moveli r6, lo16(PAGE_SIZE)
- }
- {
- auli r6, r6, ha16(PAGE_SIZE)
- move r5, r_length
- }
- {
- move r4, r_va
- move r3, zero
- }
- {
- move r2, zero
- move r1, zero
- }
- {
- move r0, zero
- jal hv_flush_remote
- }
- bnz r0, .Lwrite_stack_pte
-
- /*
- * And now a cache flush on the old cpus:
- *
- * hv_flush_remote(0ULL, HV_FLUSH_EVICT_L2, cache_cpumask,
- * NULL, 0, 0, 0, NULL, 0)
- *
- */
- {
- move r0, zero
- move r1, zero
- }
- {
- auli r2, zero, ha16(HV_FLUSH_EVICT_L2)
- move r3, r_cache_cpumask
- }
- {
- move r4, zero
- move r5, zero
- }
- {
- move r6, zero
- move r7, zero
- }
- {
- move r8, zero
- move r9, zero
- }
- jal hv_flush_remote
-
-.Lwrite_stack_pte:
- /* Finally, write the new stack PTE. */
-#if HV_PTE_INDEX_MIGRATING >= 32
-# error Fix code that assumes we should unmigrate by writing high word first
-#endif
- addi r_tmp, r_stack_ptep, 4
- sw r_tmp, r_stack_pte_hi
- sw r_stack_ptep, r_stack_pte_lo
- mf
-
- /* Reset interrupts back how they were before. */
- mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
-
- /* Restore the callee-saved registers and return. */
- addli lr, sp, FRAME_SIZE
- {
- lw lr, lr
- addli r_tmp, sp, FRAME_R30
- }
- {
- lw r30, r_tmp
- addli r_tmp, sp, FRAME_R31
- }
- {
- lw r31, r_tmp
- addli r_tmp, sp, FRAME_R32
- }
- {
- lw r32, r_tmp
- addli r_tmp, sp, FRAME_R33
- }
- {
- lw r33, r_tmp
- addli r_tmp, sp, FRAME_R34
- }
- {
- lw r34, r_tmp
- addi sp, sp, FRAME_SIZE
- }
- jrp lr
- STD_ENDPROC(homecache_migrate_stack_and_flush)
-#endif


/*
diff -ru tile.old/mm/mmap.c tile/mm/mmap.c
--- tile.old/mm/mmap.c 2010-05-28 18:03:34.031602000 -0400
+++ tile/mm/mmap.c 2010-05-28 22:57:15.270036000 -0400
@@ -51,13 +51,13 @@
*/
void arch_pick_mmap_layout(struct mm_struct *mm)
{
-
+#if !defined(__tilegx__)
int is_32bit = 1;
-
-
-
-
-
+#elif defined(CONFIG_COMPAT)
+ int is_32bit = is_compat_task();
+#else
+ int is_32bit = 0;
+#endif

/*
* Use standard layout if the expected stack growth is unlimited
diff -ru tile.old/mm/pgtable.c tile/mm/pgtable.c
--- tile.old/mm/pgtable.c 2010-05-28 18:03:34.033601000 -0400
+++ tile/mm/pgtable.c 2010-05-28 22:57:15.268041000 -0400
@@ -212,14 +212,14 @@
memset(pgd, 0, KERNEL_PGD_INDEX_START*sizeof(pgd_t));
spin_lock_irqsave(&pgd_lock, flags);

-
+#ifndef __tilegx__
/*
* Check that the user interrupt vector has no L2.
* It never should for the swapper, and new page tables
* should always start with an empty user interrupt vector.
*/
BUG_ON(((u64 *)swapper_pg_dir)[pgd_index(MEM_USER_INTRPT)] != 0);
-
+#endif

clone_pgd_range(pgd + KERNEL_PGD_INDEX_START,
swapper_pg_dir + KERNEL_PGD_INDEX_START,
@@ -304,7 +304,7 @@
}
}

-
+#ifndef __tilegx__

/*
* FIXME: needs to be atomic vs hypervisor writes. For now we make the
@@ -339,7 +339,7 @@
tmp[1] = tmp[1] & ~(1 << (HV_PTE_INDEX_WRITABLE - 32));
}

-
+#endif

pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr)
{
@@ -391,9 +391,9 @@
/* Update the home of a PTE if necessary */
pte = pte_set_home(pte, page_home(page));

-
-
-
+#ifdef __tilegx__
+ *ptep = pte;
+#else
/*
* When setting a PTE, write the high bits first, then write
* the low bits. This sets the "present" bit only after the
@@ -411,7 +411,7 @@
((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32);
barrier();
((u32 *)ptep)[0] = (u32)(pte_val(pte));
-
+#endif
}

/* Can this mm load a PTE with cached_priority set? */
Only in tile.old: oprofile
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/