diff options
Diffstat (limited to 'arch')
183 files changed, 5593 insertions, 3469 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 620f2ca94ed..8752751f998 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -223,7 +223,9 @@ source "arch/arm/mach-pxa/Kconfig" source "arch/arm/mach-sa1100/Kconfig" -source "arch/arm/mach-omap/Kconfig" +source "arch/arm/plat-omap/Kconfig" + +source "arch/arm/mach-omap1/Kconfig" source "arch/arm/mach-s3c2410/Kconfig" @@ -514,7 +516,7 @@ config XIP_PHYS_ADDR endmenu -if (ARCH_SA1100 || ARCH_INTEGRATOR) +if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP1) menu "CPU Frequency scaling" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index eb933dcafba..67f1453ade0 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -91,7 +91,8 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 machine-$(CONFIG_ARCH_IOP3XX) := iop3xx machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx machine-$(CONFIG_ARCH_IXP2000) := ixp2000 - machine-$(CONFIG_ARCH_OMAP) := omap + machine-$(CONFIG_ARCH_OMAP1) := omap1 + incdir-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_S3C2410) := s3c2410 machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x machine-$(CONFIG_ARCH_VERSATILE) := versatile @@ -142,6 +143,9 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) core-$(CONFIG_VFP) += arch/arm/vfp/ +# If we have a common platform directory, then include it in the build. +core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ + drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/ diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index b8c51ee7f1b..f67ca01b498 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git6 -# Sat Jun 25 00:57:29 2005 +# Linux kernel version: 2.6.13-rc2 +# Thu Jul 7 16:41:21 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -137,6 +137,7 @@ CONFIG_PCI_NAMES=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -345,10 +346,9 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -363,17 +363,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# +# CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -931,4 +922,3 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index 3cfbe2ec29c..5c6c928215d 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git6 -# Sat Jun 25 00:58:38 2005 +# Linux kernel version: 2.6.13-rc2 +# Thu Jul 7 16:49:01 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -138,6 +138,7 @@ CONFIG_PCI_NAMES=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -346,10 +347,9 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -364,17 +364,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# +# CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -932,4 +923,3 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 5c87e8e6969..6dc40f6be0e 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git6 -# Sat Jun 25 00:59:35 2005 +# Linux kernel version: 2.6.13-rc2 +# Thu Jul 7 16:49:08 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -138,6 +138,7 @@ CONFIG_PCI_NAMES=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -346,10 +347,9 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -364,17 +364,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set CONFIG_IP_TCPDIAG=y # CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# +# CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -933,4 +924,3 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index 3cb561a551c..d2bb0b7153f 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git6 -# Sat Jun 25 01:00:27 2005 +# Linux kernel version: 2.6.13-rc2 +# Thu Jul 7 16:49:20 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -138,6 +138,7 @@ CONFIG_PCI_NAMES=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -346,10 +347,9 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -364,17 +364,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# +# CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -932,4 +923,3 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index b1e162f29cb..2d6f960e339 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-git6 -# Sat Jun 25 01:01:18 2005 +# Linux kernel version: 2.6.13-rc2 +# Thu Jul 7 16:49:13 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -138,6 +138,7 @@ CONFIG_PCI_NAMES=y # # CONFIG_SMP is not set # CONFIG_PREEMPT is not set +# CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -346,10 +347,9 @@ CONFIG_PACKET_MMAP=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_FIB_TRIE is not set # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -364,17 +364,8 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_TUNNEL is not set # CONFIG_IP_TCPDIAG is not set # CONFIG_IP_TCPDIAG_IPV6 is not set - -# -# TCP congestion control -# +# CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y -CONFIG_TCP_CONG_WESTWOOD=m -CONFIG_TCP_CONG_HTCP=m -# CONFIG_TCP_CONG_HSTCP is not set -# CONFIG_TCP_CONG_HYBLA is not set -# CONFIG_TCP_CONG_VEGAS is not set -# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -933,4 +924,3 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -# CONFIG_TEXTSEARCH is not set diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig index 4e58d9341bc..24955263b09 100644 --- a/arch/arm/configs/omap_h2_1610_defconfig +++ b/arch/arm/configs/omap_h2_1610_defconfig @@ -1,14 +1,13 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc1-bk2 -# Sun Mar 27 17:52:41 2005 +# Linux kernel version: 2.6.13-rc2 +# Fri Jul 8 04:49:34 2005 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_IOMAP=y # # Code maturity level options @@ -17,6 +16,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -33,8 +33,9 @@ CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -82,10 +83,28 @@ CONFIG_ARCH_OMAP=y # CONFIG_ARCH_VERSATILE is not set # CONFIG_ARCH_IMX is not set # CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_AAEC2000 is not set # # TI OMAP Implementations # +CONFIG_ARCH_OMAP_OTG=y +CONFIG_ARCH_OMAP1=y +# CONFIG_ARCH_OMAP2 is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_RESET_CLOCKS is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +# CONFIG_OMAP_MPU_TIMER is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_32K_TIMER_HZ=128 +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set # # OMAP Core Type @@ -93,7 +112,6 @@ CONFIG_ARCH_OMAP=y # CONFIG_ARCH_OMAP730 is not set # CONFIG_ARCH_OMAP1510 is not set CONFIG_ARCH_OMAP16XX=y -CONFIG_ARCH_OMAP_OTG=y # # OMAP Board Type @@ -101,21 +119,14 @@ CONFIG_ARCH_OMAP_OTG=y # CONFIG_MACH_OMAP_INNOVATOR is not set CONFIG_MACH_OMAP_H2=y # CONFIG_MACH_OMAP_H3 is not set -# CONFIG_MACH_OMAP_H4 is not set # CONFIG_MACH_OMAP_OSK is not set # CONFIG_MACH_OMAP_GENERIC is not set # -# OMAP Feature Selections +# OMAP CPU Speed # -CONFIG_OMAP_MUX=y -# CONFIG_OMAP_MUX_DEBUG is not set -CONFIG_OMAP_MUX_WARNINGS=y -CONFIG_OMAP_MPU_TIMER=y -# CONFIG_OMAP_32K_TIMER is not set -CONFIG_OMAP_LL_DEBUG_UART1=y -# CONFIG_OMAP_LL_DEBUG_UART2 is not set -# CONFIG_OMAP_LL_DEBUG_UART3 is not set +# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set +# CONFIG_OMAP_ARM_216MHZ is not set CONFIG_OMAP_ARM_192MHZ=y # CONFIG_OMAP_ARM_168MHZ is not set # CONFIG_OMAP_ARM_120MHZ is not set @@ -145,6 +156,7 @@ CONFIG_ARM_THUMB=y # # Bus support # +CONFIG_ISA_DMA_API=y # # PCCARD (PCMCIA/CardBus) support @@ -154,7 +166,16 @@ CONFIG_ARM_THUMB=y # # Kernel Features # +# CONFIG_SMP is not set CONFIG_PREEMPT=y +CONFIG_NO_IDLE_HZ=y +# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_LEDS is not set CONFIG_ALIGNMENT_TRAP=y @@ -167,6 +188,22 @@ CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh" # CONFIG_XIP_KERNEL is not set # +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set + +# # Floating point emulation # @@ -202,7 +239,6 @@ CONFIG_PM=y CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set -CONFIG_DEBUG_DRIVER=y # # Memory Technology Devices (MTD) @@ -292,7 +328,6 @@ CONFIG_MTD_CFI_UTIL=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set @@ -327,6 +362,7 @@ CONFIG_SCSI_PROC_FS=y # CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -356,6 +392,7 @@ CONFIG_SCSI_PROC_FS=y # # Fusion MPT device support # +# CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support @@ -375,12 +412,12 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y @@ -395,6 +432,8 @@ CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_TUNNEL is not set CONFIG_IP_TCPDIAG=y # CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -442,6 +481,7 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_SMC91X=y +# CONFIG_DM9000 is not set # # Ethernet (1000 Mbit) @@ -518,7 +558,6 @@ CONFIG_SERIO=y CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_RAW is not set # CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y # # Character devices @@ -567,13 +606,11 @@ CONFIG_WATCHDOG_NOWAYOUT=y # # Ftape, the floppy tape device driver # -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # # TPM devices # -# CONFIG_TCG_TPM is not set # # I2C support @@ -604,7 +641,9 @@ CONFIG_I2C_CHARDEV=y # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set # CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_FSCPOS is not set @@ -620,6 +659,7 @@ CONFIG_I2C_CHARDEV=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set @@ -627,15 +667,21 @@ CONFIG_I2C_CHARDEV=y # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set CONFIG_ISP1301_OMAP=y +CONFIG_TPS65010=y +# CONFIG_SENSORS_MAX6875 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -663,8 +709,10 @@ CONFIG_FB=y # CONFIG_FB_CFB_COPYAREA is not set # CONFIG_FB_CFB_IMAGEBLIT is not set # CONFIG_FB_SOFT_CURSOR is not set +# CONFIG_FB_MACMODES is not set CONFIG_FB_MODE_HELPERS=y # CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -677,11 +725,13 @@ CONFIG_FONTS=y CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y # CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set # CONFIG_FONT_MINI_4x6 is not set # CONFIG_FONT_SUN8x16 is not set # CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set # # Logo configuration @@ -729,14 +779,14 @@ CONFIG_USB_ARCH_HAS_OHCI=y # CONFIG_USB_GADGET=y # CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_SELECTED=y # CONFIG_USB_GADGET_NET2280 is not set # CONFIG_USB_GADGET_PXA2XX is not set # CONFIG_USB_GADGET_GOKU is not set -# CONFIG_USB_GADGET_SA1100 is not set # CONFIG_USB_GADGET_LH7A40X is not set -# CONFIG_USB_GADGET_DUMMY_HCD is not set CONFIG_USB_GADGET_OMAP=y CONFIG_USB_OMAP=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set # CONFIG_USB_GADGET_DUALSPEED is not set # CONFIG_USB_ZERO is not set CONFIG_USB_ETH=y @@ -755,6 +805,7 @@ CONFIG_USB_ETH_RNDIS=y # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set # CONFIG_EXT3_FS is not set # CONFIG_JBD is not set # CONFIG_REISERFS_FS is not set @@ -791,7 +842,6 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437 # CONFIG_PROC_FS=y CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set # CONFIG_TMPFS is not set # CONFIG_HUGETLB_PAGE is not set @@ -828,12 +878,14 @@ CONFIG_CRAMFS=y # CONFIG_NFS_FS=y CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set CONFIG_NFS_V4=y # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_SUNRPC_GSS=y CONFIG_RPCSEC_GSS_KRB5=y @@ -903,24 +955,11 @@ CONFIG_NLS_DEFAULT="iso8859-1" # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y -# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_PREEMPT=y -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y -CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_FS is not set CONFIG_FRAME_POINTER=y -CONFIG_DEBUG_USER=y -# CONFIG_DEBUG_WAITQ is not set -CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_LL=y -# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_USER is not set # # Security options diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index b713c44c6fb..835d450797a 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -41,7 +41,10 @@ extern void fp_enter(void); * This has a special calling convention; it doesn't * modify any of the usual registers, except for LR. */ +#define EXPORT_CRC_ALIAS(sym) __CRC_SYMBOL(sym, "") + #define EXPORT_SYMBOL_ALIAS(sym,orig) \ + EXPORT_CRC_ALIAS(sym) \ const struct kernel_symbol __ksymtab_##sym \ __attribute__((section("__ksymtab"))) = \ { (unsigned long)&orig, #sym }; diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 4b9d841e04c..45b18658499 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -23,7 +23,7 @@ #include <linux/serial.h> #include <linux/tty.h> #include <linux/bitops.h> -#include <linux/serial_core.h> +#include <linux/serial_8250.h> #include <linux/mm.h> #include <asm/types.h> @@ -125,19 +125,6 @@ static struct map_desc ixp2000_io_desc[] __initdata = { } }; -static struct uart_port ixp2000_serial_port = { - .membase = (char *)(IXP2000_UART_VIRT_BASE + 3), - .mapbase = IXP2000_UART_PHYS_BASE + 3, - .irq = IRQ_IXP2000_UART, - .flags = UPF_SKIP_TEST, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = 50000000, - .line = 0, - .type = PORT_XSCALE, - .fifosize = 16 -}; - void __init ixp2000_map_io(void) { extern unsigned int processor_id; @@ -157,12 +144,50 @@ void __init ixp2000_map_io(void) } iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); - early_serial_setup(&ixp2000_serial_port); /* Set slowport to 8-bit mode. */ ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); } + +/************************************************************************* + * Serial port support for IXP2000 + *************************************************************************/ +static struct plat_serial8250_port ixp2000_serial_port[] = { + { + .mapbase = IXP2000_UART_PHYS_BASE, + .membase = (char *)(IXP2000_UART_VIRT_BASE + 3), + .irq = IRQ_IXP2000_UART, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = 50000000, + }, + { }, +}; + +static struct resource ixp2000_uart_resource = { + .start = IXP2000_UART_PHYS_BASE, + .end = IXP2000_UART_PHYS_BASE + 0xffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ixp2000_serial_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = ixp2000_serial_port, + }, + .num_resources = 1, + .resource = &ixp2000_uart_resource, +}; + +void __init ixp2000_uart_init(void) +{ + platform_device_register(&ixp2000_serial_device); +} + + /************************************************************************* * Timer-tick functions for IXP2000 *************************************************************************/ diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index b7ebf3898fc..9aa54de4474 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c @@ -219,6 +219,7 @@ static struct platform_device *enp2611_devices[] __initdata = { static void __init enp2611_init_machine(void) { platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices)); + ixp2000_uart_init(); } diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 5e4380747b5..a43369ad876 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -303,5 +303,6 @@ void __init ixdp2x00_init_machine(void) gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); + ixp2000_uart_init(); } diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index c73588743ee..43447dad165 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c @@ -370,6 +370,7 @@ static void __init ixdp2x01_init_machine(void) ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1); platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices)); + ixp2000_uart_init(); } diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c index aa92e370883..2b544363c07 100644 --- a/arch/arm/mach-ixp4xx/common-pci.c +++ b/arch/arm/mach-ixp4xx/common-pci.c @@ -453,8 +453,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys) local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); res[0].name = "PCI I/O Space"; - res[0].start = 0x00001000; - res[0].end = 0xffff0000; + res[0].start = 0x00000000; + res[0].end = 0x0000ffff; res[0].flags = IORESOURCE_IO; res[1].name = "PCI Memory Space"; diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c index c6335f51907..4ff4393ef0e 100644 --- a/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/arch/arm/mach-ixp4xx/coyote-setup.c @@ -56,21 +56,24 @@ static struct resource coyote_uart_resource = { .flags = IORESOURCE_MEM, }; -static struct plat_serial8250_port coyote_uart_data = { - .mapbase = IXP4XX_UART2_BASE_PHYS, - .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, - .irq = IRQ_IXP4XX_UART2, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = IXP4XX_UART_XTAL, +static struct plat_serial8250_port coyote_uart_data[] = { + { + .mapbase = IXP4XX_UART2_BASE_PHYS, + .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET, + .irq = IRQ_IXP4XX_UART2, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = IXP4XX_UART_XTAL, + }, + { }, }; static struct platform_device coyote_uart = { .name = "serial8250", .id = 0, .dev = { - .platform_data = &coyote_uart_data, + .platform_data = coyote_uart_data, }, .num_resources = 1, .resource = &coyote_uart_resource, @@ -87,10 +90,10 @@ static void __init coyote_init(void) *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0; if (machine_is_ixdpg425()) { - coyote_uart_data.membase = + coyote_uart_data[0].membase = (char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET); - coyote_uart_data.mapbase = IXP4XX_UART1_BASE_PHYS; - coyote_uart_data.irq = IRQ_IXP4XX_UART1; + coyote_uart_data[0].mapbase = IXP4XX_UART1_BASE_PHYS; + coyote_uart_data[0].irq = IRQ_IXP4XX_UART1; } diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index f2e9c0ea050..c2ba759e994 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -95,7 +95,8 @@ static struct plat_serial8250_port ixdp425_uart_data[] = { .iotype = UPIO_MEM, .regshift = 2, .uartclk = IXP4XX_UART_XTAL, - } + }, + { }, }; static struct platform_device ixdp425_uart = { diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig deleted file mode 100644 index 9e42efa66b2..00000000000 --- a/arch/arm/mach-omap/Kconfig +++ /dev/null @@ -1,221 +0,0 @@ -if ARCH_OMAP - -menu "TI OMAP Implementations" - -comment "OMAP Core Type" - -config ARCH_OMAP730 - depends on ARCH_OMAP - bool "OMAP730 Based System" - select ARCH_OMAP_OTG - -config ARCH_OMAP1510 - depends on ARCH_OMAP - default y - bool "OMAP1510 Based System" - -config ARCH_OMAP16XX - depends on ARCH_OMAP - bool "OMAP16XX Based System" - select ARCH_OMAP_OTG - -config ARCH_OMAP_OTG - bool - -comment "OMAP Board Type" - -config MACH_OMAP_INNOVATOR - bool "TI Innovator" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX - help - TI OMAP 1510 or 1610 Innovator board support. Say Y here if you - have such a board. - -config MACH_OMAP_H2 - bool "TI H2 Support" - depends on ARCH_OMAP16XX - help - TI OMAP 1610/1611B H2 board support. Say Y here if you have such - a board. - -config MACH_OMAP_H3 - bool "TI H3 Support" - depends on ARCH_OMAP16XX - help - TI OMAP 1710 H3 board support. Say Y here if you have such - a board. - -config MACH_OMAP_H4 - bool "TI H4 Support" - depends on ARCH_OMAP16XX - help - TI OMAP 1610 H4 board support. Say Y here if you have such - a board. - -config MACH_OMAP_OSK - bool "TI OSK Support" - depends on ARCH_OMAP16XX - help - TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here - if you have such a board. - -config MACH_OMAP_PERSEUS2 - bool "TI Perseus2" - depends on ARCH_OMAP730 - help - Support for TI OMAP 730 Perseus2 board. Say Y here if you have such - a board. - -config MACH_VOICEBLUE - bool "Voiceblue" - depends on ARCH_OMAP1510 - help - Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such - board. - -config MACH_NETSTAR - bool "NetStar" - depends on ARCH_OMAP1510 - help - Support for NetStar PBX. Say Y here if you have such a board. - -config MACH_OMAP_GENERIC - bool "Generic OMAP board" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX - help - Support for generic OMAP-1510, 1610 or 1710 board with - no FPGA. Can be used as template for porting Linux to - custom OMAP boards. Say Y here if you have a custom - board. - -comment "OMAP Feature Selections" - -#config OMAP_BOOT_TAG -# bool "OMAP bootloader information passing" -# depends on ARCH_OMAP -# default n -# help -# Say Y, if you have a bootloader which passes information -# about your board and its peripheral configuration. - -config OMAP_MUX - bool "OMAP multiplexing support" - depends on ARCH_OMAP - default y - help - Pin multiplexing support for OMAP boards. If your bootloader - sets the multiplexing correctly, say N. Otherwise, or if unsure, - say Y. - -config OMAP_MUX_DEBUG - bool "Multiplexing debug output" - depends on OMAP_MUX - default n - help - Makes the multiplexing functions print out a lot of debug info. - This is useful if you want to find out the correct values of the - multiplexing registers. - -config OMAP_MUX_WARNINGS - bool "Warn about pins the bootloader didn't set up" - depends on OMAP_MUX - default y - help - Choose Y here to warn whenever driver initialization logic needs - to change the pin multiplexing setup. When there are no warnings - printed, it's safe to deselect OMAP_MUX for your product. - -choice - prompt "System timer" - default OMAP_MPU_TIMER - -config OMAP_MPU_TIMER - bool "Use mpu timer" - help - Select this option if you want to use the OMAP mpu timer. This - timer provides more intra-tick resolution than the 32KHz timer, - but consumes more power. - -config OMAP_32K_TIMER - bool "Use 32KHz timer" - depends on ARCH_OMAP16XX - help - Select this option if you want to enable the OMAP 32KHz timer. - This timer saves power compared to the OMAP_MPU_TIMER, and has - support for no tick during idle. The 32KHz timer provides less - intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is - currently only available for OMAP-16xx. - -endchoice - -config OMAP_32K_TIMER_HZ - int "Kernel internal timer frequency for 32KHz timer" - range 32 1024 - depends on OMAP_32K_TIMER - default "128" - help - Kernel internal timer frequency should be a divisor of 32768, - such as 64 or 128. - -choice - prompt "Low-level debug console UART" - depends on ARCH_OMAP - default OMAP_LL_DEBUG_UART1 - -config OMAP_LL_DEBUG_UART1 - bool "UART1" - -config OMAP_LL_DEBUG_UART2 - bool "UART2" - -config OMAP_LL_DEBUG_UART3 - bool "UART3" - -endchoice - -config OMAP_ARM_195MHZ - bool "OMAP ARM 195 MHz CPU" - depends on ARCH_OMAP730 - help - Enable 195MHz clock for OMAP CPU. If unsure, say N. - -config OMAP_ARM_192MHZ - bool "OMAP ARM 192 MHz CPU" - depends on ARCH_OMAP16XX - help - Enable 192MHz clock for OMAP CPU. If unsure, say N. - -config OMAP_ARM_182MHZ - bool "OMAP ARM 182 MHz CPU" - depends on ARCH_OMAP730 - help - Enable 182MHz clock for OMAP CPU. If unsure, say N. - -config OMAP_ARM_168MHZ - bool "OMAP ARM 168 MHz CPU" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 - help - Enable 168MHz clock for OMAP CPU. If unsure, say N. - -config OMAP_ARM_120MHZ - bool "OMAP ARM 120 MHz CPU" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 - help - Enable 120MHz clock for OMAP CPU. If unsure, say N. - -config OMAP_ARM_60MHZ - bool "OMAP ARM 60 MHz CPU" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 - default y - help - Enable 60MHz clock for OMAP CPU. If unsure, say Y. - -config OMAP_ARM_30MHZ - bool "OMAP ARM 30 MHz CPU" - depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 - help - Enable 30MHz clock for OMAP CPU. If unsure, say N. - -endmenu - -endif diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile deleted file mode 100644 index 4cafb11d2c0..00000000000 --- a/arch/arm/mach-omap/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# -# Makefile for the linux kernel. -# - -# Common support -obj-y := common.o time.o irq.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o -obj-m := -obj-n := -obj- := -led-y := leds.o - -# Specific board support -obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o -obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o -obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o -obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o -obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o -obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o -obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o -obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o - -# OCPI interconnect support for 1710, 1610 and 5912 -obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o - -# LEDs support -led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o -led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o -led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o -obj-$(CONFIG_LEDS) += $(led-y) - -# Power Management -obj-$(CONFIG_PM) += pm.o sleep.o - -ifeq ($(CONFIG_ARCH_OMAP1510),y) -# Innovator-1510 FPGA -obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o -endif - -# kgdb support -obj-$(CONFIG_KGDB_SERIAL) += kgdb-serial.o diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c deleted file mode 100644 index 265cde48586..00000000000 --- a/arch/arm/mach-omap/common.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * linux/arch/arm/mach-omap/common.c - * - * Code common to all OMAP machines. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/console.h> -#include <linux/serial.h> -#include <linux/tty.h> -#include <linux/serial_8250.h> -#include <linux/serial_reg.h> - -#include <asm/hardware.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/mach/map.h> -#include <asm/hardware/clock.h> -#include <asm/io.h> -#include <asm/mach-types.h> - -#include <asm/arch/board.h> -#include <asm/arch/mux.h> -#include <asm/arch/fpga.h> - -#include "clock.h" - -#define DEBUG 1 - -struct omap_id { - u16 jtag_id; /* Used to determine OMAP type */ - u8 die_rev; /* Processor revision */ - u32 omap_id; /* OMAP revision */ - u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */ -}; - -/* Register values to detect the OMAP version */ -static struct omap_id omap_ids[] __initdata = { - { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, - { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, - { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, - { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000}, - { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000}, - { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00}, - { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00}, - { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, - { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, - { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000}, - { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00}, - { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00}, - { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300}, - { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300}, - { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300}, - { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000}, - { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000}, - { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000}, -}; - -/* - * Get OMAP type from PROD_ID. - * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM. - * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense. - * Undocumented register in TEST BLOCK is used as fallback; This seems to - * work on 1510, 1610 & 1710. The official way hopefully will work in future - * processors. - */ -static u16 __init omap_get_jtag_id(void) -{ - u32 prod_id, omap_id; - - prod_id = omap_readl(OMAP_PRODUCTION_ID_1); - omap_id = omap_readl(OMAP32_ID_1); - - /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ - if (((prod_id >> 20) == 0) || (prod_id == omap_id)) - prod_id = 0; - else - prod_id &= 0xffff; - - if (prod_id) - return prod_id; - - /* Use OMAP32_ID_1 as fallback */ - prod_id = ((omap_id >> 12) & 0xffff); - - return prod_id; -} - -/* - * Get OMAP revision from DIE_REV. - * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID. - * Undocumented register in the TEST BLOCK is used as fallback. - * REVISIT: This does not seem to work on 1510 - */ -static u8 __init omap_get_die_rev(void) -{ - u32 die_rev; - - die_rev = omap_readl(OMAP_DIE_ID_1); - - /* Check for broken OMAP_DIE_ID on early 1710 */ - if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id()) - die_rev = 0; - - die_rev = (die_rev >> 17) & 0xf; - if (die_rev) - return die_rev; - - die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf; - - return die_rev; -} - -static void __init omap_check_revision(void) -{ - int i; - u16 jtag_id; - u8 die_rev; - u32 omap_id; - u8 cpu_type; - - jtag_id = omap_get_jtag_id(); - die_rev = omap_get_die_rev(); - omap_id = omap_readl(OMAP32_ID_0); - -#ifdef DEBUG - printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0)); - printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n", - omap_readl(OMAP_DIE_ID_1), - (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf); - printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0)); - printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n", - omap_readl(OMAP_PRODUCTION_ID_1), - omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff); - printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0)); - printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1)); - printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev); -#endif - - system_serial_high = omap_readl(OMAP_DIE_ID_0); - system_serial_low = omap_readl(OMAP_DIE_ID_1); - - /* First check only the major version in a safe way */ - for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { - if (jtag_id == (omap_ids[i].jtag_id)) { - system_rev = omap_ids[i].type; - break; - } - } - - /* Check if we can find the die revision */ - for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { - if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) { - system_rev = omap_ids[i].type; - break; - } - } - - /* Finally check also the omap_id */ - for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { - if (jtag_id == omap_ids[i].jtag_id - && die_rev == omap_ids[i].die_rev - && omap_id == omap_ids[i].omap_id) { - system_rev = omap_ids[i].type; - break; - } - } - - /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */ - cpu_type = system_rev >> 24; - - switch (cpu_type) { - case 0x07: - system_rev |= 0x07; - break; - case 0x15: - system_rev |= 0x15; - break; - case 0x16: - case 0x17: - system_rev |= 0x16; - break; - case 0x24: - system_rev |= 0x24; - break; - default: - printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type); - } - - printk("OMAP%04x", system_rev >> 16); - if ((system_rev >> 8) & 0xff) - printk("%x", (system_rev >> 8) & 0xff); - printk(" revision %i handled as %02xxx id: %08x%08x\n", - die_rev, system_rev & 0xff, system_serial_low, - system_serial_high); -} - -/* - * ---------------------------------------------------------------------------- - * OMAP I/O mapping - * - * The machine specific code may provide the extra mapping besides the - * default mapping provided here. - * ---------------------------------------------------------------------------- - */ - -static struct map_desc omap_io_desc[] __initdata = { - { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, -}; - -#ifdef CONFIG_ARCH_OMAP730 -static struct map_desc omap730_io_desc[] __initdata = { - { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE }, - { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE }, - { OMAP730_SRAM_BASE, OMAP730_SRAM_START, OMAP730_SRAM_SIZE, MT_DEVICE } -}; -#endif - -#ifdef CONFIG_ARCH_OMAP1510 -static struct map_desc omap1510_io_desc[] __initdata = { - { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE }, - { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE }, - { OMAP1510_SRAM_BASE, OMAP1510_SRAM_START, OMAP1510_SRAM_SIZE, MT_DEVICE } -}; -#endif - -#if defined(CONFIG_ARCH_OMAP16XX) -static struct map_desc omap1610_io_desc[] __initdata = { - { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, - { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, - { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP1610_SRAM_SIZE, MT_DEVICE } -}; - -static struct map_desc omap5912_io_desc[] __initdata = { - { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, - { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, -/* - * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page - * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped. - * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte - * can be used. - */ - { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE } -}; -#endif - -static int initialized = 0; - -static void __init _omap_map_io(void) -{ - initialized = 1; - - /* We have to initialize the IO space mapping before we can run - * cpu_is_omapxxx() macros. */ - iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc)); - omap_check_revision(); - -#ifdef CONFIG_ARCH_OMAP730 - if (cpu_is_omap730()) { - iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc)); - } -#endif -#ifdef CONFIG_ARCH_OMAP1510 - if (cpu_is_omap1510()) { - iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); - } -#endif -#if defined(CONFIG_ARCH_OMAP16XX) - if (cpu_is_omap1610() || cpu_is_omap1710()) { - iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc)); - } - if (cpu_is_omap5912()) { - iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc)); - } -#endif - - /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort - * on a Posted Write in the TIPB Bridge". - */ - omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL); - omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL); - - /* Must init clocks early to assure that timer interrupt works - */ - clk_init(); -} - -/* - * This should only get called from board specific init - */ -void omap_map_io(void) -{ - if (!initialized) - _omap_map_io(); -} - -static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, - int offset) -{ - offset <<= up->regshift; - return (unsigned int)__raw_readb(up->membase + offset); -} - -static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset, - int value) -{ - offset <<= p->regshift; - __raw_writeb(value, p->membase + offset); -} - -/* - * Internal UARTs need to be initialized for the 8250 autoconfig to work - * properly. Note that the TX watermark initialization may not be needed - * once the 8250.c watermark handling code is merged. - */ -static void __init omap_serial_reset(struct plat_serial8250_port *p) -{ - omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */ - omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */ - omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */ - - if (!cpu_is_omap1510()) { - omap_serial_outp(p, UART_OMAP_SYSC, 0x01); - while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01)); - } -} - -static struct plat_serial8250_port serial_platform_data[] = { - { - .membase = (char*)IO_ADDRESS(OMAP_UART1_BASE), - .mapbase = (unsigned long)OMAP_UART1_BASE, - .irq = INT_UART1, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = OMAP16XX_BASE_BAUD * 16, - }, - { - .membase = (char*)IO_ADDRESS(OMAP_UART2_BASE), - .mapbase = (unsigned long)OMAP_UART2_BASE, - .irq = INT_UART2, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = OMAP16XX_BASE_BAUD * 16, - }, - { - .membase = (char*)IO_ADDRESS(OMAP_UART3_BASE), - .mapbase = (unsigned long)OMAP_UART3_BASE, - .irq = INT_UART3, - .flags = UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 2, - .uartclk = OMAP16XX_BASE_BAUD * 16, - }, - { }, -}; - -static struct platform_device serial_device = { - .name = "serial8250", - .id = 0, - .dev = { - .platform_data = serial_platform_data, - }, -}; - -/* - * Note that on Innovator-1510 UART2 pins conflict with USB2. - * By default UART2 does not work on Innovator-1510 if you have - * USB OHCI enabled. To use UART2, you must disable USB2 first. - */ -void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) -{ - int i; - - if (cpu_is_omap730()) { - serial_platform_data[0].regshift = 0; - serial_platform_data[1].regshift = 0; - serial_platform_data[0].irq = INT_730_UART_MODEM_1; - serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2; - } - - if (cpu_is_omap1510()) { - serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16; - serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16; - serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16; - } - - for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { - unsigned char reg; - - if (ports[i] == 0) { - serial_platform_data[i].membase = 0; - serial_platform_data[i].mapbase = 0; - continue; - } - - switch (i) { - case 0: - if (cpu_is_omap1510()) { - omap_cfg_reg(UART1_TX); - omap_cfg_reg(UART1_RTS); - if (machine_is_omap_innovator()) { - reg = fpga_read(OMAP1510_FPGA_POWER); - reg |= OMAP1510_FPGA_PCR_COM1_EN; - fpga_write(reg, OMAP1510_FPGA_POWER); - udelay(10); - } - } - break; - case 1: - if (cpu_is_omap1510()) { - omap_cfg_reg(UART2_TX); - omap_cfg_reg(UART2_RTS); - if (machine_is_omap_innovator()) { - reg = fpga_read(OMAP1510_FPGA_POWER); - reg |= OMAP1510_FPGA_PCR_COM2_EN; - fpga_write(reg, OMAP1510_FPGA_POWER); - udelay(10); - } - } - break; - case 2: - if (cpu_is_omap1510()) { - omap_cfg_reg(UART3_TX); - omap_cfg_reg(UART3_RX); - } - if (cpu_is_omap1710()) { - clk_enable(clk_get(0, "uart3_ck")); - } - break; - } - omap_serial_reset(&serial_platform_data[i]); - } -} - -static int __init omap_init(void) -{ - return platform_device_register(&serial_device); -} -arch_initcall(omap_init); - -#define NO_LENGTH_CHECK 0xffffffff - -extern int omap_bootloader_tag_len; -extern u8 omap_bootloader_tag[]; - -struct omap_board_config_kernel *omap_board_config; -int omap_board_config_size = 0; - -static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out) -{ - struct omap_board_config_kernel *kinfo = NULL; - int i; - -#ifdef CONFIG_OMAP_BOOT_TAG - struct omap_board_config_entry *info = NULL; - - if (omap_bootloader_tag_len > 4) - info = (struct omap_board_config_entry *) omap_bootloader_tag; - while (info != NULL) { - u8 *next; - - if (info->tag == tag) { - if (skip == 0) - break; - skip--; - } - - if ((info->len & 0x03) != 0) { - /* We bail out to avoid an alignment fault */ - printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n", - info->len, info->tag); - return NULL; - } - next = (u8 *) info + sizeof(*info) + info->len; - if (next >= omap_bootloader_tag + omap_bootloader_tag_len) - info = NULL; - else - info = (struct omap_board_config_entry *) next; - } - if (info != NULL) { - /* Check the length as a lame attempt to check for - * binary inconsistancy. */ - if (len != NO_LENGTH_CHECK) { - /* Word-align len */ - if (len & 0x03) - len = (len + 3) & ~0x03; - if (info->len != len) { - printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", - tag, len, info->len); - return NULL; - } - } - if (len_out != NULL) - *len_out = info->len; - return info->data; - } -#endif - /* Try to find the config from the board-specific structures - * in the kernel. */ - for (i = 0; i < omap_board_config_size; i++) { - if (omap_board_config[i].tag == tag) { - kinfo = &omap_board_config[i]; - break; - } - } - if (kinfo == NULL) - return NULL; - return kinfo->data; -} - -const void *__omap_get_config(u16 tag, size_t len, int nr) -{ - return get_config(tag, len, nr, NULL); -} -EXPORT_SYMBOL(__omap_get_config); - -const void *omap_get_var_config(u16 tag, size_t *len) -{ - return get_config(tag, NO_LENGTH_CHECK, 0, len); -} -EXPORT_SYMBOL(omap_get_var_config); - -static int __init omap_add_serial_console(void) -{ - const struct omap_uart_config *info; - - info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config); - if (info != NULL && info->console_uart) { - static char speed[11], *opt = NULL; - - if (info->console_speed) { - snprintf(speed, sizeof(speed), "%u", info->console_speed); - opt = speed; - } - return add_preferred_console("ttyS", info->console_uart - 1, opt); - } - return 0; -} -console_initcall(omap_add_serial_console); diff --git a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h deleted file mode 100644 index 9f62858c0df..00000000000 --- a/arch/arm/mach-omap/common.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * linux/arch/arm/mach-omap/common.h - * - * Header for code common to all OMAP machines. - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __ARCH_ARM_MACH_OMAP_COMMON_H -#define __ARCH_ARM_MACH_OMAP_COMMON_H - -struct sys_timer; - -extern void omap_map_io(void); -extern struct sys_timer omap_timer; -extern void omap_serial_init(int ports[]); - -#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig new file mode 100644 index 00000000000..7408ac94f77 --- /dev/null +++ b/arch/arm/mach-omap1/Kconfig @@ -0,0 +1,144 @@ +comment "OMAP Core Type" + depends on ARCH_OMAP1 + +config ARCH_OMAP730 + depends on ARCH_OMAP1 + bool "OMAP730 Based System" + select ARCH_OMAP_OTG + +config ARCH_OMAP1510 + depends on ARCH_OMAP1 + default y + bool "OMAP1510 Based System" + +config ARCH_OMAP16XX + depends on ARCH_OMAP1 + bool "OMAP16xx Based System" + select ARCH_OMAP_OTG + +comment "OMAP Board Type" + depends on ARCH_OMAP1 + +config MACH_OMAP_INNOVATOR + bool "TI Innovator" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX) + help + TI OMAP 1510 or 1610 Innovator board support. Say Y here if you + have such a board. + +config MACH_OMAP_H2 + bool "TI H2 Support" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + TI OMAP 1610/1611B H2 board support. Say Y here if you have such + a board. + +config MACH_OMAP_H3 + bool "TI H3 Support" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + TI OMAP 1710 H3 board support. Say Y here if you have such + a board. + +config MACH_OMAP_OSK + bool "TI OSK Support" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here + if you have such a board. + +config MACH_OMAP_PERSEUS2 + bool "TI Perseus2" + depends on ARCH_OMAP1 && ARCH_OMAP730 + help + Support for TI OMAP 730 Perseus2 board. Say Y here if you have such + a board. + +config MACH_VOICEBLUE + bool "Voiceblue" + depends on ARCH_OMAP1 && ARCH_OMAP1510 + help + Support for Voiceblue GSM/VoIP gateway. Say Y here if you have + such a board. + +config MACH_NETSTAR + bool "NetStar" + depends on ARCH_OMAP1 && ARCH_OMAP1510 + help + Support for NetStar PBX. Say Y here if you have such a board. + +config MACH_OMAP_GENERIC + bool "Generic OMAP board" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX) + help + Support for generic OMAP-1510, 1610 or 1710 board with + no FPGA. Can be used as template for porting Linux to + custom OMAP boards. Say Y here if you have a custom + board. + +comment "OMAP CPU Speed" + depends on ARCH_OMAP1 + +config OMAP_CLOCKS_SET_BY_BOOTLOADER + bool "OMAP clocks set by bootloader" + depends on ARCH_OMAP1 + help + Enable this option to prevent the kernel from overriding the clock + frequencies programmed by bootloader for MPU, DSP, MMUs, TC, + internal LCD controller and MPU peripherals. + +config OMAP_ARM_216MHZ + bool "OMAP ARM 216 MHz CPU (1710 only)" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + Enable 216 MHz clock for OMAP1710 CPU. If unsure, say N. + +config OMAP_ARM_195MHZ + bool "OMAP ARM 195 MHz CPU" + depends on ARCH_OMAP1 && ARCH_OMAP730 + help + Enable 195MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_192MHZ + bool "OMAP ARM 192 MHz CPU" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + Enable 192MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_182MHZ + bool "OMAP ARM 182 MHz CPU" + depends on ARCH_OMAP1 && ARCH_OMAP730 + help + Enable 182MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_168MHZ + bool "OMAP ARM 168 MHz CPU" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) + help + Enable 168MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_150MHZ + bool "OMAP ARM 150 MHz CPU" + depends on ARCH_OMAP1 && ARCH_OMAP1510 + help + Enable 150MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_120MHZ + bool "OMAP ARM 120 MHz CPU" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) + help + Enable 120MHz clock for OMAP CPU. If unsure, say N. + +config OMAP_ARM_60MHZ + bool "OMAP ARM 60 MHz CPU" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) + default y + help + Enable 60MHz clock for OMAP CPU. If unsure, say Y. + +config OMAP_ARM_30MHZ + bool "OMAP ARM 30 MHz CPU" + depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730) + help + Enable 30MHz clock for OMAP CPU. If unsure, say N. + diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile new file mode 100644 index 00000000000..d386fd913f0 --- /dev/null +++ b/arch/arm/mach-omap1/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux kernel. +# + +# Common support +obj-y := io.o id.o irq.o time.o serial.o +led-y := leds.o + +# Specific board support +obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o +obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o +obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o +obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o +obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o +obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o +obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o +obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o + +ifeq ($(CONFIG_ARCH_OMAP1510),y) +# Innovator-1510 FPGA +obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o +endif + +# LEDs support +led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o +led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o +led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o +led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o +obj-$(CONFIG_LEDS) += $(led-y) + diff --git a/arch/arm/mach-omap/Makefile.boot b/arch/arm/mach-omap1/Makefile.boot index fee1a6a15b5..292d56c5a88 100644 --- a/arch/arm/mach-omap/Makefile.boot +++ b/arch/arm/mach-omap1/Makefile.boot @@ -1,4 +1,3 @@ zreladdr-y := 0x10008000 params_phys-y := 0x10000100 initrd_phys-y := 0x10800000 - diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap1/board-generic.c index 384bc7cec1d..122796ebe8f 100644 --- a/arch/arm/mach-omap/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-generic.c + * linux/arch/arm/mach-omap1/board-generic.c * * Modified from board-innovator1510.c * @@ -26,8 +26,7 @@ #include <asm/arch/mux.h> #include <asm/arch/usb.h> #include <asm/arch/board.h> - -#include "common.h" +#include <asm/arch/common.h> static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; @@ -84,7 +83,7 @@ static void __init omap_generic_init(void) static void __init omap_generic_map_io(void) { - omap_map_io(); + omap_map_common_io() } MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap1/board-h2.c index f37c76a9b16..f4983ee95ab 100644 --- a/arch/arm/mach-omap/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-h2.c + * linux/arch/arm/mach-omap1/board-h2.c * * Board specific inits for OMAP-1610 H2 * @@ -35,8 +35,7 @@ #include <asm/arch/gpio.h> #include <asm/arch/tc.h> #include <asm/arch/usb.h> - -#include "common.h" +#include <asm/arch/common.h> extern int omap_gpio_init(void); @@ -172,7 +171,7 @@ static void __init h2_init(void) static void __init h2_map_io(void) { - omap_map_io(); + omap_map_common_io(); omap_serial_init(h2_serial_ports); } diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap1/board-h3.c index 705e48594e9..7cd419d61b4 100644 --- a/arch/arm/mach-omap/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-h3.c + * linux/arch/arm/mach-omap1/board-h3.c * * This file contains OMAP1710 H3 specific code. * @@ -37,8 +37,7 @@ #include <asm/arch/mux.h> #include <asm/arch/tc.h> #include <asm/arch/usb.h> - -#include "common.h" +#include <asm/arch/common.h> extern int omap_gpio_init(void); @@ -190,7 +189,7 @@ void h3_init_irq(void) static void __init h3_map_io(void) { - omap_map_io(); + omap_map_common_io(); omap_serial_init(h3_serial_ports); } diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index 523363f18cc..91de60a91ef 100644 --- a/arch/arm/mach-omap/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-innovator.c + * linux/arch/arm/mach-omap1/board-innovator.c * * Board specific inits for OMAP-1510 and OMAP-1610 Innovator * @@ -33,8 +33,7 @@ #include <asm/arch/gpio.h> #include <asm/arch/tc.h> #include <asm/arch/usb.h> - -#include "common.h" +#include <asm/arch/common.h> static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; @@ -252,7 +251,7 @@ static void __init innovator_init(void) static void __init innovator_map_io(void) { - omap_map_io(); + omap_map_common_io(); #ifdef CONFIG_ARCH_OMAP1510 if (cpu_is_omap1510()) { diff --git a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c index 8c653734d5a..6750b201409 100644 --- a/arch/arm/mach-omap/board-netstar.c +++ b/arch/arm/mach-omap1/board-netstar.c @@ -26,8 +26,7 @@ #include <asm/arch/gpio.h> #include <asm/arch/mux.h> #include <asm/arch/usb.h> - -#include "common.h" +#include <asm/arch/common.h> extern void __init omap_init_time(void); extern int omap_gpio_init(void); @@ -100,7 +99,7 @@ static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; static void __init netstar_map_io(void) { - omap_map_io(); + omap_map_common_io(); omap_serial_init(omap_serial_ports); } diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap1/board-osk.c index cb433436aa0..6844e536c69 100644 --- a/arch/arm/mach-omap/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-osk.c + * linux/arch/arm/mach-omap1/board-osk.c * * Board specific init for OMAP5912 OSK * @@ -39,8 +39,7 @@ #include <asm/arch/usb.h> #include <asm/arch/mux.h> #include <asm/arch/tc.h> - -#include "common.h" +#include <asm/arch/common.h> static struct map_desc osk5912_io_desc[] __initdata = { { OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE, @@ -153,7 +152,7 @@ static void __init osk_init(void) static void __init osk_map_io(void) { - omap_map_io(); + omap_map_common_io(); iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc)); omap_serial_init(osk_serial_ports); } diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index d5342043d48..213317392d9 100644 --- a/arch/arm/mach-omap/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-perseus2.c + * linux/arch/arm/mach-omap1/board-perseus2.c * * Modified from board-generic.c * @@ -27,8 +27,7 @@ #include <asm/arch/gpio.h> #include <asm/arch/mux.h> #include <asm/arch/fpga.h> - -#include "common.h" +#include <asm/arch/common.h> static struct resource smc91x_resources[] = { [0] = { @@ -140,7 +139,7 @@ static struct map_desc omap_perseus2_io_desc[] __initdata = { static void __init omap_perseus2_map_io(void) { - omap_map_io(); + omap_map_common_io(); iotable_init(omap_perseus2_io_desc, ARRAY_SIZE(omap_perseus2_io_desc)); diff --git a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 6b0c5003d71..e4228198899 100644 --- a/arch/arm/mach-omap/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/board-voiceblue.c + * linux/arch/arm/mach-omap1/board-voiceblue.c * * Modified from board-generic.c * @@ -31,8 +31,7 @@ #include <asm/arch/tc.h> #include <asm/arch/mux.h> #include <asm/arch/usb.h> - -#include "common.h" +#include <asm/arch/common.h> extern void omap_init_time(void); extern int omap_gpio_init(void); @@ -170,7 +169,7 @@ static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; static void __init voiceblue_map_io(void) { - omap_map_io(); + omap_map_common_io(); omap_serial_init(omap_serial_ports); } diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap1/fpga.c index 7c08f6c2e1d..7c08f6c2e1d 100644 --- a/arch/arm/mach-omap/fpga.c +++ b/arch/arm/mach-omap1/fpga.c diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c new file mode 100644 index 00000000000..986c3b7e09b --- /dev/null +++ b/arch/arm/mach-omap1/id.c @@ -0,0 +1,188 @@ +/* + * linux/arch/arm/mach-omap1/id.c + * + * OMAP1 CPU identification code + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/io.h> + +struct omap_id { + u16 jtag_id; /* Used to determine OMAP type */ + u8 die_rev; /* Processor revision */ + u32 omap_id; /* OMAP revision */ + u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */ +}; + +/* Register values to detect the OMAP version */ +static struct omap_id omap_ids[] __initdata = { + { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, + { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, + { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000}, + { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00}, + { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00}, + { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300}, + { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000}, +}; + +/* + * Get OMAP type from PROD_ID. + * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM. + * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense. + * Undocumented register in TEST BLOCK is used as fallback; This seems to + * work on 1510, 1610 & 1710. The official way hopefully will work in future + * processors. + */ +static u16 __init omap_get_jtag_id(void) +{ + u32 prod_id, omap_id; + + prod_id = omap_readl(OMAP_PRODUCTION_ID_1); + omap_id = omap_readl(OMAP32_ID_1); + + /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ + if (((prod_id >> 20) == 0) || (prod_id == omap_id)) + prod_id = 0; + else + prod_id &= 0xffff; + + if (prod_id) + return prod_id; + + /* Use OMAP32_ID_1 as fallback */ + prod_id = ((omap_id >> 12) & 0xffff); + + return prod_id; +} + +/* + * Get OMAP revision from DIE_REV. + * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID. + * Undocumented register in the TEST BLOCK is used as fallback. + * REVISIT: This does not seem to work on 1510 + */ +static u8 __init omap_get_die_rev(void) +{ + u32 die_rev; + + die_rev = omap_readl(OMAP_DIE_ID_1); + + /* Check for broken OMAP_DIE_ID on early 1710 */ + if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id()) + die_rev = 0; + + die_rev = (die_rev >> 17) & 0xf; + if (die_rev) + return die_rev; + + die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf; + + return die_rev; +} + +void __init omap_check_revision(void) +{ + int i; + u16 jtag_id; + u8 die_rev; + u32 omap_id; + u8 cpu_type; + + jtag_id = omap_get_jtag_id(); + die_rev = omap_get_die_rev(); + omap_id = omap_readl(OMAP32_ID_0); + +#ifdef DEBUG + printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0)); + printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n", + omap_readl(OMAP_DIE_ID_1), + (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf); + printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0)); + printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n", + omap_readl(OMAP_PRODUCTION_ID_1), + omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff); + printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0)); + printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1)); + printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev); +#endif + + system_serial_high = omap_readl(OMAP_DIE_ID_0); + system_serial_low = omap_readl(OMAP_DIE_ID_1); + + /* First check only the major version in a safe way */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == (omap_ids[i].jtag_id)) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Check if we can find the die revision */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Finally check also the omap_id */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id + && die_rev == omap_ids[i].die_rev + && omap_id == omap_ids[i].omap_id) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */ + cpu_type = system_rev >> 24; + + switch (cpu_type) { + case 0x07: + system_rev |= 0x07; + break; + case 0x15: + system_rev |= 0x15; + break; + case 0x16: + case 0x17: + system_rev |= 0x16; + break; + case 0x24: + system_rev |= 0x24; + break; + default: + printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type); + } + + printk("OMAP%04x", system_rev >> 16); + if ((system_rev >> 8) & 0xff) + printk("%x", (system_rev >> 8) & 0xff); + printk(" revision %i handled as %02xxx id: %08x%08x\n", + die_rev, system_rev & 0xff, system_serial_low, + system_serial_high); +} + diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c new file mode 100644 index 00000000000..207df0fe934 --- /dev/null +++ b/arch/arm/mach-omap1/io.c @@ -0,0 +1,115 @@ +/* + * linux/arch/arm/mach-omap1/io.c + * + * OMAP1 I/O mapping code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mach/map.h> +#include <asm/io.h> +#include <asm/arch/tc.h> + +extern int clk_init(void); +extern void omap_check_revision(void); + +/* + * The machine specific code may provide the extra mapping besides the + * default mapping provided here. + */ +static struct map_desc omap_io_desc[] __initdata = { + { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE }, +}; + +#ifdef CONFIG_ARCH_OMAP730 +static struct map_desc omap730_io_desc[] __initdata = { + { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE }, + { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE }, + { OMAP730_SRAM_BASE, OMAP730_SRAM_START, OMAP730_SRAM_SIZE, MT_DEVICE } +}; +#endif + +#ifdef CONFIG_ARCH_OMAP1510 +static struct map_desc omap1510_io_desc[] __initdata = { + { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE }, + { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE }, + { OMAP1510_SRAM_BASE, OMAP1510_SRAM_START, OMAP1510_SRAM_SIZE, MT_DEVICE } +}; +#endif + +#if defined(CONFIG_ARCH_OMAP16XX) +static struct map_desc omap1610_io_desc[] __initdata = { + { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, + { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, + { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP1610_SRAM_SIZE, MT_DEVICE } +}; + +static struct map_desc omap5912_io_desc[] __initdata = { + { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE }, + { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE }, +/* + * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page + * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped. + * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte + * can be used. + */ + { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE } +}; +#endif + +static int initialized = 0; + +static void __init _omap_map_io(void) +{ + initialized = 1; + + /* We have to initialize the IO space mapping before we can run + * cpu_is_omapxxx() macros. */ + iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc)); + omap_check_revision(); + +#ifdef CONFIG_ARCH_OMAP730 + if (cpu_is_omap730()) { + iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc)); + } +#endif +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) { + iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); + } +#endif +#if defined(CONFIG_ARCH_OMAP16XX) + if (cpu_is_omap1610() || cpu_is_omap1710()) { + iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc)); + } + if (cpu_is_omap5912()) { + iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc)); + } +#endif + + /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort + * on a Posted Write in the TIPB Bridge". + */ + omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL); + omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL); + + /* Must init clocks early to assure that timer interrupt works + */ + clk_init(); +} + +/* + * This should only get called from board specific init + */ +void omap_map_common_io(void) +{ + if (!initialized) + _omap_map_io(); +} diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap1/irq.c index f01c99266a8..a11b6d80735 100644 --- a/arch/arm/mach-omap/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -56,6 +56,7 @@ struct omap_irq_bank { unsigned long base_reg; unsigned long trigger_map; + unsigned long wake_enable; }; static unsigned int irq_bank_count = 0; @@ -105,6 +106,19 @@ static void omap_mask_ack_irq(unsigned int irq) omap_ack_irq(irq); } +static int omap_wake_irq(unsigned int irq, unsigned int enable) +{ + int bank = IRQ_BANK(irq); + + if (enable) + irq_banks[bank].wake_enable |= IRQ_BIT(irq); + else + irq_banks[bank].wake_enable &= ~IRQ_BIT(irq); + + return 0; +} + + /* * Allows tuning the IRQ type and priority * @@ -145,7 +159,7 @@ static struct omap_irq_bank omap1510_irq_banks[] = { static struct omap_irq_bank omap1610_irq_banks[] = { { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, - { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xfffff7ff }, + { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff }, { .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff }, }; #endif @@ -154,6 +168,7 @@ static struct irqchip omap_irq_chip = { .ack = omap_mask_ack_irq, .mask = omap_mask_irq, .unmask = omap_unmask_irq, + .wake = omap_wake_irq, }; void __init omap_init_irq(void) diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c index 6e98290cca5..6e98290cca5 100644 --- a/arch/arm/mach-omap/leds-h2p2-debug.c +++ b/arch/arm/mach-omap1/leds-h2p2-debug.c diff --git a/arch/arm/mach-omap/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c index 8043b7d0f66..8043b7d0f66 100644 --- a/arch/arm/mach-omap/leds-innovator.c +++ b/arch/arm/mach-omap1/leds-innovator.c diff --git a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c index f5177f43079..4a0e8b9d4fc 100644 --- a/arch/arm/mach-omap/leds-osk.c +++ b/arch/arm/mach-omap1/leds-osk.c @@ -129,14 +129,11 @@ void osk_leds_event(led_event_t evt) #ifdef CONFIG_FB_OMAP -#ifdef CONFIG_LEDS_TIMER case led_timer: hw_led_state ^= TIMER_LED; mistral_setled(); break; -#endif -#ifdef CONFIG_LEDS_CPU case led_idle_start: hw_led_state |= IDLE_LED; mistral_setled(); @@ -146,7 +143,6 @@ void osk_leds_event(led_event_t evt) hw_led_state &= ~IDLE_LED; mistral_setled(); break; -#endif #endif /* CONFIG_FB_OMAP */ diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap1/leds.c index 8ab21fe98e1..8ab21fe98e1 100644 --- a/arch/arm/mach-omap/leds.c +++ b/arch/arm/mach-omap1/leds.c diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap1/leds.h index a1e9fedc376..a1e9fedc376 100644 --- a/arch/arm/mach-omap/leds.h +++ b/arch/arm/mach-omap1/leds.h diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c new file mode 100644 index 00000000000..214e5d17c8b --- /dev/null +++ b/arch/arm/mach-omap1/serial.c @@ -0,0 +1,200 @@ +/* + * linux/arch/arm/mach-omap1/id.c + * + * OMAP1 CPU identification code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> + +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/hardware/clock.h> + +#include <asm/arch/board.h> +#include <asm/arch/mux.h> +#include <asm/arch/fpga.h> + +static struct clk * uart1_ck = NULL; +static struct clk * uart2_ck = NULL; +static struct clk * uart3_ck = NULL; + +static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, + int offset) +{ + offset <<= up->regshift; + return (unsigned int)__raw_readb(up->membase + offset); +} + +static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset, + int value) +{ + offset <<= p->regshift; + __raw_writeb(value, p->membase + offset); +} + +/* + * Internal UARTs need to be initialized for the 8250 autoconfig to work + * properly. Note that the TX watermark initialization may not be needed + * once the 8250.c watermark handling code is merged. + */ +static void __init omap_serial_reset(struct plat_serial8250_port *p) +{ + omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */ + omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */ + omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */ + + if (!cpu_is_omap1510()) { + omap_serial_outp(p, UART_OMAP_SYSC, 0x01); + while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01)); + } +} + +static struct plat_serial8250_port serial_platform_data[] = { + { + .membase = (char*)IO_ADDRESS(OMAP_UART1_BASE), + .mapbase = (unsigned long)OMAP_UART1_BASE, + .irq = INT_UART1, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = OMAP16XX_BASE_BAUD * 16, + }, + { + .membase = (char*)IO_ADDRESS(OMAP_UART2_BASE), + .mapbase = (unsigned long)OMAP_UART2_BASE, + .irq = INT_UART2, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = OMAP16XX_BASE_BAUD * 16, + }, + { + .membase = (char*)IO_ADDRESS(OMAP_UART3_BASE), + .mapbase = (unsigned long)OMAP_UART3_BASE, + .irq = INT_UART3, + .flags = UPF_BOOT_AUTOCONF, + .iotype = UPIO_MEM, + .regshift = 2, + .uartclk = OMAP16XX_BASE_BAUD * 16, + }, + { }, +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +/* + * Note that on Innovator-1510 UART2 pins conflict with USB2. + * By default UART2 does not work on Innovator-1510 if you have + * USB OHCI enabled. To use UART2, you must disable USB2 first. + */ +void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS]) +{ + int i; + + if (cpu_is_omap730()) { + serial_platform_data[0].regshift = 0; + serial_platform_data[1].regshift = 0; + serial_platform_data[0].irq = INT_730_UART_MODEM_1; + serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2; + } + + if (cpu_is_omap1510()) { + serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16; + serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16; + serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16; + } + + for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { + unsigned char reg; + + if (ports[i] == 0) { + serial_platform_data[i].membase = NULL; + serial_platform_data[i].mapbase = 0; + continue; + } + + switch (i) { + case 0: + uart1_ck = clk_get(NULL, "uart1_ck"); + if (IS_ERR(uart1_ck)) + printk("Could not get uart1_ck\n"); + else { + clk_use(uart1_ck); + if (cpu_is_omap1510()) + clk_set_rate(uart1_ck, 12000000); + } + if (cpu_is_omap1510()) { + omap_cfg_reg(UART1_TX); + omap_cfg_reg(UART1_RTS); + if (machine_is_omap_innovator()) { + reg = fpga_read(OMAP1510_FPGA_POWER); + reg |= OMAP1510_FPGA_PCR_COM1_EN; + fpga_write(reg, OMAP1510_FPGA_POWER); + udelay(10); + } + } + break; + case 1: + uart2_ck = clk_get(NULL, "uart2_ck"); + if (IS_ERR(uart2_ck)) + printk("Could not get uart2_ck\n"); + else { + clk_use(uart2_ck); + if (cpu_is_omap1510()) + clk_set_rate(uart2_ck, 12000000); + else + clk_set_rate(uart2_ck, 48000000); + } + if (cpu_is_omap1510()) { + omap_cfg_reg(UART2_TX); + omap_cfg_reg(UART2_RTS); + if (machine_is_omap_innovator()) { + reg = fpga_read(OMAP1510_FPGA_POWER); + reg |= OMAP1510_FPGA_PCR_COM2_EN; + fpga_write(reg, OMAP1510_FPGA_POWER); + udelay(10); + } + } + break; + case 2: + uart3_ck = clk_get(NULL, "uart3_ck"); + if (IS_ERR(uart3_ck)) + printk("Could not get uart3_ck\n"); + else { + clk_use(uart3_ck); + if (cpu_is_omap1510()) + clk_set_rate(uart3_ck, 12000000); + } + if (cpu_is_omap1510()) { + omap_cfg_reg(UART3_TX); + omap_cfg_reg(UART3_RX); + } + break; + } + omap_serial_reset(&serial_platform_data[i]); + } +} + +static int __init omap_init(void) +{ + return platform_device_register(&serial_device); +} +arch_initcall(omap_init); diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap1/time.c index dd34e9f4c41..d540539c9bb 100644 --- a/arch/arm/mach-omap/time.c +++ b/arch/arm/mach-omap1/time.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/time.c + * linux/arch/arm/mach-omap1/time.c * * OMAP Timers * @@ -58,17 +58,9 @@ struct sys_timer omap_timer; * MPU timer * --------------------------------------------------------------------------- */ -#define OMAP_MPU_TIMER1_BASE (0xfffec500) -#define OMAP_MPU_TIMER2_BASE (0xfffec600) -#define OMAP_MPU_TIMER3_BASE (0xfffec700) #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE #define OMAP_MPU_TIMER_OFFSET 0x100 -#define MPU_TIMER_FREE (1 << 6) -#define MPU_TIMER_CLOCK_ENABLE (1 << 5) -#define MPU_TIMER_AR (1 << 1) -#define MPU_TIMER_ST (1 << 0) - /* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c, * converted to use kHz by Kevin Hilman */ /* convert from cycles(64bits) => nanoseconds (64bits) @@ -255,6 +247,13 @@ unsigned long long sched_clock(void) #define OMAP_32K_TIMER_TCR 0x04 #define OMAP_32K_TICKS_PER_HZ (32768 / HZ) +#if (32768 % HZ) != 0 +/* We cannot ignore modulo. + * Potential error can be as high as several percent. + */ +#define OMAP_32K_TICK_MODULO (32768 % HZ) +static unsigned modulo_count = 0; /* Counts 1/HZ units */ +#endif /* * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 @@ -331,6 +330,19 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, now = omap_32k_sync_timer_read(); while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { +#ifdef OMAP_32K_TICK_MODULO + /* Modulo addition may put omap_32k_last_tick ahead of now + * and cause unwanted repetition of the while loop. + */ + if (unlikely(now - omap_32k_last_tick == ~0)) + break; + + modulo_count += OMAP_32K_TICK_MODULO; + if (modulo_count > HZ) { + ++omap_32k_last_tick; + modulo_count -= HZ; + } +#endif omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; timer_tick(regs); } @@ -407,7 +419,7 @@ static __init void omap_init_32k_timer(void) * Timer initialization * --------------------------------------------------------------------------- */ -void __init omap_timer_init(void) +static void __init omap_timer_init(void) { #if defined(CONFIG_OMAP_MPU_TIMER) omap_init_mpu_timer(); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 95606b4a3ba..afbbeb6f465 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -101,7 +101,7 @@ config CPU_ARM922T # ARM925T config CPU_ARM925T - bool "Support ARM925T processor" if ARCH_OMAP + bool "Support ARM925T processor" if ARCH_OMAP1 depends on ARCH_OMAP1510 default y if ARCH_OMAP1510 select CPU_32v4 diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index c3bd503b43a..b19f00e99a2 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -399,7 +399,7 @@ static void __init build_mem_type_table(void) ecc_mask = 0; } - if (cpu_arch <= CPU_ARCH_ARMv5) { + if (cpu_arch <= CPU_ARCH_ARMv5TEJ) { for (i = 0; i < ARRAY_SIZE(mem_types); i++) { if (mem_types[i].prot_l1) mem_types[i].prot_l1 |= PMD_BIT4; @@ -584,7 +584,7 @@ void setup_mm_for_reboot(char mode) pmdval = (i << PGDIR_SHIFT) | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT; - if (cpu_arch <= CPU_ARCH_ARMv5) + if (cpu_arch <= CPU_ARCH_ARMv5TEJ) pmdval |= PMD_BIT4; pmd = pmd_off(pgd, i << PGDIR_SHIFT); pmd[0] = __pmd(pmdval); diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index e3d8510f434..352db98ee26 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -200,7 +200,7 @@ __v6_setup: mcr p15, 0, r4, c2, c0, 1 @ load TTB1 #ifdef CONFIG_VFP mrc p15, 0, r0, c1, c0, 2 - orr r0, r0, #(3 << 20) + orr r0, r0, #(0xf << 20) mcr p15, 0, r0, c1, c0, 2 @ Enable full access to VFP #endif mrc p15, 0, r0, c1, c0, 0 @ read control register diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig new file mode 100644 index 00000000000..345365852f8 --- /dev/null +++ b/arch/arm/plat-omap/Kconfig @@ -0,0 +1,112 @@ +if ARCH_OMAP + +menu "TI OMAP Implementations" + +config ARCH_OMAP_OTG + bool + +choice + prompt "OMAP System Type" + default ARCH_OMAP1 + +config ARCH_OMAP1 + bool "TI OMAP1" + +config ARCH_OMAP2 + bool "TI OMAP2" + +endchoice + +comment "OMAP Feature Selections" + +config OMAP_RESET_CLOCKS + bool "Reset unused clocks during boot" + depends on ARCH_OMAP + default n + help + Say Y if you want to reset unused clocks during boot. + This option saves power, but assumes all drivers are + using the clock framework. Broken drivers that do not + yet use clock framework may not work with this option. + If you are booting from another operating system, you + probably do not want this option enabled until your + device drivers work properly. + +config OMAP_MUX + bool "OMAP multiplexing support" + depends on ARCH_OMAP + default y + help + Pin multiplexing support for OMAP boards. If your bootloader + sets the multiplexing correctly, say N. Otherwise, or if unsure, + say Y. + +config OMAP_MUX_DEBUG + bool "Multiplexing debug output" + depends on OMAP_MUX + default n + help + Makes the multiplexing functions print out a lot of debug info. + This is useful if you want to find out the correct values of the + multiplexing registers. + +config OMAP_MUX_WARNINGS + bool "Warn about pins the bootloader didn't set up" + depends on OMAP_MUX + default y + help + Choose Y here to warn whenever driver initialization logic needs + to change the pin multiplexing setup. When there are no warnings + printed, it's safe to deselect OMAP_MUX for your product. + +choice + prompt "System timer" + default OMAP_MPU_TIMER + +config OMAP_MPU_TIMER + bool "Use mpu timer" + help + Select this option if you want to use the OMAP mpu timer. This + timer provides more intra-tick resolution than the 32KHz timer, + but consumes more power. + +config OMAP_32K_TIMER + bool "Use 32KHz timer" + depends on ARCH_OMAP16XX + help + Select this option if you want to enable the OMAP 32KHz timer. + This timer saves power compared to the OMAP_MPU_TIMER, and has + support for no tick during idle. The 32KHz timer provides less + intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is + currently only available for OMAP-16xx. + +endchoice + +config OMAP_32K_TIMER_HZ + int "Kernel internal timer frequency for 32KHz timer" + range 32 1024 + depends on OMAP_32K_TIMER + default "128" + help + Kernel internal timer frequency should be a divisor of 32768, + such as 64 or 128. + +choice + prompt "Low-level debug console UART" + depends on ARCH_OMAP + default OMAP_LL_DEBUG_UART1 + +config OMAP_LL_DEBUG_UART1 + bool "UART1" + +config OMAP_LL_DEBUG_UART2 + bool "UART2" + +config OMAP_LL_DEBUG_UART3 + bool "UART3" + +endchoice + +endmenu + +endif diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile new file mode 100644 index 00000000000..531e11af54d --- /dev/null +++ b/arch/arm/plat-omap/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the linux kernel. +# + +# Common support +obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o +obj-m := +obj-n := +obj- := + +# OCPI interconnect support for 1710, 1610 and 5912 +obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o + +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o + +obj-$(CONFIG_CPU_FREQ) += cpu-omap.o diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/plat-omap/clock.c index e91186b5341..59d91b3262b 100644 --- a/arch/arm/mach-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/clock.c + * linux/arch/arm/plat-omap/clock.c * * Copyright (C) 2004 Nokia corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> @@ -14,6 +14,7 @@ #include <linux/errno.h> #include <linux/err.h> +#include <asm/io.h> #include <asm/semaphore.h> #include <asm/hardware/clock.h> #include <asm/arch/board.h> @@ -25,6 +26,8 @@ static LIST_HEAD(clocks); static DECLARE_MUTEX(clocks_sem); static DEFINE_SPINLOCK(clockfw_lock); static void propagate_rate(struct clk * clk); +/* UART clock function */ +static int set_uart_rate(struct clk * clk, unsigned long rate); /* External clock (MCLK & BCLK) functions */ static int set_ext_clk_rate(struct clk * clk, unsigned long rate); static long round_ext_clk_rate(struct clk * clk, unsigned long rate); @@ -34,7 +37,7 @@ static int select_table_rate(struct clk * clk, unsigned long rate); static long round_to_table_rate(struct clk * clk, unsigned long rate); void clk_setdpll(__u16, __u16); -struct mpu_rate rate_table[] = { +static struct mpu_rate rate_table[] = { /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv */ @@ -48,7 +51,7 @@ struct mpu_rate rate_table[] = { { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */ { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */ { 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */ - { 48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */ + { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */ { 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */ #endif #if defined(CONFIG_OMAP_ARM_182MHZ) @@ -58,7 +61,7 @@ struct mpu_rate rate_table[] = { { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */ #endif #if defined(CONFIG_OMAP_ARM_150MHZ) - { 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */ + { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */ #endif #if defined(CONFIG_OMAP_ARM_120MHZ) { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */ @@ -76,19 +79,11 @@ struct mpu_rate rate_table[] = { }; -static void ckctl_recalc(struct clk * clk) -{ - int dsor; - - /* Calculate divisor encoded as 2-bit exponent */ - dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); - if (unlikely(clk->rate == clk->parent->rate / dsor)) - return; /* No change, quick exit */ - clk->rate = clk->parent->rate / dsor; - - if (unlikely(clk->flags & RATE_PROPAGATES)) - propagate_rate(clk); -} +static void ckctl_recalc(struct clk * clk); +int __clk_enable(struct clk *clk); +void __clk_disable(struct clk *clk); +void __clk_unuse(struct clk *clk); +int __clk_use(struct clk *clk); static void followparent_recalc(struct clk * clk) @@ -102,6 +97,14 @@ static void watchdog_recalc(struct clk * clk) clk->rate = clk->parent->rate / 14; } +static void uart_recalc(struct clk * clk) +{ + unsigned int val = omap_readl(clk->enable_reg); + if (val & clk->enable_bit) + clk->rate = 48000000; + else + clk->rate = 12000000; +} static struct clk ck_ref = { .name = "ck_ref", @@ -138,7 +141,7 @@ static struct clk arm_ck = { static struct clk armper_ck = { .name = "armper_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | RATE_CKCTL, .enable_reg = ARM_IDLECT2, .enable_bit = EN_PERCK, @@ -185,7 +188,7 @@ static struct clk armwdt_ck = { static struct clk arminth_ck16xx = { .name = "arminth_ck", .parent = &arm_ck, - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, .recalc = &followparent_recalc, /* Note: On 16xx the frequency can be divided by 2 by programming * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 @@ -214,6 +217,38 @@ static struct clk dspmmu_ck = { .recalc = &ckctl_recalc, }; +static struct clk dspper_ck = { + .name = "dspper_ck", + .parent = &ck_dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, + .enable_reg = DSP_IDLECT2, + .enable_bit = EN_PERCK, + .rate_offset = CKCTL_PERDIV_OFFSET, + .recalc = &followparent_recalc, + //.recalc = &ckctl_recalc, +}; + +static struct clk dspxor_ck = { + .name = "dspxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, + .enable_reg = DSP_IDLECT2, + .enable_bit = EN_XORPCK, + .recalc = &followparent_recalc, +}; + +static struct clk dsptim_ck = { + .name = "dsptim_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS, + .enable_reg = DSP_IDLECT2, + .enable_bit = EN_DSPTIMCK, + .recalc = &followparent_recalc, +}; + static struct clk tc_ck = { .name = "tc_ck", .parent = &ck_dpll1, @@ -226,7 +261,7 @@ static struct clk tc_ck = { static struct clk arminth_ck1510 = { .name = "arminth_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510, + .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, .recalc = &followparent_recalc, /* Note: On 1510 the frequency follows TC_CK * @@ -237,7 +272,7 @@ static struct clk arminth_ck1510 = { static struct clk tipb_ck = { .name = "tibp_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510, + .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, .recalc = &followparent_recalc, }; @@ -271,14 +306,15 @@ static struct clk tc2_ck = { static struct clk dma_ck = { .name = "dma_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + ALWAYS_ENABLED, .recalc = &followparent_recalc, }; static struct clk dma_lcdfree_ck = { .name = "dma_lcdfree_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, .recalc = &followparent_recalc, }; @@ -303,14 +339,14 @@ static struct clk lb_ck = { static struct clk rhea1_ck = { .name = "rhea1_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, .recalc = &followparent_recalc, }; static struct clk rhea2_ck = { .name = "rhea2_ck", .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, .recalc = &followparent_recalc, }; @@ -325,43 +361,55 @@ static struct clk lcd_ck = { .recalc = &ckctl_recalc, }; -static struct clk uart1_ck = { +static struct clk uart1_1510 = { + .name = "uart1_ck", + /* Direct from ULPD, no parent */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, + .enable_reg = MOD_CONF_CTRL_0, + .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ + .set_rate = &set_uart_rate, + .recalc = &uart_recalc, +}; + +static struct clk uart1_16xx = { .name = "uart1_ck", /* Direct from ULPD, no parent */ .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT, + .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = MOD_CONF_CTRL_0, .enable_bit = 29, - /* (Only on 1510) - * The "enable bit" actually chooses between 48MHz and 12MHz. - */ }; static struct clk uart2_ck = { .name = "uart2_ck", /* Direct from ULPD, no parent */ - .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT, + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT, .enable_reg = MOD_CONF_CTRL_0, - .enable_bit = 30, - /* (for both 1510 and 16xx) - * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz. - */ + .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ + .set_rate = &set_uart_rate, + .recalc = &uart_recalc, }; -static struct clk uart3_ck = { +static struct clk uart3_1510 = { + .name = "uart3_ck", + /* Direct from ULPD, no parent */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED, + .enable_reg = MOD_CONF_CTRL_0, + .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ + .set_rate = &set_uart_rate, + .recalc = &uart_recalc, +}; + +static struct clk uart3_16xx = { .name = "uart3_ck", /* Direct from ULPD, no parent */ .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT, + .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = MOD_CONF_CTRL_0, .enable_bit = 31, - /* (Only on 1510) - * The "enable bit" actually chooses between 48MHz and 12MHz. - */ }; static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ @@ -480,6 +528,9 @@ static struct clk * onchip_clks[] = { /* CK_GEN2 clocks */ &dsp_ck, &dspmmu_ck, + &dspper_ck, + &dspxor_ck, + &dsptim_ck, /* CK_GEN3 clocks */ &tc_ck, &tipb_ck, @@ -494,9 +545,11 @@ static struct clk * onchip_clks[] = { &rhea2_ck, &lcd_ck, /* ULPD clocks */ - &uart1_ck, + &uart1_1510, + &uart1_16xx, &uart2_ck, - &uart3_ck, + &uart3_1510, + &uart3_16xx, &usb_clko, &usb_hhc_ck1510, &usb_hhc_ck16xx, &mclk_1510, &mclk_16xx, @@ -547,14 +600,34 @@ int __clk_enable(struct clk *clk) return 0; } + if (clk->flags & DSP_DOMAIN_CLOCK) { + __clk_use(&api_ck); + } + if (clk->flags & ENABLE_REG_32BIT) { - regval32 = omap_readl(clk->enable_reg); - regval32 |= (1 << clk->enable_bit); - omap_writel(regval32, clk->enable_reg); + if (clk->flags & VIRTUAL_IO_ADDRESS) { + regval32 = __raw_readl(clk->enable_reg); + regval32 |= (1 << clk->enable_bit); + __raw_writel(regval32, clk->enable_reg); + } else { + regval32 = omap_readl(clk->enable_reg); + regval32 |= (1 << clk->enable_bit); + omap_writel(regval32, clk->enable_reg); + } } else { - regval16 = omap_readw(clk->enable_reg); - regval16 |= (1 << clk->enable_bit); - omap_writew(regval16, clk->enable_reg); + if (clk->flags & VIRTUAL_IO_ADDRESS) { + regval16 = __raw_readw(clk->enable_reg); + regval16 |= (1 << clk->enable_bit); + __raw_writew(regval16, clk->enable_reg); + } else { + regval16 = omap_readw(clk->enable_reg); + regval16 |= (1 << clk->enable_bit); + omap_writew(regval16, clk->enable_reg); + } + } + + if (clk->flags & DSP_DOMAIN_CLOCK) { + __clk_unuse(&api_ck); } return 0; @@ -569,14 +642,34 @@ void __clk_disable(struct clk *clk) if (clk->enable_reg == 0) return; + if (clk->flags & DSP_DOMAIN_CLOCK) { + __clk_use(&api_ck); + } + if (clk->flags & ENABLE_REG_32BIT) { - regval32 = omap_readl(clk->enable_reg); - regval32 &= ~(1 << clk->enable_bit); - omap_writel(regval32, clk->enable_reg); + if (clk->flags & VIRTUAL_IO_ADDRESS) { + regval32 = __raw_readl(clk->enable_reg); + regval32 &= ~(1 << clk->enable_bit); + __raw_writel(regval32, clk->enable_reg); + } else { + regval32 = omap_readl(clk->enable_reg); + regval32 &= ~(1 << clk->enable_bit); + omap_writel(regval32, clk->enable_reg); + } } else { - regval16 = omap_readw(clk->enable_reg); - regval16 &= ~(1 << clk->enable_bit); - omap_writew(regval16, clk->enable_reg); + if (clk->flags & VIRTUAL_IO_ADDRESS) { + regval16 = __raw_readw(clk->enable_reg); + regval16 &= ~(1 << clk->enable_bit); + __raw_writew(regval16, clk->enable_reg); + } else { + regval16 = omap_readw(clk->enable_reg); + regval16 &= ~(1 << clk->enable_bit); + omap_writew(regval16, clk->enable_reg); + } + } + + if (clk->flags & DSP_DOMAIN_CLOCK) { + __clk_unuse(&api_ck); } } @@ -766,6 +859,33 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate) return dsor_exp; } + +static void ckctl_recalc(struct clk * clk) +{ + int dsor; + + /* Calculate divisor encoded as 2-bit exponent */ + if (clk->flags & DSP_DOMAIN_CLOCK) { + /* The clock control bits are in DSP domain, + * so api_ck is needed for access. + * Note that DSP_CKCTL virt addr = phys addr, so + * we must use __raw_readw() instead of omap_readw(). + */ + __clk_use(&api_ck); + dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset)); + __clk_unuse(&api_ck); + } else { + dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset)); + } + if (unlikely(clk->rate == clk->parent->rate / dsor)) + return; /* No change, quick exit */ + clk->rate = clk->parent->rate / dsor; + + if (unlikely(clk->flags & RATE_PROPAGATES)) + propagate_rate(clk); +} + + long clk_round_rate(struct clk *clk, unsigned long rate) { int dsor_exp; @@ -826,6 +946,9 @@ static int select_table_rate(struct clk * clk, unsigned long rate) if (!ptr->rate) return -EINVAL; + if (!ptr->rate) + return -EINVAL; + if (unlikely(ck_dpll1.rate == 0)) { omap_writew(ptr->dpllctl_val, DPLL_CTL); ck_dpll1.rate = ptr->pll_rate; @@ -921,6 +1044,23 @@ static unsigned calc_ext_dsor(unsigned long rate) return dsor; } +/* Only needed on 1510 */ +static int set_uart_rate(struct clk * clk, unsigned long rate) +{ + unsigned int val; + + val = omap_readl(clk->enable_reg); + if (rate == 12000000) + val &= ~(1 << clk->enable_bit); + else if (rate == 48000000) + val |= (1 << clk->enable_bit); + else + return -EINVAL; + omap_writel(val, clk->enable_reg); + clk->rate = rate; + + return 0; +} static int set_ext_clk_rate(struct clk * clk, unsigned long rate) { @@ -985,7 +1125,18 @@ void clk_unregister(struct clk *clk) } EXPORT_SYMBOL(clk_unregister); - +#ifdef CONFIG_OMAP_RESET_CLOCKS +/* + * Resets some clocks that may be left on from bootloader, + * but leaves serial clocks on. See also omap_late_clk_reset(). + */ +static inline void omap_early_clk_reset(void) +{ + //omap_writel(0x3 << 29, MOD_CONF_CTRL_0); +} +#else +#define omap_early_clk_reset() {} +#endif int __init clk_init(void) { @@ -993,6 +1144,8 @@ int __init clk_init(void) const struct omap_clock_config *info; int crystal_type = 0; /* Default 12 MHz */ + omap_early_clk_reset(); + for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) { if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) { clk_register(*clkp); @@ -1023,9 +1176,42 @@ int __init clk_init(void) ck_ref.rate = 19200000; #endif + printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n", + omap_readw(ARM_SYSST), omap_readw(DPLL_CTL), + omap_readw(ARM_CKCTL)); + /* We want to be in syncronous scalable mode */ omap_writew(0x1000, ARM_SYSST); +#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER + /* Use values set by bootloader. Determine PLL rate and recalculate + * dependent clocks as if kernel had changed PLL or divisors. + */ + { + unsigned pll_ctl_val = omap_readw(DPLL_CTL); + + ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */ + if (pll_ctl_val & 0x10) { + /* PLL enabled, apply multiplier and divisor */ + if (pll_ctl_val & 0xf80) + ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7; + ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1; + } else { + /* PLL disabled, apply bypass divisor */ + switch (pll_ctl_val & 0xc) { + case 0: + break; + case 0x4: + ck_dpll1.rate /= 2; + break; + default: + ck_dpll1.rate /= 4; + break; + } + } + } + propagate_rate(&ck_dpll1); +#else /* Find the highest supported frequency and enable it */ if (select_table_rate(&virtual_ck_mpu, ~0)) { printk(KERN_ERR "System frequencies not set. Check your config.\n"); @@ -1034,12 +1220,13 @@ int __init clk_init(void) omap_writew(0x1005, ARM_CKCTL); ck_dpll1.rate = 60000000; propagate_rate(&ck_dpll1); - printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n", - ck_ref.rate, ck_dpll1.rate, arm_ck.rate); } - +#endif /* Cache rates for clocks connected to ck_ref (not dpll1) */ propagate_rate(&ck_ref); + printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n", + ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10, + ck_dpll1.rate, arm_ck.rate); #ifdef CONFIG_MACH_OMAP_PERSEUS2 /* Select slicer output as OMAP input clock */ @@ -1074,3 +1261,63 @@ int __init clk_init(void) return 0; } + + +#ifdef CONFIG_OMAP_RESET_CLOCKS + +static int __init omap_late_clk_reset(void) +{ + /* Turn off all unused clocks */ + struct clk *p; + __u32 regval32; + + omap_writew(0, SOFT_REQ_REG); + omap_writew(0, SOFT_REQ_REG2); + + list_for_each_entry(p, &clocks, node) { + if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) || + p->enable_reg == 0) + continue; + + /* Assume no DSP clocks have been activated by bootloader */ + if (p->flags & DSP_DOMAIN_CLOCK) + continue; + + /* Is the clock already disabled? */ + if (p->flags & ENABLE_REG_32BIT) { + if (p->flags & VIRTUAL_IO_ADDRESS) + regval32 = __raw_readl(p->enable_reg); + else + regval32 = omap_readl(p->enable_reg); + } else { + if (p->flags & VIRTUAL_IO_ADDRESS) + regval32 = __raw_readw(p->enable_reg); + else + regval32 = omap_readw(p->enable_reg); + } + + if ((regval32 & (1 << p->enable_bit)) == 0) + continue; + + /* FIXME: This clock seems to be necessary but no-one + * has asked for its activation. */ + if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera + || p == &ck_dpll1out // FIX: SoSSI, SSR + || p == &arm_gpio_ck // FIX: GPIO code for 1510 + ) { + printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n", + p->name); + continue; + } + + printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name); + __clk_disable(p); + printk(" done\n"); + } + + return 0; +} + +late_initcall(omap_late_clk_reset); + +#endif diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/plat-omap/clock.h index 08c0ddde183..a89e1e8c251 100644 --- a/arch/arm/mach-omap/clock.h +++ b/arch/arm/plat-omap/clock.h @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/clock.h + * linux/arch/arm/plat-omap/clock.h * * Copyright (C) 2004 Nokia corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> @@ -52,6 +52,8 @@ struct mpu_rate { #define CLOCK_IN_OMAP16XX 64 #define CLOCK_IN_OMAP1510 128 #define CLOCK_IN_OMAP730 256 +#define DSP_DOMAIN_CLOCK 512 +#define VIRTUAL_IO_ADDRESS 1024 /* ARM_CKCTL bit shifts */ #define CKCTL_PERDIV_OFFSET 0 @@ -63,6 +65,8 @@ struct mpu_rate { /*#define ARM_TIMXO 12*/ #define EN_DSPCK 13 /*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */ +/* DSP_CKCTL bit shifts */ +#define CKCTL_DSPPERDIV_OFFSET 0 /* ARM_IDLECT1 bit shifts */ /*#define IDLWDT_ARM 0*/ @@ -96,6 +100,9 @@ struct mpu_rate { #define EN_TC1_CK 2 #define EN_TC2_CK 4 +/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */ +#define EN_DSPTIMCK 5 + /* Various register defines for clock controls scattered around OMAP chip */ #define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */ #define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */ @@ -103,7 +110,8 @@ struct mpu_rate { #define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */ #define SWD_CLK_DIV_CTRL_SEL 0xfffe0874 #define COM_CLK_DIV_CTRL_SEL 0xfffe0878 - +#define SOFT_REQ_REG 0xfffe0834 +#define SOFT_REQ_REG2 0xfffe0880 int clk_register(struct clk *clk); void clk_unregister(struct clk *clk); diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c new file mode 100644 index 00000000000..ea967a8f6ce --- /dev/null +++ b/arch/arm/plat-omap/common.c @@ -0,0 +1,135 @@ +/* + * linux/arch/arm/plat-omap/common.c + * + * Code common to all OMAP machines. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/console.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> + +#include <asm/hardware.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/mach/map.h> +#include <asm/hardware/clock.h> +#include <asm/io.h> +#include <asm/mach-types.h> + +#include <asm/arch/board.h> +#include <asm/arch/mux.h> +#include <asm/arch/fpga.h> + +#include "clock.h" + +#define NO_LENGTH_CHECK 0xffffffff + +extern int omap_bootloader_tag_len; +extern u8 omap_bootloader_tag[]; + +struct omap_board_config_kernel *omap_board_config; +int omap_board_config_size = 0; + +static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out) +{ + struct omap_board_config_kernel *kinfo = NULL; + int i; + +#ifdef CONFIG_OMAP_BOOT_TAG + struct omap_board_config_entry *info = NULL; + + if (omap_bootloader_tag_len > 4) + info = (struct omap_board_config_entry *) omap_bootloader_tag; + while (info != NULL) { + u8 *next; + + if (info->tag == tag) { + if (skip == 0) + break; + skip--; + } + + if ((info->len & 0x03) != 0) { + /* We bail out to avoid an alignment fault */ + printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n", + info->len, info->tag); + return NULL; + } + next = (u8 *) info + sizeof(*info) + info->len; + if (next >= omap_bootloader_tag + omap_bootloader_tag_len) + info = NULL; + else + info = (struct omap_board_config_entry *) next; + } + if (info != NULL) { + /* Check the length as a lame attempt to check for + * binary inconsistancy. */ + if (len != NO_LENGTH_CHECK) { + /* Word-align len */ + if (len & 0x03) + len = (len + 3) & ~0x03; + if (info->len != len) { + printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n", + tag, len, info->len); + return NULL; + } + } + if (len_out != NULL) + *len_out = info->len; + return info->data; + } +#endif + /* Try to find the config from the board-specific structures + * in the kernel. */ + for (i = 0; i < omap_board_config_size; i++) { + if (omap_board_config[i].tag == tag) { + kinfo = &omap_board_config[i]; + break; + } + } + if (kinfo == NULL) + return NULL; + return kinfo->data; +} + +const void *__omap_get_config(u16 tag, size_t len, int nr) +{ + return get_config(tag, len, nr, NULL); +} +EXPORT_SYMBOL(__omap_get_config); + +const void *omap_get_var_config(u16 tag, size_t *len) +{ + return get_config(tag, NO_LENGTH_CHECK, 0, len); +} +EXPORT_SYMBOL(omap_get_var_config); + +static int __init omap_add_serial_console(void) +{ + const struct omap_serial_console_config *info; + + info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE, + struct omap_serial_console_config); + if (info != NULL && info->console_uart) { + static char speed[11], *opt = NULL; + + if (info->console_speed) { + snprintf(speed, sizeof(speed), "%u", info->console_speed); + opt = speed; + } + return add_preferred_console("ttyS", info->console_uart - 1, opt); + } + return 0; +} +console_initcall(omap_add_serial_console); diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c new file mode 100644 index 00000000000..409aac2c4b9 --- /dev/null +++ b/arch/arm/plat-omap/cpu-omap.c @@ -0,0 +1,128 @@ +/* + * linux/arch/arm/plat-omap/cpu-omap.c + * + * CPU frequency scaling for OMAP + * + * Copyright (C) 2005 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> + +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <asm/hardware/clock.h> + +/* TODO: Add support for SDRAM timing changes */ + +int omap_verify_speed(struct cpufreq_policy *policy) +{ + struct clk * mpu_clk; + + if (policy->cpu) + return -EINVAL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + mpu_clk = clk_get(NULL, "mpu"); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; + policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + clk_put(mpu_clk); + + return 0; +} + +unsigned int omap_getspeed(unsigned int cpu) +{ + struct clk * mpu_clk; + unsigned long rate; + + if (cpu) + return 0; + + mpu_clk = clk_get(NULL, "mpu"); + if (IS_ERR(mpu_clk)) + return 0; + rate = clk_get_rate(mpu_clk) / 1000; + clk_put(mpu_clk); + + return rate; +} + +static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct clk * mpu_clk; + struct cpufreq_freqs freqs; + int ret = 0; + + mpu_clk = clk_get(NULL, "mpu"); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + freqs.old = omap_getspeed(0); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + ret = clk_set_rate(mpu_clk, target_freq * 1000); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + clk_put(mpu_clk); + + return ret; +} + +static int __init omap_cpu_init(struct cpufreq_policy *policy) +{ + struct clk * mpu_clk; + + mpu_clk = clk_get(NULL, "mpu"); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + if (policy->cpu != 0) + return -EINVAL; + policy->cur = policy->min = policy->max = omap_getspeed(0); + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; + policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, 216000000) / 1000; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + clk_put(mpu_clk); + + return 0; +} + +static struct cpufreq_driver omap_driver = { + .flags = CPUFREQ_STICKY, + .verify = omap_verify_speed, + .target = omap_target, + .get = omap_getspeed, + .init = omap_cpu_init, + .name = "omap", +}; + +static int __init omap_cpufreq_init(void) +{ + return cpufreq_register_driver(&omap_driver); +} + +arch_initcall(omap_cpufreq_init); diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/plat-omap/dma.c index 7a9ebe80d6f..c0a5c2fa42b 100644 --- a/arch/arm/mach-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/omap/dma.c + * linux/arch/arm/plat-omap/dma.c * * Copyright (C) 2003 Nokia Corporation * Author: Juha Yrjölä <juha.yrjola@nokia.com> @@ -794,10 +794,6 @@ static void set_b1_regs(void) w = omap_readw(OMAP1610_DMA_LCD_CTRL); /* Always set the source port as SDRAM for now*/ w &= ~(0x03 << 6); - if (lcd_dma.ext_ctrl) - w |= 1 << 8; - else - w &= ~(1 << 8); if (lcd_dma.callback != NULL) w |= 1 << 1; /* Block interrupt enable */ else @@ -889,9 +885,15 @@ void omap_enable_lcd_dma(void) */ if (enable_1510_mode || !lcd_dma.ext_ctrl) return; + + w = omap_readw(OMAP1610_DMA_LCD_CTRL); + w |= 1 << 8; + omap_writew(w, OMAP1610_DMA_LCD_CTRL); + w = omap_readw(OMAP1610_DMA_LCD_CCR); w |= 1 << 7; omap_writew(w, OMAP1610_DMA_LCD_CCR); + lcd_dma.active = 1; } @@ -922,10 +924,19 @@ void omap_setup_lcd_dma(void) void omap_stop_lcd_dma(void) { + u16 w; + lcd_dma.active = 0; - if (!enable_1510_mode && lcd_dma.ext_ctrl) - omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7), - OMAP1610_DMA_LCD_CCR); + if (enable_1510_mode || !lcd_dma.ext_ctrl) + return; + + w = omap_readw(OMAP1610_DMA_LCD_CCR); + w &= ~(1 << 7); + omap_writew(w, OMAP1610_DMA_LCD_CCR); + + w = omap_readw(OMAP1610_DMA_LCD_CTRL); + w &= ~(1 << 8); + omap_writew(w, OMAP1610_DMA_LCD_CTRL); } /* @@ -972,6 +983,25 @@ dma_addr_t omap_get_dma_dst_pos(int lch) (OMAP_DMA_CDSA_U(lch) << 16)); } +int omap_dma_running(void) +{ + int lch; + + /* Check if LCD DMA is running */ + if (cpu_is_omap16xx()) + if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN) + return 1; + + for (lch = 0; lch < dma_chan_count; lch++) { + u16 w; + + w = omap_readw(OMAP_DMA_CCR(lch)); + if (w & OMAP_DMA_CCR_EN) + return 1; + } + return 0; +} + static int __init omap_init_dma(void) { int ch, r; diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/plat-omap/gpio.c index 9045dfd469a..1c85b4e536c 100644 --- a/arch/arm/mach-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/gpio.c + * linux/arch/arm/plat-omap/gpio.c * * Support functions for OMAP GPIO * diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 7c4ad771309..43567d5eddd 100644 --- a/arch/arm/mach-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/omap/mcbsp.c + * linux/arch/arm/plat-omap/mcbsp.c * * Copyright (C) 2004 Nokia Corporation * Author: Samuel Ortiz <samuel.ortiz@nokia.com> @@ -66,6 +66,7 @@ struct omap_mcbsp { static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; static struct clk *mcbsp_dsp_ck = 0; static struct clk *mcbsp_api_ck = 0; +static struct clk *mcbsp_dspxor_ck = 0; static void omap_mcbsp_dump_reg(u8 id) @@ -175,7 +176,7 @@ static int omap_mcbsp_check(unsigned int id) return 0; } - if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + if (cpu_is_omap1510() || cpu_is_omap16xx()) { if (id > OMAP_MAX_MCBSP_COUNT) { printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); return -1; @@ -191,15 +192,12 @@ static int omap_mcbsp_check(unsigned int id) static void omap_mcbsp_dsp_request(void) { - if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { - omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)), - ARM_RSTCT1); - clk_enable(mcbsp_dsp_ck); - clk_enable(mcbsp_api_ck); + if (cpu_is_omap1510() || cpu_is_omap16xx()) { + clk_use(mcbsp_dsp_ck); + clk_use(mcbsp_api_ck); /* enable 12MHz clock to mcbsp 1 & 3 */ - __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK), - DSP_IDLECT2); + clk_use(mcbsp_dspxor_ck); __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1, DSP_RSTCT2); } @@ -207,10 +205,13 @@ static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_free(void) { - /* Useless for now */ + if (cpu_is_omap1510() || cpu_is_omap16xx()) { + clk_unuse(mcbsp_dspxor_ck); + clk_unuse(mcbsp_dsp_ck); + clk_unuse(mcbsp_api_ck); + } } - int omap_mcbsp_request(unsigned int id) { int err; @@ -350,6 +351,73 @@ void omap_mcbsp_stop(unsigned int id) } +/* polled mcbsp i/o operations */ +int omap_mcbsp_pollwrite(unsigned int id, u16 buf) +{ + u32 base = mcbsp[id].io_base; + writew(buf, base + OMAP_MCBSP_REG_DXR1); + /* if frame sync error - clear the error */ + if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) { + /* clear error */ + writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR), + base + OMAP_MCBSP_REG_SPCR2); + /* resend */ + return -1; + } else { + /* wait for transmit confirmation */ + int attemps = 0; + while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) { + if (attemps++ > 1000) { + writew(readw(base + OMAP_MCBSP_REG_SPCR2) & + (~XRST), + base + OMAP_MCBSP_REG_SPCR2); + udelay(10); + writew(readw(base + OMAP_MCBSP_REG_SPCR2) | + (XRST), + base + OMAP_MCBSP_REG_SPCR2); + udelay(10); + printk(KERN_ERR + " Could not write to McBSP Register\n"); + return -2; + } + } + } + return 0; +} + +int omap_mcbsp_pollread(unsigned int id, u16 * buf) +{ + u32 base = mcbsp[id].io_base; + /* if frame sync error - clear the error */ + if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { + /* clear error */ + writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), + base + OMAP_MCBSP_REG_SPCR1); + /* resend */ + return -1; + } else { + /* wait for recieve confirmation */ + int attemps = 0; + while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { + if (attemps++ > 1000) { + writew(readw(base + OMAP_MCBSP_REG_SPCR1) & + (~RRST), + base + OMAP_MCBSP_REG_SPCR1); + udelay(10); + writew(readw(base + OMAP_MCBSP_REG_SPCR1) | + (RRST), + base + OMAP_MCBSP_REG_SPCR1); + udelay(10); + printk(KERN_ERR + " Could not read from McBSP Register\n"); + return -2; + } + } + } + *buf = readw(base + OMAP_MCBSP_REG_DRR1); + return 0; +} + /* * IRQ based word transmission. */ @@ -625,10 +693,15 @@ static int __init omap_mcbsp_init(void) return PTR_ERR(mcbsp_dsp_ck); } mcbsp_api_ck = clk_get(0, "api_ck"); - if (IS_ERR(mcbsp_dsp_ck)) { + if (IS_ERR(mcbsp_api_ck)) { printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n"); return PTR_ERR(mcbsp_api_ck); } + mcbsp_dspxor_ck = clk_get(0, "dspxor_ck"); + if (IS_ERR(mcbsp_dspxor_ck)) { + printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); + return PTR_ERR(mcbsp_dspxor_ck); + } #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { @@ -643,7 +716,7 @@ static int __init omap_mcbsp_init(void) } #endif #if defined(CONFIG_ARCH_OMAP16XX) - if (cpu_is_omap1610() || cpu_is_omap1710()) { + if (cpu_is_omap16xx()) { mcbsp_info = mcbsp_1610; mcbsp_count = ARRAY_SIZE(mcbsp_1610); } diff --git a/arch/arm/mach-omap/mux.c b/arch/arm/plat-omap/mux.c index bcf3c6e5ecd..ea7b955b9c8 100644 --- a/arch/arm/mach-omap/mux.c +++ b/arch/arm/plat-omap/mux.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/mux.c + * linux/arch/arm/plat-omap/mux.c * * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h * @@ -53,19 +53,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) return -EINVAL; } - cfg = ®_cfg_table[reg_cfg]; - - /* - * We do a pretty long section here with lock on, but pin muxing - * should only happen on driver init for each driver, so it's not time - * critical. - */ - spin_lock_irqsave(&mux_spin_lock, flags); + cfg = (reg_cfg_set *)®_cfg_table[reg_cfg]; /* Check the mux register in question */ if (cfg->mux_reg) { unsigned tmp1, tmp2; + spin_lock_irqsave(&mux_spin_lock, flags); reg_orig = omap_readl(cfg->mux_reg); /* The mux registers always seem to be 3 bits long */ @@ -80,11 +74,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) warn = 1; omap_writel(reg, cfg->mux_reg); + spin_unlock_irqrestore(&mux_spin_lock, flags); } /* Check for pull up or pull down selection on 1610 */ if (!cpu_is_omap1510()) { if (cfg->pu_pd_reg && cfg->pull_val) { + spin_lock_irqsave(&mux_spin_lock, flags); pu_pd_orig = omap_readl(cfg->pu_pd_reg); mask = 1 << cfg->pull_bit; @@ -100,11 +96,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) pu_pd = pu_pd_orig & ~mask; } omap_writel(pu_pd, cfg->pu_pd_reg); + spin_unlock_irqrestore(&mux_spin_lock, flags); } } /* Check for an associated pull down register */ if (cfg->pull_reg) { + spin_lock_irqsave(&mux_spin_lock, flags); pull_orig = omap_readl(cfg->pull_reg); mask = 1 << cfg->pull_bit; @@ -121,6 +119,7 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) } omap_writel(pull, cfg->pull_reg); + spin_unlock_irqrestore(&mux_spin_lock, flags); } if (warn) { @@ -149,8 +148,6 @@ omap_cfg_reg(const reg_cfg_t reg_cfg) } #endif - spin_unlock_irqrestore(&mux_spin_lock, flags); - #ifdef CONFIG_OMAP_MUX_ERRORS return warn ? -ETXTBSY : 0; #else diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c index c9ced134a75..1fb16f9edfd 100644 --- a/arch/arm/mach-omap/ocpi.c +++ b/arch/arm/plat-omap/ocpi.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/ocpi.c + * linux/arch/arm/plat-omap/ocpi.c * * Minimal OCP bus support for omap16xx * diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/plat-omap/pm.c index 6b03ccdc1e9..e6536b16c38 100644 --- a/arch/arm/mach-omap/pm.c +++ b/arch/arm/plat-omap/pm.c @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/pm.c + * linux/arch/arm/plat-omap/pm.c * * OMAP Power Management Routines * diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/plat-omap/sleep.S index 4d426d10582..279490ce772 100644 --- a/arch/arm/mach-omap/sleep.S +++ b/arch/arm/plat-omap/sleep.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap/sleep.S + * linux/arch/arm/plat-omap/sleep.S * * Low-level OMAP1510/1610 sleep/wakeUp support * diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/plat-omap/usb.c index fd483ff9f8f..25bc4a8dd76 100644 --- a/arch/arm/mach-omap/usb.c +++ b/arch/arm/plat-omap/usb.c @@ -1,5 +1,5 @@ /* - * arch/arm/mach-omap/usb.c -- platform level USB initialization + * arch/arm/plat-omap/usb.c -- platform level USB initialization * * Copyright (C) 2004 Texas Instruments, Inc. * @@ -326,7 +326,7 @@ static u64 ohci_dmamask = ~(u32)0; static struct resource ohci_resources[] = { { .start = OMAP_OHCI_BASE, - .end = OMAP_OHCI_BASE + 4096, + .end = OMAP_OHCI_BASE + 4096 - 1, .flags = IORESOURCE_MEM, }, { diff --git a/arch/frv/defconfig b/arch/frv/defconfig new file mode 100644 index 00000000000..b6e4ca5efb5 --- /dev/null +++ b/arch/frv/defconfig @@ -0,0 +1,627 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11.8 +# Fri May 13 17:16:03 2005 +# +CONFIG_FRV=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +# CONFIG_GENERIC_CALIBRATE_DELAY is not set +# CONFIG_GENERIC_HARDIRQS is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +# CONFIG_KOBJECT_UEVENT is not set +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Fujitsu FR-V system setup +# +CONFIG_MMU=y +CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FRV_DEFL_CACHE_WBACK is not set +# CONFIG_FRV_DEFL_CACHE_WBEHIND is not set +CONFIG_FRV_DEFL_CACHE_WTHRU=y +# CONFIG_FRV_DEFL_CACHE_DISABLED is not set + +# +# CPU core support +# +CONFIG_CPU_FR451=y +CONFIG_CPU_FR451_COMPILE=y +CONFIG_FRV_L1_CACHE_SHIFT=5 +CONFIG_MB93091_VDK=y +# CONFIG_MB93093_PDK is not set +CONFIG_MB93090_MB00=y +# CONFIG_MB93091_NO_MB is not set +# CONFIG_GPREL_DATA_8 is not set +CONFIG_GPREL_DATA_4=y +# CONFIG_GPREL_DATA_NONE is not set +CONFIG_PCI=y +# CONFIG_PCI_LEGACY_PROC is not set +# CONFIG_PCI_NAMES is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCMCIA is not set + +# +# Power management options +# +# CONFIG_PM is not set + +# +# Executable formats +# +# CONFIG_BINFMT_ELF is not set +CONFIG_BINFMT_ELF_FDPIC=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set + +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set +# CONFIG_FORK_CONNECTOR is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_IEEE80211 is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +# CONFIG_E100 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +CONFIG_NE2K_PCI=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SKGE is not set +# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_CHELSIO_T1 is not set +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +# CONFIG_INPUT is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISER4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_FRAME_POINTER is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_DEBUG_STACKOVERFLOW=y +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_GDBSTUB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 2203a9d2021..4553ffd94b1 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -435,6 +435,11 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c) if (c == &boot_cpu_data) sysenter_setup(); enable_sep_cpu(); + + if (c == &boot_cpu_data) + mtrr_bp_init(); + else + mtrr_ap_init(); } #ifdef CONFIG_X86_HT diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c index 96a75d04583..a2c33c1a46c 100644 --- a/arch/i386/kernel/cpu/intel.c +++ b/arch/i386/kernel/cpu/intel.c @@ -25,7 +25,7 @@ extern int trap_init_f00f_bug(void); /* * Alignment at which movsl is preferred for bulk memory copies. */ -struct movsl_mask movsl_mask; +struct movsl_mask movsl_mask __read_mostly; #endif void __devinit early_intel_workaround(struct cpuinfo_x86 *c) diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c index 64d91f73a0a..169ac8e0db6 100644 --- a/arch/i386/kernel/cpu/mtrr/generic.c +++ b/arch/i386/kernel/cpu/mtrr/generic.c @@ -67,13 +67,6 @@ void __init get_mtrr_state(void) mtrr_state.enabled = (lo & 0xc00) >> 10; } -/* Free resources associated with a struct mtrr_state */ -void __init finalize_mtrr_state(void) -{ - kfree(mtrr_state.var_ranges); - mtrr_state.var_ranges = NULL; -} - /* Some BIOS's are fucked and don't set all MTRRs the same! */ void __init mtrr_state_warn(void) { @@ -334,6 +327,9 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, */ { unsigned long flags; + struct mtrr_var_range *vr; + + vr = &mtrr_state.var_ranges[reg]; local_irq_save(flags); prepare_set(); @@ -342,11 +338,15 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, /* The invalid bit is kept in the mask, so we simply clear the relevant mask register to disable a range. */ mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0); + memset(vr, 0, sizeof(struct mtrr_var_range)); } else { - mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); - mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800, - (-size & size_and_mask) >> (32 - PAGE_SHIFT)); + vr->base_lo = base << PAGE_SHIFT | type; + vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT); + vr->mask_lo = -size << PAGE_SHIFT | 0x800; + vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT); + + mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi); + mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi); } post_set(); diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index d66b09e0c82..764cac64e21 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -332,6 +332,8 @@ int mtrr_add_page(unsigned long base, unsigned long size, error = -EINVAL; + /* No CPU hotplug when we change MTRR entries */ + lock_cpu_hotplug(); /* Search for existing MTRR */ down(&main_lock); for (i = 0; i < num_var_ranges; ++i) { @@ -372,6 +374,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, error = i; out: up(&main_lock); + unlock_cpu_hotplug(); return error; } @@ -461,6 +464,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) return -ENXIO; max = num_var_ranges; + /* No CPU hotplug when we change MTRR entries */ + lock_cpu_hotplug(); down(&main_lock); if (reg < 0) { /* Search for existing MTRR */ @@ -501,6 +506,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) error = reg; out: up(&main_lock); + unlock_cpu_hotplug(); return error; } /** @@ -544,21 +550,9 @@ static void __init init_ifs(void) centaur_init_mtrr(); } -static void __init init_other_cpus(void) -{ - if (use_intel()) - get_mtrr_state(); - - /* bring up the other processors */ - set_mtrr(~0U,0,0,0); - - if (use_intel()) { - finalize_mtrr_state(); - mtrr_state_warn(); - } -} - - +/* The suspend/resume methods are only for CPU without MTRR. CPU using generic + * MTRR driver doesn't require this + */ struct mtrr_value { mtrr_type ltype; unsigned long lbase; @@ -611,13 +605,13 @@ static struct sysdev_driver mtrr_sysdev_driver = { /** - * mtrr_init - initialize mtrrs on the boot CPU + * mtrr_bp_init - initialize mtrrs on the boot CPU * * This needs to be called early; before any of the other CPUs are * initialized (i.e. before smp_init()). * */ -static int __init mtrr_init(void) +void __init mtrr_bp_init(void) { init_ifs(); @@ -674,12 +668,48 @@ static int __init mtrr_init(void) if (mtrr_if) { set_num_var_ranges(); init_table(); - init_other_cpus(); - - return sysdev_driver_register(&cpu_sysdev_class, - &mtrr_sysdev_driver); + if (use_intel()) + get_mtrr_state(); } - return -ENXIO; } -subsys_initcall(mtrr_init); +void mtrr_ap_init(void) +{ + unsigned long flags; + + if (!mtrr_if || !use_intel()) + return; + /* + * Ideally we should hold main_lock here to avoid mtrr entries changed, + * but this routine will be called in cpu boot time, holding the lock + * breaks it. This routine is called in two cases: 1.very earily time + * of software resume, when there absolutely isn't mtrr entry changes; + * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to + * prevent mtrr entry changes + */ + local_irq_save(flags); + + mtrr_if->set_all(); + + local_irq_restore(flags); +} + +static int __init mtrr_init_finialize(void) +{ + if (!mtrr_if) + return 0; + if (use_intel()) + mtrr_state_warn(); + else { + /* The CPUs haven't MTRR and seemes not support SMP. They have + * specific drivers, we use a tricky method to support + * suspend/resume for them. + * TBD: is there any system with such CPU which supports + * suspend/resume? if no, we should remove the code. + */ + sysdev_driver_register(&cpu_sysdev_class, + &mtrr_sysdev_driver); + } + return 0; +} +subsys_initcall(mtrr_init_finialize); diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h index de135124559..99c9f268204 100644 --- a/arch/i386/kernel/cpu/mtrr/mtrr.h +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h @@ -91,7 +91,6 @@ extern struct mtrr_ops * mtrr_if; extern unsigned int num_var_ranges; -void finalize_mtrr_state(void); void mtrr_state_warn(void); char *mtrr_attrib_to_str(int x); void mtrr_wrmsr(unsigned, unsigned, unsigned); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index d66bf489a2e..8ac8e9fd561 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -68,21 +68,21 @@ EXPORT_SYMBOL(smp_num_siblings); #endif /* Package ID of each logical CPU */ -int phys_proc_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; +int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; EXPORT_SYMBOL(phys_proc_id); /* Core ID of each logical CPU */ -int cpu_core_id[NR_CPUS] = {[0 ... NR_CPUS-1] = BAD_APICID}; +int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; EXPORT_SYMBOL(cpu_core_id); -cpumask_t cpu_sibling_map[NR_CPUS]; +cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_sibling_map); -cpumask_t cpu_core_map[NR_CPUS]; +cpumask_t cpu_core_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_core_map); /* bitmap of online cpus */ -cpumask_t cpu_online_map; +cpumask_t cpu_online_map __read_mostly; EXPORT_SYMBOL(cpu_online_map); cpumask_t cpu_callin_map; @@ -100,7 +100,7 @@ static int __devinitdata tsc_sync_disabled; struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; EXPORT_SYMBOL(cpu_data); -u8 x86_cpu_to_apicid[NR_CPUS] = +u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0xff }; EXPORT_SYMBOL(x86_cpu_to_apicid); @@ -550,10 +550,10 @@ extern struct { #ifdef CONFIG_NUMA /* which logical CPUs are on which nodes */ -cpumask_t node_2_cpu_mask[MAX_NUMNODES] = +cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly = { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE }; /* which node each logical CPU is on */ -int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 }; +int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 }; EXPORT_SYMBOL(cpu_2_node); /* set up a mapping between cpu and node. */ @@ -581,7 +581,7 @@ static inline void unmap_cpu_to_node(int cpu) #endif /* CONFIG_NUMA */ -u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; +u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; static void map_cpu_to_logical_apicid(void) { diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 2854c357377..0ee9dee8af0 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -91,7 +91,7 @@ EXPORT_SYMBOL(rtc_lock); DEFINE_SPINLOCK(i8253_lock); EXPORT_SYMBOL(i8253_lock); -struct timer_opts *cur_timer = &timer_none; +struct timer_opts *cur_timer __read_mostly = &timer_none; /* * This is a special lock that is owned by the CPU and holds the index diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c index d766e0963ac..ef8dac5dd33 100644 --- a/arch/i386/kernel/timers/timer_hpet.c +++ b/arch/i386/kernel/timers/timer_hpet.c @@ -18,7 +18,7 @@ #include "mach_timer.h" #include <asm/hpet.h> -static unsigned long hpet_usec_quotient; /* convert hpet clks to usec */ +static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */ static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */ static unsigned long hpet_last; /* hpet counter value at last tick*/ static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ @@ -180,7 +180,7 @@ static int __init init_hpet(char* override) /************************************************************/ /* tsc timer_opts struct */ -static struct timer_opts timer_hpet = { +static struct timer_opts timer_hpet __read_mostly = { .name = "hpet", .mark_offset = mark_offset_hpet, .get_offset = get_offset_hpet, diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 7e01a528a83..761972f8cb6 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S @@ -57,6 +57,9 @@ SECTIONS *(.data.cacheline_aligned) } + /* rarely changed data like cpu maps */ + . = ALIGN(32); + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } _edata = .; /* End of data section */ . = ALIGN(THREAD_SIZE); /* init_task */ diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 6b25afc933b..f379b8d6755 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -228,7 +228,8 @@ EXPORT_SYMBOL(ioremap_nocache); void iounmap(volatile void __iomem *addr) { struct vm_struct *p; - if ((void __force *) addr <= high_memory) + + if ((void __force *)addr <= high_memory) return; /* @@ -241,9 +242,10 @@ void iounmap(volatile void __iomem *addr) return; write_lock(&vmlist_lock); - p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); + p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr)); if (!p) { printk(KERN_WARNING "iounmap: bad address %p\n", addr); + dump_stack(); goto out_unlock; } diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 0e6b45b6125..c547c1af6fa 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -137,6 +137,7 @@ void __restore_processor_state(struct saved_context *ctxt) fix_processor_context(); do_fpu_end(); + mtrr_ap_init(); } void restore_processor_state(void) diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index b2e2f6509eb..e1fb68ddec2 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_IA64_PALINFO) += palinfo.o obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o domain.o +obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o obj-$(CONFIG_IA64_CYCLONE) += cyclone.o obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index cda06f88c66..542256e98e6 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -640,9 +640,11 @@ acpi_boot_init (void) if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id()) node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu]; } - build_cpu_to_node_map(); # endif #endif +#ifdef CONFIG_ACPI_NUMA + build_cpu_to_node_map(); +#endif /* Make boot-up look pretty */ printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus); return 0; diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c new file mode 100644 index 00000000000..a68ce667809 --- /dev/null +++ b/arch/ia64/kernel/numa.c @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ia64 kernel NUMA specific stuff + * + * Copyright (C) 2002 Erich Focht <efocht@ess.nec.de> + * Copyright (C) 2004 Silicon Graphics, Inc. + * Jesse Barnes <jbarnes@sgi.com> + */ +#include <linux/config.h> +#include <linux/topology.h> +#include <linux/module.h> +#include <asm/processor.h> +#include <asm/smp.h> + +u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_to_node_map); + +cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; + +/** + * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays + * + * Build cpu to node mapping and initialize the per node cpu masks using + * info from the node_cpuid array handed to us by ACPI. + */ +void __init build_cpu_to_node_map(void) +{ + int cpu, i, node; + + for(node=0; node < MAX_NUMNODES; node++) + cpus_clear(node_to_cpu_mask[node]); + + for(cpu = 0; cpu < NR_CPUS; ++cpu) { + node = -1; + for (i = 0; i < NR_CPUS; ++i) + if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) { + node = node_cpuid[i].nid; + break; + } + cpu_to_node_map[cpu] = (node >= 0) ? node : 0; + if (node >= 0) + cpu_set(cpu, node_to_cpu_mask[node]); + } +} diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index edd9f07860b..b8a0a7d257a 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -143,6 +143,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); psr->mfh = 0; /* drop signal handler's fph contents... */ + preempt_disable(); if (psr->dfh) ia64_drop_fpu(current); else { @@ -150,6 +151,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr) __ia64_load_fpu(current->thread.fph); ia64_set_local_fpu_owner(current); } + preempt_enable(); } return err; } diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 623b0a54670..7d72c0d872b 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -525,47 +525,6 @@ smp_build_cpu_map (void) } } -#ifdef CONFIG_NUMA - -/* on which node is each logical CPU (one cacheline even for 64 CPUs) */ -u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned; -EXPORT_SYMBOL(cpu_to_node_map); -/* which logical CPUs are on which nodes */ -cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned; - -/* - * Build cpu to node mapping and initialize the per node cpu masks. - */ -void __init -build_cpu_to_node_map (void) -{ - int cpu, i, node; - - for(node=0; node<MAX_NUMNODES; node++) - cpus_clear(node_to_cpu_mask[node]); - for(cpu = 0; cpu < NR_CPUS; ++cpu) { - /* - * All Itanium NUMA platforms I know use ACPI, so maybe we - * can drop this ifdef completely. [EF] - */ -#ifdef CONFIG_ACPI_NUMA - node = -1; - for (i = 0; i < NR_CPUS; ++i) - if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) { - node = node_cpuid[i].nid; - break; - } -#else -# error Fixme: Dunno how to build CPU-to-node map. -#endif - cpu_to_node_map[cpu] = (node >= 0) ? node : 0; - if (node >= 0) - cpu_set(cpu, node_to_cpu_mask[node]); - } -} - -#endif /* CONFIG_NUMA */ - /* * Cycle through the APs sending Wakeup IPIs to boot each. */ diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index e7e520d90f0..4440c8343fa 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -90,14 +90,16 @@ die (const char *str, struct pt_regs *regs, long err) .lock_owner_depth = 0 }; static int die_counter; + int cpu = get_cpu(); - if (die.lock_owner != smp_processor_id()) { + if (die.lock_owner != cpu) { console_verbose(); spin_lock_irq(&die.lock); - die.lock_owner = smp_processor_id(); + die.lock_owner = cpu; die.lock_owner_depth = 0; bust_spinlocks(1); } + put_cpu(); if (++die.lock_owner_depth < 3) { printk("%s[%d]: %s %ld [%d]\n", diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index f3fd528ead3..b5c90e54819 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -44,150 +44,7 @@ struct early_node_data { }; static struct early_node_data mem_data[MAX_NUMNODES] __initdata; - -/** - * reassign_cpu_only_nodes - called from find_memory to move CPU-only nodes to a memory node - * - * This function will move nodes with only CPUs (no memory) - * to a node with memory which is at the minimum numa_slit distance. - * Any reassigments will result in the compression of the nodes - * and renumbering the nid values where appropriate. - * The static declarations below are to avoid large stack size which - * makes the code not re-entrant. - */ -static void __init reassign_cpu_only_nodes(void) -{ - struct node_memblk_s *p; - int i, j, k, nnode, nid, cpu, cpunid, pxm; - u8 cslit, slit; - static DECLARE_BITMAP(nodes_with_mem, MAX_NUMNODES) __initdata; - static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata; - static int node_flip[MAX_NUMNODES] __initdata; - static int old_nid_map[NR_CPUS] __initdata; - - for (nnode = 0, p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++) - if (!test_bit(p->nid, (void *) nodes_with_mem)) { - set_bit(p->nid, (void *) nodes_with_mem); - nnode++; - } - - /* - * All nids with memory. - */ - if (nnode == num_online_nodes()) - return; - - /* - * Change nids and attempt to migrate CPU-only nodes - * to the best numa_slit (closest neighbor) possible. - * For reassigned CPU nodes a nid can't be arrived at - * until after this loop because the target nid's new - * identity might not have been established yet. So - * new nid values are fabricated above num_online_nodes() and - * mapped back later to their true value. - */ - /* MCD - This code is a bit complicated, but may be unnecessary now. - * We can now handle much more interesting node-numbering. - * The old requirement that 0 <= nid <= numnodes <= MAX_NUMNODES - * and that there be no holes in the numbering 0..numnodes - * has become simply 0 <= nid <= MAX_NUMNODES. - */ - nid = 0; - for_each_online_node(i) { - if (test_bit(i, (void *) nodes_with_mem)) { - /* - * Save original nid value for numa_slit - * fixup and node_cpuid reassignments. - */ - node_flip[nid] = i; - - if (i == nid) { - nid++; - continue; - } - - for (p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++) - if (p->nid == i) - p->nid = nid; - - cpunid = nid; - nid++; - } else - cpunid = MAX_NUMNODES; - - for (cpu = 0; cpu < NR_CPUS; cpu++) - if (node_cpuid[cpu].nid == i) { - /* - * For nodes not being reassigned just - * fix the cpu's nid and reverse pxm map - */ - if (cpunid < MAX_NUMNODES) { - pxm = nid_to_pxm_map[i]; - pxm_to_nid_map[pxm] = - node_cpuid[cpu].nid = cpunid; - continue; - } - - /* - * For nodes being reassigned, find best node by - * numa_slit information and then make a temporary - * nid value based on current nid and num_online_nodes(). - */ - slit = 0xff; - k = 2*num_online_nodes(); - for_each_online_node(j) { - if (i == j) - continue; - else if (test_bit(j, (void *) nodes_with_mem)) { - cslit = numa_slit[i * num_online_nodes() + j]; - if (cslit < slit) { - k = num_online_nodes() + j; - slit = cslit; - } - } - } - - /* save old nid map so we can update the pxm */ - old_nid_map[cpu] = node_cpuid[cpu].nid; - node_cpuid[cpu].nid = k; - } - } - - /* - * Fixup temporary nid values for CPU-only nodes. - */ - for (cpu = 0; cpu < NR_CPUS; cpu++) - if (node_cpuid[cpu].nid == (2*num_online_nodes())) { - pxm = nid_to_pxm_map[old_nid_map[cpu]]; - pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = nnode - 1; - } else { - for (i = 0; i < nnode; i++) { - if (node_flip[i] != (node_cpuid[cpu].nid - num_online_nodes())) - continue; - - pxm = nid_to_pxm_map[old_nid_map[cpu]]; - pxm_to_nid_map[pxm] = node_cpuid[cpu].nid = i; - break; - } - } - - /* - * Fix numa_slit by compressing from larger - * nid array to reduced nid array. - */ - for (i = 0; i < nnode; i++) - for (j = 0; j < nnode; j++) - numa_slit_fix[i * nnode + j] = - numa_slit[node_flip[i] * num_online_nodes() + node_flip[j]]; - - memcpy(numa_slit, numa_slit_fix, sizeof (numa_slit)); - - nodes_clear(node_online_map); - for (i = 0; i < nnode; i++) - node_set_online(i); - - return; -} +static nodemask_t memory_less_mask __initdata; /* * To prevent cache aliasing effects, align per-node structures so that they @@ -233,44 +90,101 @@ static int __init build_node_maps(unsigned long start, unsigned long len, } /** - * early_nr_phys_cpus_node - return number of physical cpus on a given node + * early_nr_cpus_node - return number of cpus on a given node * @node: node to check * - * Count the number of physical cpus on @node. These are cpus that actually - * exist. We can't use nr_cpus_node() yet because + * Count the number of cpus on @node. We can't use nr_cpus_node() yet because * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been - * called yet. + * called yet. Note that node 0 will also count all non-existent cpus. */ -static int early_nr_phys_cpus_node(int node) +static int __init early_nr_cpus_node(int node) { int cpu, n = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) if (node == node_cpuid[cpu].nid) - if ((cpu == 0) || node_cpuid[cpu].phys_id) - n++; + n++; return n; } +/** + * compute_pernodesize - compute size of pernode data + * @node: the node id. + */ +static unsigned long __init compute_pernodesize(int node) +{ + unsigned long pernodesize = 0, cpus; + + cpus = early_nr_cpus_node(node); + pernodesize += PERCPU_PAGE_SIZE * cpus; + pernodesize += node * L1_CACHE_BYTES; + pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t)); + pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); + pernodesize = PAGE_ALIGN(pernodesize); + return pernodesize; +} /** - * early_nr_cpus_node - return number of cpus on a given node - * @node: node to check + * per_cpu_node_setup - setup per-cpu areas on each node + * @cpu_data: per-cpu area on this node + * @node: node to setup * - * Count the number of cpus on @node. We can't use nr_cpus_node() yet because - * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been - * called yet. Note that node 0 will also count all non-existent cpus. + * Copy the static per-cpu data into the region we just set aside and then + * setup __per_cpu_offset for each CPU on this node. Return a pointer to + * the end of the area. */ -static int early_nr_cpus_node(int node) +static void *per_cpu_node_setup(void *cpu_data, int node) { - int cpu, n = 0; +#ifdef CONFIG_SMP + int cpu; - for (cpu = 0; cpu < NR_CPUS; cpu++) - if (node == node_cpuid[cpu].nid) - n++; + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (node == node_cpuid[cpu].nid) { + memcpy(__va(cpu_data), __phys_per_cpu_start, + __per_cpu_end - __per_cpu_start); + __per_cpu_offset[cpu] = (char*)__va(cpu_data) - + __per_cpu_start; + cpu_data += PERCPU_PAGE_SIZE; + } + } +#endif + return cpu_data; +} - return n; +/** + * fill_pernode - initialize pernode data. + * @node: the node id. + * @pernode: physical address of pernode data + * @pernodesize: size of the pernode data + */ +static void __init fill_pernode(int node, unsigned long pernode, + unsigned long pernodesize) +{ + void *cpu_data; + int cpus = early_nr_cpus_node(node); + struct bootmem_data *bdp = &mem_data[node].bootmem_data; + + mem_data[node].pernode_addr = pernode; + mem_data[node].pernode_size = pernodesize; + memset(__va(pernode), 0, pernodesize); + + cpu_data = (void *)pernode; + pernode += PERCPU_PAGE_SIZE * cpus; + pernode += node * L1_CACHE_BYTES; + + mem_data[node].pgdat = __va(pernode); + pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); + + mem_data[node].node_data = __va(pernode); + pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); + + mem_data[node].pgdat->bdata = bdp; + pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); + + cpu_data = per_cpu_node_setup(cpu_data, node); + + return; } /** @@ -304,9 +218,8 @@ static int early_nr_cpus_node(int node) static int __init find_pernode_space(unsigned long start, unsigned long len, int node) { - unsigned long epfn, cpu, cpus, phys_cpus; + unsigned long epfn; unsigned long pernodesize = 0, pernode, pages, mapsize; - void *cpu_data; struct bootmem_data *bdp = &mem_data[node].bootmem_data; epfn = (start + len) >> PAGE_SHIFT; @@ -329,49 +242,12 @@ static int __init find_pernode_space(unsigned long start, unsigned long len, * Calculate total size needed, incl. what's necessary * for good alignment and alias prevention. */ - cpus = early_nr_cpus_node(node); - phys_cpus = early_nr_phys_cpus_node(node); - pernodesize += PERCPU_PAGE_SIZE * cpus; - pernodesize += node * L1_CACHE_BYTES; - pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t)); - pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); - pernodesize = PAGE_ALIGN(pernodesize); + pernodesize = compute_pernodesize(node); pernode = NODEDATA_ALIGN(start, node); /* Is this range big enough for what we want to store here? */ - if (start + len > (pernode + pernodesize + mapsize)) { - mem_data[node].pernode_addr = pernode; - mem_data[node].pernode_size = pernodesize; - memset(__va(pernode), 0, pernodesize); - - cpu_data = (void *)pernode; - pernode += PERCPU_PAGE_SIZE * cpus; - pernode += node * L1_CACHE_BYTES; - - mem_data[node].pgdat = __va(pernode); - pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); - - mem_data[node].node_data = __va(pernode); - pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data)); - - mem_data[node].pgdat->bdata = bdp; - pernode += L1_CACHE_ALIGN(sizeof(pg_data_t)); - - /* - * Copy the static per-cpu data into the region we - * just set aside and then setup __per_cpu_offset - * for each CPU on this node. - */ - for (cpu = 0; cpu < NR_CPUS; cpu++) { - if (node == node_cpuid[cpu].nid) { - memcpy(__va(cpu_data), __phys_per_cpu_start, - __per_cpu_end - __per_cpu_start); - __per_cpu_offset[cpu] = (char*)__va(cpu_data) - - __per_cpu_start; - cpu_data += PERCPU_PAGE_SIZE; - } - } - } + if (start + len > (pernode + pernodesize + mapsize)) + fill_pernode(node, pernode, pernodesize); return 0; } @@ -411,6 +287,9 @@ static void __init reserve_pernode_space(void) for_each_online_node(node) { pg_data_t *pdp = mem_data[node].pgdat; + if (node_isset(node, memory_less_mask)) + continue; + bdp = pdp->bdata; /* First the bootmem_map itself */ @@ -436,8 +315,8 @@ static void __init reserve_pernode_space(void) */ static void __init initialize_pernode_data(void) { - int cpu, node; pg_data_t *pgdat_list[MAX_NUMNODES]; + int cpu, node; for_each_online_node(node) pgdat_list[node] = mem_data[node].pgdat; @@ -447,12 +326,99 @@ static void __init initialize_pernode_data(void) memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list, sizeof(pgdat_list)); } - +#ifdef CONFIG_SMP /* Set the node_data pointer for each per-cpu struct */ for (cpu = 0; cpu < NR_CPUS; cpu++) { node = node_cpuid[cpu].nid; per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data; } +#else + { + struct cpuinfo_ia64 *cpu0_cpu_info; + cpu = 0; + node = node_cpuid[cpu].nid; + cpu0_cpu_info = (struct cpuinfo_ia64 *)(__phys_per_cpu_start + + ((char *)&per_cpu__cpu_info - __per_cpu_start)); + cpu0_cpu_info->node_data = mem_data[node].node_data; + } +#endif /* CONFIG_SMP */ +} + +/** + * memory_less_node_alloc - * attempt to allocate memory on the best NUMA slit + * node but fall back to any other node when __alloc_bootmem_node fails + * for best. + * @nid: node id + * @pernodesize: size of this node's pernode data + * @align: alignment to use for this node's pernode data + */ +static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize, + unsigned long align) +{ + void *ptr = NULL; + u8 best = 0xff; + int bestnode = -1, node; + + for_each_online_node(node) { + if (node_isset(node, memory_less_mask)) + continue; + else if (node_distance(nid, node) < best) { + best = node_distance(nid, node); + bestnode = node; + } + } + + ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat, + pernodesize, align, __pa(MAX_DMA_ADDRESS)); + + if (!ptr) + panic("NO memory for memory less node\n"); + return ptr; +} + +/** + * pgdat_insert - insert the pgdat into global pgdat_list + * @pgdat: the pgdat for a node. + */ +static void __init pgdat_insert(pg_data_t *pgdat) +{ + pg_data_t *prev = NULL, *next; + + for_each_pgdat(next) + if (pgdat->node_id < next->node_id) + break; + else + prev = next; + + if (prev) { + prev->pgdat_next = pgdat; + pgdat->pgdat_next = next; + } else { + pgdat->pgdat_next = pgdat_list; + pgdat_list = pgdat; + } + + return; +} + +/** + * memory_less_nodes - allocate and initialize CPU only nodes pernode + * information. + */ +static void __init memory_less_nodes(void) +{ + unsigned long pernodesize; + void *pernode; + int node; + + for_each_node_mask(node, memory_less_mask) { + pernodesize = compute_pernodesize(node); + pernode = memory_less_node_alloc(node, pernodesize, + (node) ? (node * PERCPU_PAGE_SIZE) : (1024*1024)); + fill_pernode(node, __pa(pernode), pernodesize); + } + + return; } /** @@ -472,16 +438,19 @@ void __init find_memory(void) node_set_online(0); } + nodes_or(memory_less_mask, memory_less_mask, node_online_map); min_low_pfn = -1; max_low_pfn = 0; - if (num_online_nodes() > 1) - reassign_cpu_only_nodes(); - /* These actually end up getting called by call_pernode_memory() */ efi_memmap_walk(filter_rsvd_memory, build_node_maps); efi_memmap_walk(filter_rsvd_memory, find_pernode_space); + for_each_online_node(node) + if (mem_data[node].bootmem_data.node_low_pfn) { + node_clear(node, memory_less_mask); + mem_data[node].min_pfn = ~0UL; + } /* * Initialize the boot memory maps in reverse order since that's * what the bootmem allocator expects @@ -492,17 +461,14 @@ void __init find_memory(void) if (!node_online(node)) continue; + else if (node_isset(node, memory_less_mask)) + continue; bdp = &mem_data[node].bootmem_data; pernode = mem_data[node].pernode_addr; pernodesize = mem_data[node].pernode_size; map = pernode + pernodesize; - /* Sanity check... */ - if (!pernode) - panic("pernode space for node %d " - "could not be allocated!", node); - init_bootmem_node(mem_data[node].pgdat, map>>PAGE_SHIFT, bdp->node_boot_start>>PAGE_SHIFT, @@ -512,6 +478,7 @@ void __init find_memory(void) efi_memmap_walk(filter_rsvd_memory, free_node_bootmem); reserve_pernode_space(); + memory_less_nodes(); initialize_pernode_data(); max_pfn = max_low_pfn; @@ -519,6 +486,7 @@ void __init find_memory(void) find_initrd(); } +#ifdef CONFIG_SMP /** * per_cpu_init - setup per-cpu variables * @@ -529,15 +497,15 @@ void *per_cpu_init(void) { int cpu; - if (smp_processor_id() == 0) { - for (cpu = 0; cpu < NR_CPUS; cpu++) { - per_cpu(local_per_cpu_offset, cpu) = - __per_cpu_offset[cpu]; - } - } + if (smp_processor_id() != 0) + return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; + + for (cpu = 0; cpu < NR_CPUS; cpu++) + per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; return __per_cpu_start + __per_cpu_offset[smp_processor_id()]; } +#endif /* CONFIG_SMP */ /** * show_mem - give short summary of memory stats @@ -680,12 +648,13 @@ void __init paging_init(void) max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT; - /* so min() will work in count_node_pages */ - for_each_online_node(node) - mem_data[node].min_pfn = ~0UL; - efi_memmap_walk(filter_rsvd_memory, count_node_pages); + vmalloc_end -= PAGE_ALIGN(max_low_pfn * sizeof(struct page)); + vmem_map = (struct page *) vmalloc_end; + efi_memmap_walk(create_mem_map_page_table, NULL); + printk("Virtual mem_map starts at 0x%p\n", vmem_map); + for_each_online_node(node) { memset(zones_size, 0, sizeof(zones_size)); memset(zholes_size, 0, sizeof(zholes_size)); @@ -719,15 +688,6 @@ void __init paging_init(void) mem_data[node].num_dma_physpages); } - if (node == 0) { - vmalloc_end -= - PAGE_ALIGN(max_low_pfn * sizeof(struct page)); - vmem_map = (struct page *) vmalloc_end; - - efi_memmap_walk(create_mem_map_page_table, NULL); - printk("Virtual mem_map starts at 0x%p\n", vmem_map); - } - pfn_offset = mem_data[node].min_pfn; NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset; @@ -735,5 +695,11 @@ void __init paging_init(void) pfn_offset, zholes_size); } + /* + * Make memory less nodes become a member of the known nodes. + */ + for_each_node_mask(node, memory_less_mask) + pgdat_insert(mem_data[node].pgdat); + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 4eb2f52b87a..65f9958db9f 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -597,7 +597,8 @@ mem_init (void) kclist_add(&kcore_kernel, _stext, _end - _stext); for_each_pgdat(pgdat) - totalram_pages += free_all_bootmem_node(pgdat); + if (pgdat->bdata->node_bootmem_map) + totalram_pages += free_all_bootmem_node(pgdat); reserved_pages = 0; efi_memmap_walk(count_reserved_pages, &reserved_pages); diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/arch/ia64/sn/include/pci/pcibr_provider.h deleted file mode 100644 index 1cd291d8bad..00000000000 --- a/arch/ia64/sn/include/pci/pcibr_provider.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H -#define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H - -/* Workarounds */ -#define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */ - -#define BUSTYPE_MASK 0x1 - -/* Macros given a pcibus structure */ -#define IS_PCIX(ps) ((ps)->pbi_bridge_mode & BUSTYPE_MASK) -#define IS_PCI_BRIDGE_ASIC(asic) (asic == PCIIO_ASIC_TYPE_PIC || \ - asic == PCIIO_ASIC_TYPE_TIOCP) -#define IS_PIC_SOFT(ps) (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC) - - -/* - * The different PCI Bridge types supported on the SGI Altix platforms - */ -#define PCIBR_BRIDGETYPE_UNKNOWN -1 -#define PCIBR_BRIDGETYPE_PIC 2 -#define PCIBR_BRIDGETYPE_TIOCP 3 - -/* - * Bridge 64bit Direct Map Attributes - */ -#define PCI64_ATTR_PREF (1ull << 59) -#define PCI64_ATTR_PREC (1ull << 58) -#define PCI64_ATTR_VIRTUAL (1ull << 57) -#define PCI64_ATTR_BAR (1ull << 56) -#define PCI64_ATTR_SWAP (1ull << 55) -#define PCI64_ATTR_VIRTUAL1 (1ull << 54) - -#define PCI32_LOCAL_BASE 0 -#define PCI32_MAPPED_BASE 0x40000000 -#define PCI32_DIRECT_BASE 0x80000000 - -#define IS_PCI32_MAPPED(x) ((uint64_t)(x) < PCI32_DIRECT_BASE && \ - (uint64_t)(x) >= PCI32_MAPPED_BASE) -#define IS_PCI32_DIRECT(x) ((uint64_t)(x) >= PCI32_MAPPED_BASE) - - -/* - * Bridge PMU Address Transaltion Entry Attibutes - */ -#define PCI32_ATE_V (0x1 << 0) -#define PCI32_ATE_CO (0x1 << 1) -#define PCI32_ATE_PREC (0x1 << 2) -#define PCI32_ATE_PREF (0x1 << 3) -#define PCI32_ATE_BAR (0x1 << 4) -#define PCI32_ATE_ADDR_SHFT 12 - -#define MINIMAL_ATES_REQUIRED(addr, size) \ - (IOPG(IOPGOFF(addr) + (size) - 1) == IOPG((size) - 1)) - -#define MINIMAL_ATE_FLAG(addr, size) \ - (MINIMAL_ATES_REQUIRED((uint64_t)addr, size) ? 1 : 0) - -/* bit 29 of the pci address is the SWAP bit */ -#define ATE_SWAPSHIFT 29 -#define ATE_SWAP_ON(x) ((x) |= (1 << ATE_SWAPSHIFT)) -#define ATE_SWAP_OFF(x) ((x) &= ~(1 << ATE_SWAPSHIFT)) - -/* - * I/O page size - */ -#if PAGE_SIZE < 16384 -#define IOPFNSHIFT 12 /* 4K per mapped page */ -#else -#define IOPFNSHIFT 14 /* 16K per mapped page */ -#endif - -#define IOPGSIZE (1 << IOPFNSHIFT) -#define IOPG(x) ((x) >> IOPFNSHIFT) -#define IOPGOFF(x) ((x) & (IOPGSIZE-1)) - -#define PCIBR_DEV_SWAP_DIR (1ull << 19) -#define PCIBR_CTRL_PAGE_SIZE (0x1 << 21) - -/* - * PMU resources. - */ -struct ate_resource{ - uint64_t *ate; - uint64_t num_ate; - uint64_t lowest_free_index; -}; - -struct pcibus_info { - struct pcibus_bussoft pbi_buscommon; /* common header */ - uint32_t pbi_moduleid; - short pbi_bridge_type; - short pbi_bridge_mode; - - struct ate_resource pbi_int_ate_resource; - uint64_t pbi_int_ate_size; - - uint64_t pbi_dir_xbase; - char pbi_hub_xid; - - uint64_t pbi_devreg[8]; - spinlock_t pbi_lock; - - uint32_t pbi_valid_devices; - uint32_t pbi_enabled_devices; -}; - -/* - * pcibus_info structure locking macros - */ -inline static unsigned long -pcibr_lock(struct pcibus_info *pcibus_info) -{ - unsigned long flag; - spin_lock_irqsave(&pcibus_info->pbi_lock, flag); - return(flag); -} -#define pcibr_unlock(pcibus_info, flag) spin_unlock_irqrestore(&pcibus_info->pbi_lock, flag) - -extern int pcibr_init_provider(void); -extern void *pcibr_bus_fixup(struct pcibus_bussoft *); -extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t); -extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t); -extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); - -/* - * prototypes for the bridge asic register access routines in pcibr_reg.c - */ -extern void pcireg_control_bit_clr(struct pcibus_info *, uint64_t); -extern void pcireg_control_bit_set(struct pcibus_info *, uint64_t); -extern uint64_t pcireg_tflush_get(struct pcibus_info *); -extern uint64_t pcireg_intr_status_get(struct pcibus_info *); -extern void pcireg_intr_enable_bit_clr(struct pcibus_info *, uint64_t); -extern void pcireg_intr_enable_bit_set(struct pcibus_info *, uint64_t); -extern void pcireg_intr_addr_addr_set(struct pcibus_info *, int, uint64_t); -extern void pcireg_force_intr_set(struct pcibus_info *, int); -extern uint64_t pcireg_wrb_flush_get(struct pcibus_info *, int); -extern void pcireg_int_ate_set(struct pcibus_info *, int, uint64_t); -extern uint64_t * pcireg_int_ate_addr(struct pcibus_info *, int); -extern void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info); -extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info); -extern int pcibr_ate_alloc(struct pcibus_info *, int); -extern void pcibr_ate_free(struct pcibus_info *, int); -extern void ate_write(struct pcibus_info *, int, int, uint64_t); -#endif diff --git a/arch/ia64/sn/include/pci/pic.h b/arch/ia64/sn/include/pci/pic.h deleted file mode 100644 index fd18acecb1e..00000000000 --- a/arch/ia64/sn/include/pci/pic.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_PIC_H -#define _ASM_IA64_SN_PCI_PIC_H - -/* - * PIC AS DEVICE ZERO - * ------------------ - * - * PIC handles PCI/X busses. PCI/X requires that the 'bridge' (i.e. PIC) - * be designated as 'device 0'. That is a departure from earlier SGI - * PCI bridges. Because of that we use config space 1 to access the - * config space of the first actual PCI device on the bus. - * Here's what the PIC manual says: - * - * The current PCI-X bus specification now defines that the parent - * hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC - * reduced the total number of devices from 8 to 4 and removed the - * device registers and windows, now only supporting devices 0,1,2, and - * 3. PIC did leave all 8 configuration space windows. The reason was - * there was nothing to gain by removing them. Here in lies the problem. - * The device numbering we do using 0 through 3 is unrelated to the device - * numbering which PCI-X requires in configuration space. In the past we - * correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc. - * PCI-X requires we start a 1, not 0 and currently the PX brick - * does associate our: - * - * device 0 with configuration space window 1, - * device 1 with configuration space window 2, - * device 2 with configuration space window 3, - * device 3 with configuration space window 4. - * - * The net effect is that all config space access are off-by-one with - * relation to other per-slot accesses on the PIC. - * Here is a table that shows some of that: - * - * Internal Slot# - * | - * | 0 1 2 3 - * ----------|--------------------------------------- - * config | 0x21000 0x22000 0x23000 0x24000 - * | - * even rrb | 0[0] n/a 1[0] n/a [] == implied even/odd - * | - * odd rrb | n/a 0[1] n/a 1[1] - * | - * int dev | 00 01 10 11 - * | - * ext slot# | 1 2 3 4 - * ----------|--------------------------------------- - */ - -#define PIC_ATE_TARGETID_SHFT 8 -#define PIC_HOST_INTR_ADDR 0x0000FFFFFFFFFFFFUL -#define PIC_PCI64_ATTR_TARG_SHFT 60 - - -/***************************************************************************** - *********************** PIC MMR structure mapping *************************** - *****************************************************************************/ - -/* NOTE: PIC WAR. PV#854697. PIC does not allow writes just to [31:0] - * of a 64-bit register. When writing PIC registers, always write the - * entire 64 bits. - */ - -struct pic { - - /* 0x000000-0x00FFFF -- Local Registers */ - - /* 0x000000-0x000057 -- Standard Widget Configuration */ - uint64_t p_wid_id; /* 0x000000 */ - uint64_t p_wid_stat; /* 0x000008 */ - uint64_t p_wid_err_upper; /* 0x000010 */ - uint64_t p_wid_err_lower; /* 0x000018 */ - #define p_wid_err p_wid_err_lower - uint64_t p_wid_control; /* 0x000020 */ - uint64_t p_wid_req_timeout; /* 0x000028 */ - uint64_t p_wid_int_upper; /* 0x000030 */ - uint64_t p_wid_int_lower; /* 0x000038 */ - #define p_wid_int p_wid_int_lower - uint64_t p_wid_err_cmdword; /* 0x000040 */ - uint64_t p_wid_llp; /* 0x000048 */ - uint64_t p_wid_tflush; /* 0x000050 */ - - /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */ - uint64_t p_wid_aux_err; /* 0x000058 */ - uint64_t p_wid_resp_upper; /* 0x000060 */ - uint64_t p_wid_resp_lower; /* 0x000068 */ - #define p_wid_resp p_wid_resp_lower - uint64_t p_wid_tst_pin_ctrl; /* 0x000070 */ - uint64_t p_wid_addr_lkerr; /* 0x000078 */ - - /* 0x000080-0x00008F -- PMU & MAP */ - uint64_t p_dir_map; /* 0x000080 */ - uint64_t _pad_000088; /* 0x000088 */ - - /* 0x000090-0x00009F -- SSRAM */ - uint64_t p_map_fault; /* 0x000090 */ - uint64_t _pad_000098; /* 0x000098 */ - - /* 0x0000A0-0x0000AF -- Arbitration */ - uint64_t p_arb; /* 0x0000A0 */ - uint64_t _pad_0000A8; /* 0x0000A8 */ - - /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */ - uint64_t p_ate_parity_err; /* 0x0000B0 */ - uint64_t _pad_0000B8; /* 0x0000B8 */ - - /* 0x0000C0-0x0000FF -- PCI/GIO */ - uint64_t p_bus_timeout; /* 0x0000C0 */ - uint64_t p_pci_cfg; /* 0x0000C8 */ - uint64_t p_pci_err_upper; /* 0x0000D0 */ - uint64_t p_pci_err_lower; /* 0x0000D8 */ - #define p_pci_err p_pci_err_lower - uint64_t _pad_0000E0[4]; /* 0x0000{E0..F8} */ - - /* 0x000100-0x0001FF -- Interrupt */ - uint64_t p_int_status; /* 0x000100 */ - uint64_t p_int_enable; /* 0x000108 */ - uint64_t p_int_rst_stat; /* 0x000110 */ - uint64_t p_int_mode; /* 0x000118 */ - uint64_t p_int_device; /* 0x000120 */ - uint64_t p_int_host_err; /* 0x000128 */ - uint64_t p_int_addr[8]; /* 0x0001{30,,,68} */ - uint64_t p_err_int_view; /* 0x000170 */ - uint64_t p_mult_int; /* 0x000178 */ - uint64_t p_force_always[8]; /* 0x0001{80,,,B8} */ - uint64_t p_force_pin[8]; /* 0x0001{C0,,,F8} */ - - /* 0x000200-0x000298 -- Device */ - uint64_t p_device[4]; /* 0x0002{00,,,18} */ - uint64_t _pad_000220[4]; /* 0x0002{20,,,38} */ - uint64_t p_wr_req_buf[4]; /* 0x0002{40,,,58} */ - uint64_t _pad_000260[4]; /* 0x0002{60,,,78} */ - uint64_t p_rrb_map[2]; /* 0x0002{80,,,88} */ - #define p_even_resp p_rrb_map[0] /* 0x000280 */ - #define p_odd_resp p_rrb_map[1] /* 0x000288 */ - uint64_t p_resp_status; /* 0x000290 */ - uint64_t p_resp_clear; /* 0x000298 */ - - uint64_t _pad_0002A0[12]; /* 0x0002{A0..F8} */ - - /* 0x000300-0x0003F8 -- Buffer Address Match Registers */ - struct { - uint64_t upper; /* 0x0003{00,,,F0} */ - uint64_t lower; /* 0x0003{08,,,F8} */ - } p_buf_addr_match[16]; - - /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */ - struct { - uint64_t flush_w_touch; /* 0x000{400,,,5C0} */ - uint64_t flush_wo_touch; /* 0x000{408,,,5C8} */ - uint64_t inflight; /* 0x000{410,,,5D0} */ - uint64_t prefetch; /* 0x000{418,,,5D8} */ - uint64_t total_pci_retry; /* 0x000{420,,,5E0} */ - uint64_t max_pci_retry; /* 0x000{428,,,5E8} */ - uint64_t max_latency; /* 0x000{430,,,5F0} */ - uint64_t clear_all; /* 0x000{438,,,5F8} */ - } p_buf_count[8]; - - - /* 0x000600-0x0009FF -- PCI/X registers */ - uint64_t p_pcix_bus_err_addr; /* 0x000600 */ - uint64_t p_pcix_bus_err_attr; /* 0x000608 */ - uint64_t p_pcix_bus_err_data; /* 0x000610 */ - uint64_t p_pcix_pio_split_addr; /* 0x000618 */ - uint64_t p_pcix_pio_split_attr; /* 0x000620 */ - uint64_t p_pcix_dma_req_err_attr; /* 0x000628 */ - uint64_t p_pcix_dma_req_err_addr; /* 0x000630 */ - uint64_t p_pcix_timeout; /* 0x000638 */ - - uint64_t _pad_000640[120]; /* 0x000{640,,,9F8} */ - - /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */ - struct { - uint64_t p_buf_addr; /* 0x000{A00,,,AF0} */ - uint64_t p_buf_attr; /* 0X000{A08,,,AF8} */ - } p_pcix_read_buf_64[16]; - - struct { - uint64_t p_buf_addr; /* 0x000{B00,,,BE0} */ - uint64_t p_buf_attr; /* 0x000{B08,,,BE8} */ - uint64_t p_buf_valid; /* 0x000{B10,,,BF0} */ - uint64_t __pad1; /* 0x000{B18,,,BF8} */ - } p_pcix_write_buf_64[8]; - - /* End of Local Registers -- Start of Address Map space */ - - char _pad_000c00[0x010000 - 0x000c00]; - - /* 0x010000-0x011fff -- Internal ATE RAM (Auto Parity Generation) */ - uint64_t p_int_ate_ram[1024]; /* 0x010000-0x011fff */ - - /* 0x012000-0x013fff -- Internal ATE RAM (Manual Parity Generation) */ - uint64_t p_int_ate_ram_mp[1024]; /* 0x012000-0x013fff */ - - char _pad_014000[0x18000 - 0x014000]; - - /* 0x18000-0x197F8 -- PIC Write Request Ram */ - uint64_t p_wr_req_lower[256]; /* 0x18000 - 0x187F8 */ - uint64_t p_wr_req_upper[256]; /* 0x18800 - 0x18FF8 */ - uint64_t p_wr_req_parity[256]; /* 0x19000 - 0x197F8 */ - - char _pad_019800[0x20000 - 0x019800]; - - /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */ - union { - uint8_t c[0x1000 / 1]; /* 0x02{0000,,,7FFF} */ - uint16_t s[0x1000 / 2]; /* 0x02{0000,,,7FFF} */ - uint32_t l[0x1000 / 4]; /* 0x02{0000,,,7FFF} */ - uint64_t d[0x1000 / 8]; /* 0x02{0000,,,7FFF} */ - union { - uint8_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } p_type0_cfg_dev[8]; /* 0x02{0000,,,7FFF} */ - - /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */ - union { - uint8_t c[0x1000 / 1]; /* 0x028000-0x029000 */ - uint16_t s[0x1000 / 2]; /* 0x028000-0x029000 */ - uint32_t l[0x1000 / 4]; /* 0x028000-0x029000 */ - uint64_t d[0x1000 / 8]; /* 0x028000-0x029000 */ - union { - uint8_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } p_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x030000-0x029000]; - - /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */ - union { - uint8_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } p_pci_iack; /* 0x030000-0x030007 */ - - char _pad_030007[0x040000-0x030008]; - - /* 0x040000-0x030007 -- PCIX Special Cycle */ - union { - uint8_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } p_pcix_cycle; /* 0x040000-0x040007 */ -}; - -#endif /* _ASM_IA64_SN_PCI_PIC_H */ diff --git a/arch/ia64/sn/include/pci/tiocp.h b/arch/ia64/sn/include/pci/tiocp.h deleted file mode 100644 index f07c83b2bf6..00000000000 --- a/arch/ia64/sn/include/pci/tiocp.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_PCI_TIOCP_H -#define _ASM_IA64_SN_PCI_TIOCP_H - -#define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL -#define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60) - - -/***************************************************************************** - *********************** TIOCP MMR structure mapping *************************** - *****************************************************************************/ - -struct tiocp{ - - /* 0x000000-0x00FFFF -- Local Registers */ - - /* 0x000000-0x000057 -- (Legacy Widget Space) Configuration */ - uint64_t cp_id; /* 0x000000 */ - uint64_t cp_stat; /* 0x000008 */ - uint64_t cp_err_upper; /* 0x000010 */ - uint64_t cp_err_lower; /* 0x000018 */ - #define cp_err cp_err_lower - uint64_t cp_control; /* 0x000020 */ - uint64_t cp_req_timeout; /* 0x000028 */ - uint64_t cp_intr_upper; /* 0x000030 */ - uint64_t cp_intr_lower; /* 0x000038 */ - #define cp_intr cp_intr_lower - uint64_t cp_err_cmdword; /* 0x000040 */ - uint64_t _pad_000048; /* 0x000048 */ - uint64_t cp_tflush; /* 0x000050 */ - - /* 0x000058-0x00007F -- Bridge-specific Configuration */ - uint64_t cp_aux_err; /* 0x000058 */ - uint64_t cp_resp_upper; /* 0x000060 */ - uint64_t cp_resp_lower; /* 0x000068 */ - #define cp_resp cp_resp_lower - uint64_t cp_tst_pin_ctrl; /* 0x000070 */ - uint64_t cp_addr_lkerr; /* 0x000078 */ - - /* 0x000080-0x00008F -- PMU & MAP */ - uint64_t cp_dir_map; /* 0x000080 */ - uint64_t _pad_000088; /* 0x000088 */ - - /* 0x000090-0x00009F -- SSRAM */ - uint64_t cp_map_fault; /* 0x000090 */ - uint64_t _pad_000098; /* 0x000098 */ - - /* 0x0000A0-0x0000AF -- Arbitration */ - uint64_t cp_arb; /* 0x0000A0 */ - uint64_t _pad_0000A8; /* 0x0000A8 */ - - /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */ - uint64_t cp_ate_parity_err; /* 0x0000B0 */ - uint64_t _pad_0000B8; /* 0x0000B8 */ - - /* 0x0000C0-0x0000FF -- PCI/GIO */ - uint64_t cp_bus_timeout; /* 0x0000C0 */ - uint64_t cp_pci_cfg; /* 0x0000C8 */ - uint64_t cp_pci_err_upper; /* 0x0000D0 */ - uint64_t cp_pci_err_lower; /* 0x0000D8 */ - #define cp_pci_err cp_pci_err_lower - uint64_t _pad_0000E0[4]; /* 0x0000{E0..F8} */ - - /* 0x000100-0x0001FF -- Interrupt */ - uint64_t cp_int_status; /* 0x000100 */ - uint64_t cp_int_enable; /* 0x000108 */ - uint64_t cp_int_rst_stat; /* 0x000110 */ - uint64_t cp_int_mode; /* 0x000118 */ - uint64_t cp_int_device; /* 0x000120 */ - uint64_t cp_int_host_err; /* 0x000128 */ - uint64_t cp_int_addr[8]; /* 0x0001{30,,,68} */ - uint64_t cp_err_int_view; /* 0x000170 */ - uint64_t cp_mult_int; /* 0x000178 */ - uint64_t cp_force_always[8]; /* 0x0001{80,,,B8} */ - uint64_t cp_force_pin[8]; /* 0x0001{C0,,,F8} */ - - /* 0x000200-0x000298 -- Device */ - uint64_t cp_device[4]; /* 0x0002{00,,,18} */ - uint64_t _pad_000220[4]; /* 0x0002{20,,,38} */ - uint64_t cp_wr_req_buf[4]; /* 0x0002{40,,,58} */ - uint64_t _pad_000260[4]; /* 0x0002{60,,,78} */ - uint64_t cp_rrb_map[2]; /* 0x0002{80,,,88} */ - #define cp_even_resp cp_rrb_map[0] /* 0x000280 */ - #define cp_odd_resp cp_rrb_map[1] /* 0x000288 */ - uint64_t cp_resp_status; /* 0x000290 */ - uint64_t cp_resp_clear; /* 0x000298 */ - - uint64_t _pad_0002A0[12]; /* 0x0002{A0..F8} */ - - /* 0x000300-0x0003F8 -- Buffer Address Match Registers */ - struct { - uint64_t upper; /* 0x0003{00,,,F0} */ - uint64_t lower; /* 0x0003{08,,,F8} */ - } cp_buf_addr_match[16]; - - /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */ - struct { - uint64_t flush_w_touch; /* 0x000{400,,,5C0} */ - uint64_t flush_wo_touch; /* 0x000{408,,,5C8} */ - uint64_t inflight; /* 0x000{410,,,5D0} */ - uint64_t prefetch; /* 0x000{418,,,5D8} */ - uint64_t total_pci_retry; /* 0x000{420,,,5E0} */ - uint64_t max_pci_retry; /* 0x000{428,,,5E8} */ - uint64_t max_latency; /* 0x000{430,,,5F0} */ - uint64_t clear_all; /* 0x000{438,,,5F8} */ - } cp_buf_count[8]; - - - /* 0x000600-0x0009FF -- PCI/X registers */ - uint64_t cp_pcix_bus_err_addr; /* 0x000600 */ - uint64_t cp_pcix_bus_err_attr; /* 0x000608 */ - uint64_t cp_pcix_bus_err_data; /* 0x000610 */ - uint64_t cp_pcix_pio_split_addr; /* 0x000618 */ - uint64_t cp_pcix_pio_split_attr; /* 0x000620 */ - uint64_t cp_pcix_dma_req_err_attr; /* 0x000628 */ - uint64_t cp_pcix_dma_req_err_addr; /* 0x000630 */ - uint64_t cp_pcix_timeout; /* 0x000638 */ - - uint64_t _pad_000640[24]; /* 0x000{640,,,6F8} */ - - /* 0x000700-0x000737 -- Debug Registers */ - uint64_t cp_ct_debug_ctl; /* 0x000700 */ - uint64_t cp_br_debug_ctl; /* 0x000708 */ - uint64_t cp_mux3_debug_ctl; /* 0x000710 */ - uint64_t cp_mux4_debug_ctl; /* 0x000718 */ - uint64_t cp_mux5_debug_ctl; /* 0x000720 */ - uint64_t cp_mux6_debug_ctl; /* 0x000728 */ - uint64_t cp_mux7_debug_ctl; /* 0x000730 */ - - uint64_t _pad_000738[89]; /* 0x000{738,,,9F8} */ - - /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */ - struct { - uint64_t cp_buf_addr; /* 0x000{A00,,,AF0} */ - uint64_t cp_buf_attr; /* 0X000{A08,,,AF8} */ - } cp_pcix_read_buf_64[16]; - - struct { - uint64_t cp_buf_addr; /* 0x000{B00,,,BE0} */ - uint64_t cp_buf_attr; /* 0x000{B08,,,BE8} */ - uint64_t cp_buf_valid; /* 0x000{B10,,,BF0} */ - uint64_t __pad1; /* 0x000{B18,,,BF8} */ - } cp_pcix_write_buf_64[8]; - - /* End of Local Registers -- Start of Address Map space */ - - char _pad_000c00[0x010000 - 0x000c00]; - - /* 0x010000-0x011FF8 -- Internal ATE RAM (Auto Parity Generation) */ - uint64_t cp_int_ate_ram[1024]; /* 0x010000-0x011FF8 */ - - char _pad_012000[0x14000 - 0x012000]; - - /* 0x014000-0x015FF8 -- Internal ATE RAM (Manual Parity Generation) */ - uint64_t cp_int_ate_ram_mp[1024]; /* 0x014000-0x015FF8 */ - - char _pad_016000[0x18000 - 0x016000]; - - /* 0x18000-0x197F8 -- TIOCP Write Request Ram */ - uint64_t cp_wr_req_lower[256]; /* 0x18000 - 0x187F8 */ - uint64_t cp_wr_req_upper[256]; /* 0x18800 - 0x18FF8 */ - uint64_t cp_wr_req_parity[256]; /* 0x19000 - 0x197F8 */ - - char _pad_019800[0x1C000 - 0x019800]; - - /* 0x1C000-0x1EFF8 -- TIOCP Read Response Ram */ - uint64_t cp_rd_resp_lower[512]; /* 0x1C000 - 0x1CFF8 */ - uint64_t cp_rd_resp_upper[512]; /* 0x1D000 - 0x1DFF8 */ - uint64_t cp_rd_resp_parity[512]; /* 0x1E000 - 0x1EFF8 */ - - char _pad_01F000[0x20000 - 0x01F000]; - - /* 0x020000-0x021FFF -- Host Device (CP) Configuration Space (not used) */ - char _pad_020000[0x021000 - 0x20000]; - - /* 0x021000-0x027FFF -- PCI Device Configuration Spaces */ - union { - uint8_t c[0x1000 / 1]; /* 0x02{0000,,,7FFF} */ - uint16_t s[0x1000 / 2]; /* 0x02{0000,,,7FFF} */ - uint32_t l[0x1000 / 4]; /* 0x02{0000,,,7FFF} */ - uint64_t d[0x1000 / 8]; /* 0x02{0000,,,7FFF} */ - union { - uint8_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } cp_type0_cfg_dev[7]; /* 0x02{1000,,,7FFF} */ - - /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */ - union { - uint8_t c[0x1000 / 1]; /* 0x028000-0x029000 */ - uint16_t s[0x1000 / 2]; /* 0x028000-0x029000 */ - uint32_t l[0x1000 / 4]; /* 0x028000-0x029000 */ - uint64_t d[0x1000 / 8]; /* 0x028000-0x029000 */ - union { - uint8_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } cp_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x030000-0x029000]; - - /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */ - union { - uint8_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } cp_pci_iack; /* 0x030000-0x030007 */ - - char _pad_030007[0x040000-0x030008]; - - /* 0x040000-0x040007 -- PCIX Special Cycle */ - union { - uint8_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } cp_pcix_cycle; /* 0x040000-0x040007 */ - - char _pad_040007[0x200000-0x040008]; - - /* 0x200000-0x7FFFFF -- PCI/GIO Device Spaces */ - union { - uint8_t c[0x100000 / 1]; - uint16_t s[0x100000 / 2]; - uint32_t l[0x100000 / 4]; - uint64_t d[0x100000 / 8]; - } cp_devio_raw[6]; /* 0x200000-0x7FFFFF */ - - #define cp_devio(n) cp_devio_raw[((n)<2)?(n*2):(n+2)] - - char _pad_800000[0xA00000-0x800000]; - - /* 0xA00000-0xBFFFFF -- PCI/GIO Device Spaces w/flush */ - union { - uint8_t c[0x100000 / 1]; - uint16_t s[0x100000 / 2]; - uint32_t l[0x100000 / 4]; - uint64_t d[0x100000 / 8]; - } cp_devio_raw_flush[6]; /* 0xA00000-0xBFFFFF */ - - #define cp_devio_flush(n) cp_devio_raw_flush[((n)<2)?(n*2):(n+2)] - -}; - -#endif /* _ASM_IA64_SN_PCI_TIOCP_H */ diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h index 868e7ecae84..580a1c0403a 100644 --- a/arch/ia64/sn/include/xtalk/hubdev.h +++ b/arch/ia64/sn/include/xtalk/hubdev.h @@ -8,6 +8,8 @@ #ifndef _ASM_IA64_SN_XTALK_HUBDEV_H #define _ASM_IA64_SN_XTALK_HUBDEV_H +#include "xtalk/xwidgetdev.h" + #define HUB_WIDGET_ID_MAX 0xf #define DEV_PER_WIDGET (2*2*8) #define IIO_ITTE_WIDGET_BITS 4 /* size of widget field */ diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 783eb432384..a67f39e448c 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c @@ -9,21 +9,28 @@ #include <linux/bootmem.h> #include <linux/nodemask.h> #include <asm/sn/types.h> -#include <asm/sn/sn_sal.h> #include <asm/sn/addrs.h> -#include <asm/sn/pcibus_provider_defs.h> -#include <asm/sn/pcidev.h> -#include "pci/pcibr_provider.h" -#include "xtalk/xwidgetdev.h" #include <asm/sn/geo.h> -#include "xtalk/hubdev.h" #include <asm/sn/io.h> +#include <asm/sn/pcibr_provider.h> +#include <asm/sn/pcibus_provider_defs.h> +#include <asm/sn/pcidev.h> #include <asm/sn/simulator.h> +#include <asm/sn/sn_sal.h> #include <asm/sn/tioca_provider.h> +#include "xtalk/hubdev.h" +#include "xtalk/xwidgetdev.h" -char master_baseio_wid; nasid_t master_nasid = INVALID_NASID; /* Partition Master */ +static struct list_head sn_sysdata_list; + +/* sysdata list struct */ +struct sysdata_el { + struct list_head entry; + void *sysdata; +}; + struct slab_info { struct hubdev_info hubdev; }; @@ -138,23 +145,6 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, } /* - * sn_alloc_pci_sysdata() - This routine allocates a pci controller - * which is expected as the pci_dev and pci_bus sysdata by the Linux - * PCI infrastructure. - */ -static inline struct pci_controller *sn_alloc_pci_sysdata(void) -{ - struct pci_controller *pci_sysdata; - - pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL); - if (!pci_sysdata) - BUG(); - - memset(pci_sysdata, 0, sizeof(*pci_sysdata)); - return pci_sysdata; -} - -/* * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for * each node in the system. */ @@ -221,22 +211,34 @@ static void sn_fixup_ionodes(void) } +void sn_pci_unfixup_slot(struct pci_dev *dev) +{ + struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; + + sn_irq_unfixup(dev); + pci_dev_put(host_pci_dev); + pci_dev_put(dev); +} + /* * sn_pci_fixup_slot() - This routine sets up a slot's resources * consistent with the Linux PCI abstraction layer. Resources acquired * from our PCI provider include PIO maps to BAR space and interrupt * objects. */ -static void sn_pci_fixup_slot(struct pci_dev *dev) +void sn_pci_fixup_slot(struct pci_dev *dev) { int idx; int segment = 0; - uint64_t size; - struct sn_irq_info *sn_irq_info; - struct pci_dev *host_pci_dev; int status = 0; struct pcibus_bussoft *bs; + struct pci_bus *host_pci_bus; + struct pci_dev *host_pci_dev; + struct sn_irq_info *sn_irq_info; + unsigned long size; + unsigned int bus_no, devfn; + pci_dev_get(dev); /* for the sysdata pointer */ dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); if (SN_PCIDEV_INFO(dev) <= 0) BUG(); /* Cannot afford to run out of memory */ @@ -253,7 +255,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) (u64) __pa(SN_PCIDEV_INFO(dev)), (u64) __pa(sn_irq_info)); if (status) - BUG(); /* Cannot get platform pci device information information */ + BUG(); /* Cannot get platform pci device information */ /* Copy over PIO Mapped Addresses */ for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { @@ -275,15 +277,21 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) dev->resource[idx].parent = &iomem_resource; } - /* set up host bus linkages */ - bs = SN_PCIBUS_BUSSOFT(dev->bus); - host_pci_dev = - pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, - SN_PCIDEV_INFO(dev)-> - pdi_slot_host_handle & 0xffffffff); + /* + * Using the PROMs values for the PCI host bus, get the Linux + * PCI host_pci_dev struct and set up host bus linkages + */ + + bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32; + devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; + host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no); + host_pci_dev = pci_get_slot(host_pci_bus, devfn); + + SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = - SN_PCIDEV_INFO(host_pci_dev); + SN_PCIDEV_INFO(host_pci_dev); SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; + bs = SN_PCIBUS_BUSSOFT(dev->bus); SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { @@ -297,6 +305,9 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; sn_irq_fixup(dev, sn_irq_info); + } else { + SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL; + kfree(sn_irq_info); } } @@ -304,55 +315,57 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) * sn_pci_controller_fixup() - This routine sets up a bus's resources * consistent with the Linux PCI abstraction layer. */ -static void sn_pci_controller_fixup(int segment, int busnum) +void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) { int status = 0; int nasid, cnode; - struct pci_bus *bus; struct pci_controller *controller; struct pcibus_bussoft *prom_bussoft_ptr; struct hubdev_info *hubdev_info; void *provider_soft; struct sn_pcibus_provider *provider; - status = - sal_get_pcibus_info((u64) segment, (u64) busnum, - (u64) ia64_tpa(&prom_bussoft_ptr)); - if (status > 0) { - return; /* bus # does not exist */ - } - + status = sal_get_pcibus_info((u64) segment, (u64) busnum, + (u64) ia64_tpa(&prom_bussoft_ptr)); + if (status > 0) + return; /*bus # does not exist */ prom_bussoft_ptr = __va(prom_bussoft_ptr); - controller = sn_alloc_pci_sysdata(); - /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */ - bus = pci_scan_bus(busnum, &pci_root_ops, controller); + controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL); + if (!controller) + BUG(); + if (bus == NULL) { - return; /* error, or bus already scanned */ + bus = pci_scan_bus(busnum, &pci_root_ops, controller); + if (bus == NULL) + return; /* error, or bus already scanned */ + bus->sysdata = NULL; } + if (bus->sysdata) + goto error_return; /* sysdata already alloc'd */ + /* * Per-provider fixup. Copies the contents from prom to local * area and links SN_PCIBUS_BUSSOFT(). */ - if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { + if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) return; /* unsupported asic type */ - } + + if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) + goto error_return; /* no further fixup necessary */ provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; - if (provider == NULL) { + if (provider == NULL) return; /* no provider registerd for this asic */ - } provider_soft = NULL; - if (provider->bus_fixup) { + if (provider->bus_fixup) provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); - } - if (provider_soft == NULL) { + if (provider_soft == NULL) return; /* fixup failed or not applicable */ - } /* * Generic bus fixup goes here. Don't reference prom_bussoft_ptr @@ -361,12 +374,47 @@ static void sn_pci_controller_fixup(int segment, int busnum) bus->sysdata = controller; PCI_CONTROLLER(bus)->platform_data = provider_soft; - nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); cnode = nasid_to_cnodeid(nasid); hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); + + return; + +error_return: + + kfree(controller); + return; +} + +void sn_bus_store_sysdata(struct pci_dev *dev) +{ + struct sysdata_el *element; + + element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL); + if (!element) { + dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); + return; + } + element->sysdata = dev->sysdata; + list_add(&element->entry, &sn_sysdata_list); +} + +void sn_bus_free_sysdata(void) +{ + struct sysdata_el *element; + struct list_head *list; + +sn_sysdata_free_start: + list_for_each(list, &sn_sysdata_list) { + element = list_entry(list, struct sysdata_el, entry); + list_del(&element->entry); + kfree(element->sysdata); + kfree(element); + goto sn_sysdata_free_start; + } + return; } /* @@ -403,20 +451,17 @@ static int __init sn_pci_init(void) */ ia64_max_iommu_merge_mask = ~PAGE_MASK; sn_fixup_ionodes(); - sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL); - if (sn_irq <= 0) - BUG(); /* Canno afford to run out of memory. */ - memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS); - + sn_irq_lh_init(); + INIT_LIST_HEAD(&sn_sysdata_list); sn_init_cpei_timer(); #ifdef CONFIG_PROC_FS register_sn_procfs(); #endif - for (i = 0; i < PCI_BUSES_TO_SCAN; i++) { - sn_pci_controller_fixup(0, i); - } + /* busses are not known yet ... */ + for (i = 0; i < PCI_BUSES_TO_SCAN; i++) + sn_pci_controller_fixup(0, i, NULL); /* * Generic Linux PCI Layer has created the pci_bus and pci_dev @@ -425,9 +470,8 @@ static int __init sn_pci_init(void) */ while ((pci_dev = - pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { + pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) sn_pci_fixup_slot(pci_dev); - } sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ @@ -469,3 +513,8 @@ cnodeid_get_geoid(cnodeid_t cnode) } subsys_initcall(sn_pci_init); +EXPORT_SYMBOL(sn_pci_fixup_slot); +EXPORT_SYMBOL(sn_pci_unfixup_slot); +EXPORT_SYMBOL(sn_pci_controller_fixup); +EXPORT_SYMBOL(sn_bus_store_sysdata); +EXPORT_SYMBOL(sn_bus_free_sysdata); diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index 0f4e8138658..84d276a14ec 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c @@ -9,13 +9,13 @@ */ #include <linux/irq.h> -#include <asm/sn/intr.h> +#include <linux/spinlock.h> #include <asm/sn/addrs.h> #include <asm/sn/arch.h> -#include "xtalk/xwidgetdev.h" +#include <asm/sn/intr.h> +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> -#include "pci/pcibr_provider.h" #include <asm/sn/shub_mmr.h> #include <asm/sn/sn_sal.h> @@ -25,7 +25,8 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); extern int sn_force_interrupt_flag; extern int sn_ioif_inited; -struct sn_irq_info **sn_irq; +static struct list_head **sn_irq_lh; +static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ static inline uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget, u64 sn_irq_info, @@ -101,7 +102,7 @@ static void sn_end_irq(unsigned int irq) nasid = get_nasid(); event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR (nasid, SH_EVENT_OCCURRED)); - /* If the UART bit is set here, we may have received an + /* If the UART bit is set here, we may have received an * interrupt from the UART that the driver missed. To * make sure, we IPI ourselves to force us to look again. */ @@ -115,82 +116,84 @@ static void sn_end_irq(unsigned int irq) force_interrupt(irq); } +static void sn_irq_info_free(struct rcu_head *head); + static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) { - struct sn_irq_info *sn_irq_info = sn_irq[irq]; - struct sn_irq_info *tmp_sn_irq_info; + struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; int cpuid, cpuphys; - nasid_t t_nasid; /* nasid to target */ - int t_slice; /* slice to target */ - - /* allocate a temp sn_irq_info struct to get new target info */ - tmp_sn_irq_info = kmalloc(sizeof(*tmp_sn_irq_info), GFP_KERNEL); - if (!tmp_sn_irq_info) - return; cpuid = first_cpu(mask); cpuphys = cpu_physical_id(cpuid); - t_nasid = cpuid_to_nasid(cpuid); - t_slice = cpuid_to_slice(cpuid); - while (sn_irq_info) { - int status; - int local_widget; - uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge; - nasid_t local_nasid = NASID_GET(bridge); + list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, + sn_irq_lh[irq], list) { + uint64_t bridge; + int local_widget, status; + nasid_t local_nasid; + struct sn_irq_info *new_irq_info; + + new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); + if (new_irq_info == NULL) + break; + memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); + + bridge = (uint64_t) new_irq_info->irq_bridge; + if (!bridge) { + kfree(new_irq_info); + break; /* irq is not a device interrupt */ + } - if (!bridge) - break; /* irq is not a device interrupt */ + local_nasid = NASID_GET(bridge); if (local_nasid & 1) local_widget = TIO_SWIN_WIDGETNUM(bridge); else local_widget = SWIN_WIDGETNUM(bridge); - /* Free the old PROM sn_irq_info structure */ - sn_intr_free(local_nasid, local_widget, sn_irq_info); + /* Free the old PROM new_irq_info structure */ + sn_intr_free(local_nasid, local_widget, new_irq_info); + /* Update kernels new_irq_info with new target info */ + unregister_intr_pda(new_irq_info); - /* allocate a new PROM sn_irq_info struct */ + /* allocate a new PROM new_irq_info struct */ status = sn_intr_alloc(local_nasid, local_widget, - __pa(tmp_sn_irq_info), irq, t_nasid, - t_slice); - - if (status == 0) { - /* Update kernels sn_irq_info with new target info */ - unregister_intr_pda(sn_irq_info); - sn_irq_info->irq_cpuid = cpuid; - sn_irq_info->irq_nasid = t_nasid; - sn_irq_info->irq_slice = t_slice; - sn_irq_info->irq_xtalkaddr = - tmp_sn_irq_info->irq_xtalkaddr; - sn_irq_info->irq_cookie = tmp_sn_irq_info->irq_cookie; - register_intr_pda(sn_irq_info); - - if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type)) { - pcibr_change_devices_irq(sn_irq_info); - } + __pa(new_irq_info), irq, + cpuid_to_nasid(cpuid), + cpuid_to_slice(cpuid)); + + /* SAL call failed */ + if (status) { + kfree(new_irq_info); + break; + } + + new_irq_info->irq_cpuid = cpuid; + register_intr_pda(new_irq_info); + + if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type)) + pcibr_change_devices_irq(new_irq_info); - sn_irq_info = sn_irq_info->irq_next; + spin_lock(&sn_irq_info_lock); + list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); + spin_unlock(&sn_irq_info_lock); + call_rcu(&sn_irq_info->rcu, sn_irq_info_free); #ifdef CONFIG_SMP - set_irq_affinity_info((irq & 0xff), cpuphys, 0); + set_irq_affinity_info((irq & 0xff), cpuphys, 0); #endif - } else { - break; /* snp_affinity failed the intr_alloc */ - } } - kfree(tmp_sn_irq_info); } struct hw_interrupt_type irq_type_sn = { - "SN hub", - sn_startup_irq, - sn_shutdown_irq, - sn_enable_irq, - sn_disable_irq, - sn_ack_irq, - sn_end_irq, - sn_set_affinity_irq + .typename = "SN hub", + .startup = sn_startup_irq, + .shutdown = sn_shutdown_irq, + .enable = sn_enable_irq, + .disable = sn_disable_irq, + .ack = sn_ack_irq, + .end = sn_end_irq, + .set_affinity = sn_set_affinity_irq }; unsigned int sn_local_vector_to_irq(u8 vector) @@ -231,19 +234,18 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info) struct sn_irq_info *tmp_irq_info; int i, foundmatch; + rcu_read_lock(); if (pdacpu(cpu)->sn_last_irq == irq) { foundmatch = 0; - for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--) { - tmp_irq_info = sn_irq[i]; - while (tmp_irq_info) { + for (i = pdacpu(cpu)->sn_last_irq - 1; + i && !foundmatch; i--) { + list_for_each_entry_rcu(tmp_irq_info, + sn_irq_lh[i], + list) { if (tmp_irq_info->irq_cpuid == cpu) { - foundmatch++; + foundmatch = 1; break; } - tmp_irq_info = tmp_irq_info->irq_next; - } - if (foundmatch) { - break; } } pdacpu(cpu)->sn_last_irq = i; @@ -251,60 +253,27 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info) if (pdacpu(cpu)->sn_first_irq == irq) { foundmatch = 0; - for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++) { - tmp_irq_info = sn_irq[i]; - while (tmp_irq_info) { + for (i = pdacpu(cpu)->sn_first_irq + 1; + i < NR_IRQS && !foundmatch; i++) { + list_for_each_entry_rcu(tmp_irq_info, + sn_irq_lh[i], + list) { if (tmp_irq_info->irq_cpuid == cpu) { - foundmatch++; + foundmatch = 1; break; } - tmp_irq_info = tmp_irq_info->irq_next; - } - if (foundmatch) { - break; } } pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i); } + rcu_read_unlock(); } -struct sn_irq_info *sn_irq_alloc(nasid_t local_nasid, int local_widget, int irq, - nasid_t nasid, int slice) +static void sn_irq_info_free(struct rcu_head *head) { struct sn_irq_info *sn_irq_info; - int status; - - sn_irq_info = kmalloc(sizeof(*sn_irq_info), GFP_KERNEL); - if (sn_irq_info == NULL) - return NULL; - - memset(sn_irq_info, 0x0, sizeof(*sn_irq_info)); - - status = - sn_intr_alloc(local_nasid, local_widget, __pa(sn_irq_info), irq, - nasid, slice); - - if (status) { - kfree(sn_irq_info); - return NULL; - } else { - return sn_irq_info; - } -} - -void sn_irq_free(struct sn_irq_info *sn_irq_info) -{ - uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge; - nasid_t local_nasid = NASID_GET(bridge); - int local_widget; - - if (local_nasid & 1) /* tio check */ - local_widget = TIO_SWIN_WIDGETNUM(bridge); - else - local_widget = SWIN_WIDGETNUM(bridge); - - sn_intr_free(local_nasid, local_widget, sn_irq_info); + sn_irq_info = container_of(head, struct sn_irq_info, rcu); kfree(sn_irq_info); } @@ -314,30 +283,54 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) int slice = sn_irq_info->irq_slice; int cpu = nasid_slice_to_cpuid(nasid, slice); + pci_dev_get(pci_dev); sn_irq_info->irq_cpuid = cpu; sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev); /* link it into the sn_irq[irq] list */ - sn_irq_info->irq_next = sn_irq[sn_irq_info->irq_irq]; - sn_irq[sn_irq_info->irq_irq] = sn_irq_info; + spin_lock(&sn_irq_info_lock); + list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); + spin_unlock(&sn_irq_info_lock); (void)register_intr_pda(sn_irq_info); } +void sn_irq_unfixup(struct pci_dev *pci_dev) +{ + struct sn_irq_info *sn_irq_info; + + /* Only cleanup IRQ stuff if this device has a host bus context */ + if (!SN_PCIDEV_BUSSOFT(pci_dev)) + return; + + sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info; + if (!sn_irq_info || !sn_irq_info->irq_irq) { + kfree(sn_irq_info); + return; + } + + unregister_intr_pda(sn_irq_info); + spin_lock(&sn_irq_info_lock); + list_del_rcu(&sn_irq_info->list); + spin_unlock(&sn_irq_info_lock); + call_rcu(&sn_irq_info->rcu, sn_irq_info_free); + pci_dev_put(pci_dev); +} + static void force_interrupt(int irq) { struct sn_irq_info *sn_irq_info; if (!sn_ioif_inited) return; - sn_irq_info = sn_irq[irq]; - while (sn_irq_info) { + + rcu_read_lock(); + list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) { if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) && - (sn_irq_info->irq_bridge != NULL)) { + (sn_irq_info->irq_bridge != NULL)) pcibr_force_interrupt(sn_irq_info); - } - sn_irq_info = sn_irq_info->irq_next; } + rcu_read_unlock(); } /* @@ -402,19 +395,41 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info) void sn_lb_int_war_check(void) { + struct sn_irq_info *sn_irq_info; int i; if (!sn_ioif_inited || pda->sn_first_irq == 0) return; + + rcu_read_lock(); for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) { - struct sn_irq_info *sn_irq_info = sn_irq[i]; - while (sn_irq_info) { - /* Only call for PCI bridges that are fully initialized. */ + list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) { + /* + * Only call for PCI bridges that are fully + * initialized. + */ if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) && - (sn_irq_info->irq_bridge != NULL)) { + (sn_irq_info->irq_bridge != NULL)) sn_check_intr(i, sn_irq_info); - } - sn_irq_info = sn_irq_info->irq_next; } } + rcu_read_unlock(); +} + +void sn_irq_lh_init(void) +{ + int i; + + sn_irq_lh = kmalloc(sizeof(struct list_head *) * NR_IRQS, GFP_KERNEL); + if (!sn_irq_lh) + panic("SN PCI INIT: Failed to allocate memory for PCI init\n"); + + for (i = 0; i < NR_IRQS; i++) { + sn_irq_lh[i] = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!sn_irq_lh[i]) + panic("SN PCI INIT: Failed IRQ memory allocation\n"); + + INIT_LIST_HEAD(sn_irq_lh[i]); + } + } diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 22e10d282c7..7c7fe441d62 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -270,7 +270,7 @@ void __init sn_setup(char **cmdline_p) { long status, ticks_per_sec, drift; int pxm; - int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); + u32 version = sn_sal_rev(); extern void sn_cpu_init(void); ia64_sn_plat_set_error_handling_features(); @@ -308,22 +308,21 @@ void __init sn_setup(char **cmdline_p) * support here so we don't have to listen to failed keyboard probe * messages. */ - if ((major < 2 || (major == 2 && minor <= 9)) && - acpi_kbd_controller_present) { + if (version <= 0x0209 && acpi_kbd_controller_present) { printk(KERN_INFO "Disabling legacy keyboard support as prom " "is too old and doesn't provide FADT\n"); acpi_kbd_controller_present = 0; } - printk("SGI SAL version %x.%02x\n", major, minor); + printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); /* * Confirm the SAL we're running on is recent enough... */ - if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR && - minor < SN_SAL_MIN_MINOR)) { + if (version < SN_SAL_MIN_VERSION) { printk(KERN_ERR "This kernel needs SGI SAL version >= " - "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR); + "%x.%02x\n", SN_SAL_MIN_VERSION >> 8, + SN_SAL_MIN_VERSION & 0x00FF); panic("PROM version too old\n"); } diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index 8716f4d5314..c1cbcd1a139 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -14,6 +14,7 @@ #include <linux/proc_fs.h> #include <linux/device.h> #include <linux/delay.h> +#include <asm/system.h> #include <asm/uaccess.h> #include <asm/sn/sn_sal.h> #include <asm/sn/addrs.h> @@ -481,6 +482,9 @@ static int __init tiocx_init(void) cnodeid_t cnodeid; int found_tiocx_device = 0; + if (!ia64_platform_is("sn2")) + return -ENODEV; + bus_register(&tiocx_bus_type); for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) { diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index 5da9bdbde7c..a2f7a88aefb 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -11,9 +11,10 @@ #include <linux/module.h> #include <asm/dma.h> -#include <asm/sn/sn_sal.h> +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> +#include <asm/sn/sn_sal.h> #define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c index 0e47bce85f2..d1647b863e6 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c @@ -8,9 +8,9 @@ #include <linux/types.h> #include <asm/sn/sn_sal.h> +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> -#include "pci/pcibr_provider.h" int pcibr_invalidate_ate = 0; /* by default don't invalidate ATE on free */ diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index 64af2b2c178..b058dc2a0b9 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c @@ -8,18 +8,17 @@ #include <linux/types.h> #include <linux/pci.h> -#include <asm/sn/sn_sal.h> +#include <asm/sn/addrs.h> #include <asm/sn/geo.h> -#include "xtalk/xwidgetdev.h" -#include "xtalk/hubdev.h" +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> -#include "pci/tiocp.h" -#include "pci/pic.h" -#include "pci/pcibr_provider.h" -#include "pci/tiocp.h" +#include <asm/sn/pic.h> +#include <asm/sn/sn_sal.h> +#include <asm/sn/tiocp.h> #include "tio.h" -#include <asm/sn/addrs.h> +#include "xtalk/xwidgetdev.h" +#include "xtalk/hubdev.h" extern int sn_ioif_inited; diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index 3893999d23d..9813da56d31 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -6,18 +6,51 @@ * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved. */ -#include <linux/types.h> #include <linux/interrupt.h> +#include <linux/types.h> #include <linux/pci.h> -#include <asm/sn/sn_sal.h> -#include "xtalk/xwidgetdev.h" +#include <asm/sn/addrs.h> #include <asm/sn/geo.h> -#include "xtalk/hubdev.h" +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> -#include "pci/pcibr_provider.h" -#include <asm/sn/addrs.h> +#include <asm/sn/sn_sal.h> +#include "xtalk/xwidgetdev.h" +#include "xtalk/hubdev.h" + +int +sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp) +{ + struct ia64_sal_retval ret_stuff; + uint64_t busnum; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + busnum = soft->pbi_buscommon.bs_persist_busnum; + SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, (u64) busnum, + (u64) device, (u64) resp, 0, 0, 0, 0); + + return (int)ret_stuff.v0; +} + +int +sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action, + void *resp) +{ + struct ia64_sal_retval ret_stuff; + uint64_t busnum; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + + busnum = soft->pbi_buscommon.bs_persist_busnum; + SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE, + (u64) busnum, (u64) device, (u64) action, + (u64) resp, 0, 0, 0); + + return (int)ret_stuff.v0; +} static int sal_pcibr_error_interrupt(struct pcibus_info *soft) { @@ -188,3 +221,6 @@ pcibr_init_provider(void) return 0; } + +EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable); +EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable); diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c index 865c11c3b50..21426d02fbe 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c @@ -6,13 +6,13 @@ * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. */ -#include <linux/types.h> #include <linux/interrupt.h> +#include <linux/types.h> +#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcidev.h> -#include "pci/tiocp.h" -#include "pci/pic.h" -#include "pci/pcibr_provider.h" +#include <asm/sn/pic.h> +#include <asm/sn/tiocp.h> union br_ptr { struct tiocp tio; diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index 05aa8c2fe9b..51cc4e63092 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c @@ -589,8 +589,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft) /* sanity check prom rev */ - if (sn_sal_rev_major() < 4 || - (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) { + if (sn_sal_rev() < 0x0406) { printk (KERN_ERR "%s: SGI prom rev 4.06 or greater required " "for tioca support\n", __FUNCTION__); diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c index b014e2c1e52..a146b24a556 100644 --- a/arch/m32r/kernel/setup_m32700ut.c +++ b/arch/m32r/kernel/setup_m32700ut.c @@ -3,8 +3,8 @@ * * Setup routines for Renesas M32700UT Board * - * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Takeo Takahashi + * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Takeo Takahashi * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this @@ -435,7 +435,7 @@ void __init init_IRQ(void) icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; enable_m32700ut_irq(M32R_IRQ_INT2); -//#if defined(CONFIG_VIDEO_M32R_AR) +#if defined(CONFIG_VIDEO_M32R_AR) /* * INT3# is used for AR */ @@ -445,9 +445,11 @@ void __init init_IRQ(void) irq_desc[M32R_IRQ_INT3].depth = 1; icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; disable_m32700ut_irq(M32R_IRQ_INT3); -//#endif /* CONFIG_VIDEO_M32R_AR */ +#endif /* CONFIG_VIDEO_M32R_AR */ } +#if defined(CONFIG_SMC91X) + #define LAN_IOSTART 0x300 #define LAN_IOEND 0x320 static struct resource smc91x_resources[] = { @@ -469,10 +471,55 @@ static struct platform_device smc91x_device = { .num_resources = ARRAY_SIZE(smc91x_resources), .resource = smc91x_resources, }; +#endif + +#if defined(CONFIG_FB_S1D13XXX) + +#include <video/s1d13xxxfb.h> +#include <asm/s1d13806.h> + +static struct s1d13xxxfb_pdata s1d13xxxfb_data = { + .initregs = s1d13xxxfb_initregs, + .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs), + .platform_init_video = NULL, +#ifdef CONFIG_PM + .platform_suspend_video = NULL, + .platform_resume_video = NULL, +#endif +}; + +static struct resource s1d13xxxfb_resources[] = { + [0] = { + .start = 0x10600000UL, + .end = 0x1073FFFFUL, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x10400000UL, + .end = 0x104001FFUL, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device s1d13xxxfb_device = { + .name = S1D_DEVICENAME, + .id = 0, + .dev = { + .platform_data = &s1d13xxxfb_data, + }, + .num_resources = ARRAY_SIZE(s1d13xxxfb_resources), + .resource = s1d13xxxfb_resources, +}; +#endif static int __init platform_init(void) { +#if defined(CONFIG_SMC91X) platform_device_register(&smc91x_device); +#endif +#if defined(CONFIG_FB_S1D13XXX) + platform_device_register(&s1d13xxxfb_device); +#endif return 0; } arch_initcall(platform_init); diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c index aaf8e569b93..4e709809efc 100644 --- a/arch/m32r/kernel/setup_mappi.c +++ b/arch/m32r/kernel/setup_mappi.c @@ -3,14 +3,15 @@ * * Setup routines for Renesas MAPPI Board * - * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto */ #include <linux/config.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/device.h> #include <asm/system.h> #include <asm/m32r.h> @@ -158,3 +159,49 @@ void __init init_IRQ(void) disable_mappi_irq(M32R_IRQ_INT2); #endif /* CONFIG_M32RPCC */ } + +#if defined(CONFIG_FB_S1D13XXX) + +#include <video/s1d13xxxfb.h> +#include <asm/s1d13806.h> + +static struct s1d13xxxfb_pdata s1d13xxxfb_data = { + .initregs = s1d13xxxfb_initregs, + .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs), + .platform_init_video = NULL, +#ifdef CONFIG_PM + .platform_suspend_video = NULL, + .platform_resume_video = NULL, +#endif +}; + +static struct resource s1d13xxxfb_resources[] = { + [0] = { + .start = 0x10200000UL, + .end = 0x1033FFFFUL, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x10000000UL, + .end = 0x100001FFUL, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device s1d13xxxfb_device = { + .name = S1D_DEVICENAME, + .id = 0, + .dev = { + .platform_data = &s1d13xxxfb_data, + }, + .num_resources = ARRAY_SIZE(s1d13xxxfb_resources), + .resource = s1d13xxxfb_resources, +}; + +static int __init platform_init(void) +{ + platform_device_register(&s1d13xxxfb_device); + return 0; +} +arch_initcall(platform_init); +#endif diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c index 38d5e9a4142..a1d801598aa 100644 --- a/arch/m32r/kernel/setup_mappi2.c +++ b/arch/m32r/kernel/setup_mappi2.c @@ -3,8 +3,8 @@ * * Setup routines for Renesas MAPPI-II(M3A-ZA36) Board * - * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Mamoru Sakugawa + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa */ #include <linux/config.h> diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c index 3d60a85aaec..a76412e883e 100644 --- a/arch/m32r/kernel/setup_mappi3.c +++ b/arch/m32r/kernel/setup_mappi3.c @@ -3,8 +3,8 @@ * * Setup routines for Renesas MAPPI-III(M3A-2170) Board * - * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Mamoru Sakugawa + * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa */ #include <linux/config.h> @@ -178,6 +178,8 @@ void __init init_IRQ(void) #endif /* CONFIG_M32R_CFC */ } +#if defined(CONFIG_SMC91X) + #define LAN_IOSTART 0x300 #define LAN_IOEND 0x320 static struct resource smc91x_resources[] = { @@ -200,9 +202,55 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; +#endif + +#if defined(CONFIG_FB_S1D13XXX) + +#include <video/s1d13xxxfb.h> +#include <asm/s1d13806.h> + +static struct s1d13xxxfb_pdata s1d13xxxfb_data = { + .initregs = s1d13xxxfb_initregs, + .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs), + .platform_init_video = NULL, +#ifdef CONFIG_PM + .platform_suspend_video = NULL, + .platform_resume_video = NULL, +#endif +}; + +static struct resource s1d13xxxfb_resources[] = { + [0] = { + .start = 0x1d600000UL, + .end = 0x1d73FFFFUL, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x1d400000UL, + .end = 0x1d4001FFUL, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device s1d13xxxfb_device = { + .name = S1D_DEVICENAME, + .id = 0, + .dev = { + .platform_data = &s1d13xxxfb_data, + }, + .num_resources = ARRAY_SIZE(s1d13xxxfb_resources), + .resource = s1d13xxxfb_resources, +}; +#endif + static int __init platform_init(void) { +#if defined(CONFIG_SMC91X) platform_device_register(&smc91x_device); +#endif +#if defined(CONFIG_FB_S1D13XXX) + platform_device_register(&s1d13xxxfb_device); +#endif return 0; } arch_initcall(platform_init); diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c index d656640badc..45add5b76f1 100644 --- a/arch/m32r/kernel/setup_oaks32r.c +++ b/arch/m32r/kernel/setup_oaks32r.c @@ -3,8 +3,8 @@ * * Setup routines for OAKS32R Board * - * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata, - * Hitoshi Yamamoto, Mamoru Sakugawa + * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata, + * Hitoshi Yamamoto, Mamoru Sakugawa */ #include <linux/config.h> @@ -139,5 +139,4 @@ void __init init_IRQ(void) icu_data[M32R_IRQ_SIO1_S].icucr = 0; disable_oaks32r_irq(M32R_IRQ_SIO1_S); #endif /* CONFIG_SERIAL_M32R_SIO */ - } diff --git a/arch/m32r/kernel/setup_opsput.c b/arch/m32r/kernel/setup_opsput.c index 86f4cf2a86c..f0301f58bcc 100644 --- a/arch/m32r/kernel/setup_opsput.c +++ b/arch/m32r/kernel/setup_opsput.c @@ -3,7 +3,7 @@ * * Setup routines for Renesas OPSPUT Board * - * Copyright (c) 2002-2004 + * Copyright (c) 2002-2005 * Hiroyuki Kondo, Hirokazu Takata, * Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa * @@ -439,7 +439,7 @@ void __init init_IRQ(void) icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01; enable_opsput_irq(M32R_IRQ_INT2); -//#if defined(CONFIG_VIDEO_M32R_AR) +#if defined(CONFIG_VIDEO_M32R_AR) /* * INT3# is used for AR */ @@ -449,9 +449,11 @@ void __init init_IRQ(void) irq_desc[M32R_IRQ_INT3].depth = 1; icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10; disable_opsput_irq(M32R_IRQ_INT3); -//#endif /* CONFIG_VIDEO_M32R_AR */ +#endif /* CONFIG_VIDEO_M32R_AR */ } +#if defined(CONFIG_SMC91X) + #define LAN_IOSTART 0x300 #define LAN_IOEND 0x320 static struct resource smc91x_resources[] = { @@ -473,10 +475,55 @@ static struct platform_device smc91x_device = { .num_resources = ARRAY_SIZE(smc91x_resources), .resource = smc91x_resources, }; +#endif + +#if defined(CONFIG_FB_S1D13XXX) + +#include <video/s1d13xxxfb.h> +#include <asm/s1d13806.h> + +static struct s1d13xxxfb_pdata s1d13xxxfb_data = { + .initregs = s1d13xxxfb_initregs, + .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs), + .platform_init_video = NULL, +#ifdef CONFIG_PM + .platform_suspend_video = NULL, + .platform_resume_video = NULL, +#endif +}; + +static struct resource s1d13xxxfb_resources[] = { + [0] = { + .start = 0x10600000UL, + .end = 0x1073FFFFUL, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0x10400000UL, + .end = 0x104001FFUL, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device s1d13xxxfb_device = { + .name = S1D_DEVICENAME, + .id = 0, + .dev = { + .platform_data = &s1d13xxxfb_data, + }, + .num_resources = ARRAY_SIZE(s1d13xxxfb_resources), + .resource = s1d13xxxfb_resources, +}; +#endif static int __init platform_init(void) { +#if defined(CONFIG_SMC91X) platform_device_register(&smc91x_device); +#endif +#if defined(CONFIG_FB_S1D13XXX) + platform_device_register(&s1d13xxxfb_device); +#endif return 0; } arch_initcall(platform_init); diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 5fdd4f607a4..c0605244edd 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np) return offset; } -static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state) +static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg) { /* Ok, this could be made a bit smarter, but let's be robust for now. We * always force a speed change to high speed before sleep, to make sure diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c index 49c0e34e2d6..1eb4f726ca9 100644 --- a/arch/ppc/syslib/of_device.c +++ b/arch/ppc/syslib/of_device.c @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <asm/errno.h> #include <asm/of_device.h> @@ -15,20 +16,20 @@ * Used by a driver to check whether an of_device present in the * system is in its list of supported devices. */ -const struct of_match * of_match_device(const struct of_match *matches, +const struct of_device_id * of_match_device(const struct of_device_id *matches, const struct of_device *dev) { if (!dev->node) return NULL; - while (matches->name || matches->type || matches->compatible) { + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; - if (matches->name && matches->name != OF_ANY_MATCH) + if (matches->name[0]) match &= dev->node->name && !strcmp(matches->name, dev->node->name); - if (matches->type && matches->type != OF_ANY_MATCH) + if (matches->type[0]) match &= dev->node->type && !strcmp(matches->type, dev->node->type); - if (matches->compatible && matches->compatible != OF_ANY_MATCH) + if (matches->compatible[0]) match &= device_is_compatible(dev->node, matches->compatible); if (match) @@ -42,7 +43,7 @@ static int of_platform_bus_match(struct device *dev, struct device_driver *drv) { struct of_device * of_dev = to_of_device(dev); struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_match * matches = of_drv->match_table; + const struct of_device_id * matches = of_drv->match_table; if (!matches) return 0; @@ -75,7 +76,7 @@ static int of_device_probe(struct device *dev) int error = -ENODEV; struct of_platform_driver *drv; struct of_device *of_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); of_dev = to_of_device(dev); diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 1d162c7c59d..8d4c46f6f0b 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c @@ -49,160 +49,219 @@ extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); #endif struct cpu_spec cpu_specs[] = { - { /* Power3 */ - 0xffff0000, 0x00400000, "POWER3 (630)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* Power3+ */ - 0xffff0000, 0x00410000, "POWER3 (630+)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* Northstar */ - 0xffff0000, 0x00330000, "RS64-II (northstar)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* Pulsar */ - 0xffff0000, 0x00340000, "RS64-III (pulsar)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* I-star */ - 0xffff0000, 0x00360000, "RS64-III (icestar)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* S-star */ - 0xffff0000, 0x00370000, "RS64-IV (sstar)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power3, - COMMON_PPC64_FW - }, - { /* Power4 */ - 0xffff0000, 0x00350000, "POWER4 (gp)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power4, - COMMON_PPC64_FW - }, - { /* Power4+ */ - 0xffff0000, 0x00380000, "POWER4+ (gq)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power4, - COMMON_PPC64_FW - }, - { /* PPC970 */ - 0xffff0000, 0x00390000, "PPC970", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, - 128, 128, - __setup_cpu_ppc970, - COMMON_PPC64_FW - }, - { /* PPC970FX */ - 0xffff0000, 0x003c0000, "PPC970FX", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, - COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, - 128, 128, - __setup_cpu_ppc970, - COMMON_PPC64_FW - }, - { /* Power5 */ - 0xffff0000, 0x003a0000, "POWER5 (gr)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | - CPU_FTR_MMCRA_SIHV, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power4, - COMMON_PPC64_FW - }, - { /* Power5 */ - 0xffff0000, 0x003b0000, "POWER5 (gs)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | - CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | - CPU_FTR_MMCRA_SIHV, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power4, - COMMON_PPC64_FW - }, - { /* BE DD1.x */ - 0xffff0000, 0x00700000, "Broadband Engine", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | - CPU_FTR_SMT, - COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, - 128, 128, - __setup_cpu_be, - COMMON_PPC64_FW - }, - { /* default match */ - 0x00000000, 0x00000000, "POWER4 (compatible)", - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | - CPU_FTR_PPCAS_ARCH_V2, - COMMON_USER_PPC64, - 128, 128, - __setup_cpu_power4, - COMMON_PPC64_FW - } + { /* Power3 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00400000, + .cpu_name = "POWER3 (630)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Power3+ */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00410000, + .cpu_name = "POWER3 (630+)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Northstar */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00330000, + .cpu_name = "RS64-II (northstar)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Pulsar */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00340000, + .cpu_name = "RS64-III (pulsar)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* I-star */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00360000, + .cpu_name = "RS64-III (icestar)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* S-star */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00370000, + .cpu_name = "RS64-IV (sstar)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | + CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power3, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Power4 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00350000, + .cpu_name = "POWER4 (gp)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power4, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Power4+ */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00380000, + .cpu_name = "POWER4+ (gq)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power4, + .firmware_features = COMMON_PPC64_FW, + }, + { /* PPC970 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00390000, + .cpu_name = "PPC970", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_ppc970, + .firmware_features = COMMON_PPC64_FW, + }, + { /* PPC970FX */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003c0000, + .cpu_name = "PPC970FX", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_ppc970, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Power5 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003a0000, + .cpu_name = "POWER5 (gr)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | + CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | + CPU_FTR_MMCRA_SIHV, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power4, + .firmware_features = COMMON_PPC64_FW, + }, + { /* Power5 */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x003b0000, + .cpu_name = "POWER5 (gs)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT | + CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | + CPU_FTR_MMCRA_SIHV, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power4, + .firmware_features = COMMON_PPC64_FW, + }, + { /* BE DD1.x */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00700000, + .cpu_name = "Broadband Engine", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | + CPU_FTR_SMT, + .cpu_user_features = COMMON_USER_PPC64 | + PPC_FEATURE_HAS_ALTIVEC_COMP, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_be, + .firmware_features = COMMON_PPC64_FW, + }, + { /* default match */ + .pvr_mask = 0x00000000, + .pvr_value = 0x00000000, + .cpu_name = "POWER4 (compatible)", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | + CPU_FTR_PPCAS_ARCH_V2, + .cpu_user_features = COMMON_USER_PPC64, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power4, + .firmware_features = COMMON_PPC64_FW, + } }; firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = { - {FW_FEATURE_PFT, "hcall-pft"}, - {FW_FEATURE_TCE, "hcall-tce"}, - {FW_FEATURE_SPRG0, "hcall-sprg0"}, - {FW_FEATURE_DABR, "hcall-dabr"}, - {FW_FEATURE_COPY, "hcall-copy"}, - {FW_FEATURE_ASR, "hcall-asr"}, - {FW_FEATURE_DEBUG, "hcall-debug"}, - {FW_FEATURE_PERF, "hcall-perf"}, - {FW_FEATURE_DUMP, "hcall-dump"}, - {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, - {FW_FEATURE_MIGRATE, "hcall-migrate"}, - {FW_FEATURE_PERFMON, "hcall-perfmon"}, - {FW_FEATURE_CRQ, "hcall-crq"}, - {FW_FEATURE_VIO, "hcall-vio"}, - {FW_FEATURE_RDMA, "hcall-rdma"}, - {FW_FEATURE_LLAN, "hcall-lLAN"}, - {FW_FEATURE_BULK, "hcall-bulk"}, - {FW_FEATURE_XDABR, "hcall-xdabr"}, - {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, - {FW_FEATURE_SPLPAR, "hcall-splpar"}, + {FW_FEATURE_PFT, "hcall-pft"}, + {FW_FEATURE_TCE, "hcall-tce"}, + {FW_FEATURE_SPRG0, "hcall-sprg0"}, + {FW_FEATURE_DABR, "hcall-dabr"}, + {FW_FEATURE_COPY, "hcall-copy"}, + {FW_FEATURE_ASR, "hcall-asr"}, + {FW_FEATURE_DEBUG, "hcall-debug"}, + {FW_FEATURE_PERF, "hcall-perf"}, + {FW_FEATURE_DUMP, "hcall-dump"}, + {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, + {FW_FEATURE_MIGRATE, "hcall-migrate"}, + {FW_FEATURE_PERFMON, "hcall-perfmon"}, + {FW_FEATURE_CRQ, "hcall-crq"}, + {FW_FEATURE_VIO, "hcall-vio"}, + {FW_FEATURE_RDMA, "hcall-rdma"}, + {FW_FEATURE_LLAN, "hcall-lLAN"}, + {FW_FEATURE_BULK, "hcall-bulk"}, + {FW_FEATURE_XDABR, "hcall-xdabr"}, + {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, + {FW_FEATURE_SPLPAR, "hcall-splpar"}, }; diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 675c2708588..93ebcac0d5a 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -308,6 +308,7 @@ exception_marker: label##_pSeries: \ HMT_MEDIUM; \ mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) #define STD_EXCEPTION_ISERIES(n, label, area) \ @@ -315,6 +316,7 @@ label##_pSeries: \ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(area); \ EXCEPTION_PROLOG_ISERIES_2; \ b label##_common @@ -324,6 +326,7 @@ label##_iSeries: \ label##_iSeries: \ HMT_MEDIUM; \ mtspr SPRG1,r13; /* save r13 */ \ + RUNLATCH_ON(r13); \ EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \ lbz r10,PACAPROCENABLED(r13); \ cmpwi 0,r10,0; \ @@ -393,6 +396,7 @@ __start_interrupts: _machine_check_pSeries: HMT_MEDIUM mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) . = 0x300 @@ -419,6 +423,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) data_access_slb_pSeries: HMT_MEDIUM mtspr SPRG1,r13 + RUNLATCH_ON(r13) mfspr r13,SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) @@ -439,6 +444,7 @@ data_access_slb_pSeries: instruction_access_slb_pSeries: HMT_MEDIUM mtspr SPRG1,r13 + RUNLATCH_ON(r13) mfspr r13,SPRG3 /* get paca address into r13 */ std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */ std r10,PACA_EXSLB+EX_R10(r13) @@ -464,6 +470,7 @@ instruction_access_slb_pSeries: .globl system_call_pSeries system_call_pSeries: HMT_MEDIUM + RUNLATCH_ON(r9) mr r9,r13 mfmsr r10 mfspr r13,SPRG3 @@ -707,11 +714,13 @@ fwnmi_data_area: system_reset_fwnmi: HMT_MEDIUM mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) .globl machine_check_fwnmi machine_check_fwnmi: HMT_MEDIUM mtspr SPRG1,r13 /* save r13 */ + RUNLATCH_ON(r13) EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) /* @@ -848,6 +857,7 @@ unrecov_fer: .align 7 .globl data_access_common data_access_common: + RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */ mfspr r10,DAR std r10,PACA_EXGEN+EX_DAR(r13) mfspr r10,DSISR diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c index c72fb8ffe97..138e128a388 100644 --- a/arch/ppc64/kernel/hvconsole.c +++ b/arch/ppc64/kernel/hvconsole.c @@ -27,7 +27,6 @@ #include <linux/module.h> #include <asm/hvcall.h> #include <asm/hvconsole.h> -#include <asm/prom.h> /** * hvc_get_chars - retrieve characters from firmware for denoted vterm adatper @@ -42,29 +41,14 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count) unsigned long got; if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { - /* - * Work around a HV bug where it gives us a null - * after every \r. -- paulus - */ - if (got > 0) { - int i; - for (i = 1; i < got; ++i) { - if (buf[i] == 0 && buf[i-1] == '\r') { - --got; - if (i < got) - memmove(&buf[i], &buf[i+1], - got - i); - } - } - } + (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) return got; - } return 0; } EXPORT_SYMBOL(hvc_get_chars); + /** * hvc_put_chars: send characters to firmware for denoted vterm adapter * @vtermno: The vtermno or unit_address of the adapter from which the data @@ -88,34 +72,3 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count) } EXPORT_SYMBOL(hvc_put_chars); - -/* - * We hope/assume that the first vty found corresponds to the first console - * device. - */ -int hvc_find_vtys(void) -{ - struct device_node *vty; - int num_found = 0; - - for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; - vty = of_find_node_by_name(vty, "vty")) { - uint32_t *vtermno; - - /* We have statically defined space for only a certain number of - * console adapters. */ - if (num_found >= MAX_NR_HVC_CONSOLES) - break; - - vtermno = (uint32_t *)get_property(vty, "reg", NULL); - if (!vtermno) - continue; - - if (device_is_compatible(vty, "hvterm1")) { - hvc_instantiate(*vtermno, num_found); - ++num_found; - } - } - - return num_found; -} diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index b3f770f6d40..077c82fc9f3 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c @@ -834,6 +834,92 @@ static int __init iSeries_src_init(void) late_initcall(iSeries_src_init); +static inline void process_iSeries_events(void) +{ + asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); +} + +static void yield_shared_processor(void) +{ + unsigned long tb; + + HvCall_setEnabledInterrupts(HvCall_MaskIPI | + HvCall_MaskLpEvent | + HvCall_MaskLpProd | + HvCall_MaskTimeout); + + tb = get_tb(); + /* Compute future tb value when yield should expire */ + HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); + + /* + * The decrementer stops during the yield. Force a fake decrementer + * here and let the timer_interrupt code sort out the actual time. + */ + get_paca()->lppaca.int_dword.fields.decr_int = 1; + process_iSeries_events(); +} + +static int iseries_shared_idle(void) +{ + while (1) { + while (!need_resched() && !hvlpevent_is_pending()) { + local_irq_disable(); + ppc64_runlatch_off(); + + /* Recheck with irqs off */ + if (!need_resched() && !hvlpevent_is_pending()) + yield_shared_processor(); + + HMT_medium(); + local_irq_enable(); + } + + ppc64_runlatch_on(); + + if (hvlpevent_is_pending()) + process_iSeries_events(); + + schedule(); + } + + return 0; +} + +static int iseries_dedicated_idle(void) +{ + long oldval; + + while (1) { + oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); + + if (!oldval) { + set_thread_flag(TIF_POLLING_NRFLAG); + + while (!need_resched()) { + ppc64_runlatch_off(); + HMT_low(); + + if (hvlpevent_is_pending()) { + HMT_medium(); + ppc64_runlatch_on(); + process_iSeries_events(); + } + } + + HMT_medium(); + clear_thread_flag(TIF_POLLING_NRFLAG); + } else { + set_need_resched(); + } + + ppc64_runlatch_on(); + schedule(); + } + + return 0; +} + #ifndef CONFIG_PCI void __init iSeries_init_IRQ(void) { } #endif @@ -859,5 +945,13 @@ void __init iSeries_early_setup(void) ppc_md.get_rtc_time = iSeries_get_rtc_time; ppc_md.calibrate_decr = iSeries_calibrate_decr; ppc_md.progress = iSeries_progress; + + if (get_paca()->lppaca.shared_proc) { + ppc_md.idle_loop = iseries_shared_idle; + printk(KERN_INFO "Using shared processor idle loop\n"); + } else { + ppc_md.idle_loop = iseries_dedicated_idle; + printk(KERN_INFO "Using dedicated idle loop\n"); + } } diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 08952c7e621..954395d4263 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -20,109 +20,18 @@ #include <linux/kernel.h> #include <linux/smp.h> #include <linux/cpu.h> -#include <linux/module.h> #include <linux/sysctl.h> -#include <linux/smp.h> #include <asm/system.h> #include <asm/processor.h> -#include <asm/mmu.h> #include <asm/cputable.h> #include <asm/time.h> -#include <asm/iSeries/HvCall.h> -#include <asm/iSeries/ItLpQueue.h> -#include <asm/plpar_wrappers.h> #include <asm/systemcfg.h> +#include <asm/machdep.h> extern void power4_idle(void); -static int (*idle_loop)(void); - -#ifdef CONFIG_PPC_ISERIES -static unsigned long maxYieldTime = 0; -static unsigned long minYieldTime = 0xffffffffffffffffUL; - -static inline void process_iSeries_events(void) -{ - asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); -} - -static void yield_shared_processor(void) -{ - unsigned long tb; - unsigned long yieldTime; - - HvCall_setEnabledInterrupts(HvCall_MaskIPI | - HvCall_MaskLpEvent | - HvCall_MaskLpProd | - HvCall_MaskTimeout); - - tb = get_tb(); - /* Compute future tb value when yield should expire */ - HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); - - yieldTime = get_tb() - tb; - if (yieldTime > maxYieldTime) - maxYieldTime = yieldTime; - - if (yieldTime < minYieldTime) - minYieldTime = yieldTime; - - /* - * The decrementer stops during the yield. Force a fake decrementer - * here and let the timer_interrupt code sort out the actual time. - */ - get_paca()->lppaca.int_dword.fields.decr_int = 1; - process_iSeries_events(); -} - -static int iSeries_idle(void) -{ - struct paca_struct *lpaca; - long oldval; - - /* ensure iSeries run light will be out when idle */ - ppc64_runlatch_off(); - - lpaca = get_paca(); - - while (1) { - if (lpaca->lppaca.shared_proc) { - if (hvlpevent_is_pending()) - process_iSeries_events(); - if (!need_resched()) - yield_shared_processor(); - } else { - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - - if (!oldval) { - set_thread_flag(TIF_POLLING_NRFLAG); - - while (!need_resched()) { - HMT_medium(); - if (hvlpevent_is_pending()) - process_iSeries_events(); - HMT_low(); - } - - HMT_medium(); - clear_thread_flag(TIF_POLLING_NRFLAG); - } else { - set_need_resched(); - } - } - - ppc64_runlatch_on(); - schedule(); - ppc64_runlatch_off(); - } - - return 0; -} - -#else - -static int default_idle(void) +int default_idle(void) { long oldval; unsigned int cpu = smp_processor_id(); @@ -134,7 +43,8 @@ static int default_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); while (!need_resched() && !cpu_is_offline(cpu)) { - barrier(); + ppc64_runlatch_off(); + /* * Go into low thread priority and possibly * low power mode. @@ -149,6 +59,7 @@ static int default_idle(void) set_need_resched(); } + ppc64_runlatch_on(); schedule(); if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) cpu_die(); @@ -157,127 +68,19 @@ static int default_idle(void) return 0; } -#ifdef CONFIG_PPC_PSERIES - -DECLARE_PER_CPU(unsigned long, smt_snooze_delay); - -int dedicated_idle(void) +int native_idle(void) { - long oldval; - struct paca_struct *lpaca = get_paca(), *ppaca; - unsigned long start_snooze; - unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); - unsigned int cpu = smp_processor_id(); - - ppaca = &paca[cpu ^ 1]; - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - lpaca->lppaca.idle = 1; - - oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); - if (!oldval) { - set_thread_flag(TIF_POLLING_NRFLAG); - start_snooze = __get_tb() + - *smt_snooze_delay * tb_ticks_per_usec; - while (!need_resched() && !cpu_is_offline(cpu)) { - /* - * Go into low thread priority and possibly - * low power mode. - */ - HMT_low(); - HMT_very_low(); - - if (*smt_snooze_delay == 0 || - __get_tb() < start_snooze) - continue; - - HMT_medium(); - - if (!(ppaca->lppaca.idle)) { - local_irq_disable(); - - /* - * We are about to sleep the thread - * and so wont be polling any - * more. - */ - clear_thread_flag(TIF_POLLING_NRFLAG); - - /* - * SMT dynamic mode. Cede will result - * in this thread going dormant, if the - * partner thread is still doing work. - * Thread wakes up if partner goes idle, - * an interrupt is presented, or a prod - * occurs. Returning from the cede - * enables external interrupts. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); - } else { - /* - * Give the HV an opportunity at the - * processor, since we are not doing - * any work. - */ - poll_pending(); - } - } - - clear_thread_flag(TIF_POLLING_NRFLAG); - } else { - set_need_resched(); - } - - HMT_medium(); - lpaca->lppaca.idle = 0; - schedule(); - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - } - return 0; -} - -static int shared_idle(void) -{ - struct paca_struct *lpaca = get_paca(); - unsigned int cpu = smp_processor_id(); - - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - lpaca->lppaca.idle = 1; + ppc64_runlatch_off(); - while (!need_resched() && !cpu_is_offline(cpu)) { - local_irq_disable(); + if (!need_resched()) + power4_idle(); - /* - * Yield the processor to the hypervisor. We return if - * an external interrupt occurs (which are driven prior - * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts - * are enabled. - * - * Check need_resched() again with interrupts disabled - * to avoid a race. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); + if (need_resched()) { + ppc64_runlatch_on(); + schedule(); } - HMT_medium(); - lpaca->lppaca.idle = 0; - schedule(); if (cpu_is_offline(smp_processor_id()) && system_state == SYSTEM_RUNNING) cpu_die(); @@ -286,29 +89,10 @@ static int shared_idle(void) return 0; } -#endif /* CONFIG_PPC_PSERIES */ - -static int native_idle(void) -{ - while(1) { - /* check CPU type here */ - if (!need_resched()) - power4_idle(); - if (need_resched()) - schedule(); - - if (cpu_is_offline(raw_smp_processor_id()) && - system_state == SYSTEM_RUNNING) - cpu_die(); - } - return 0; -} - -#endif /* CONFIG_PPC_ISERIES */ - void cpu_idle(void) { - idle_loop(); + BUG_ON(NULL == ppc_md.idle_loop); + ppc_md.idle_loop(); } int powersave_nap; @@ -342,42 +126,3 @@ register_powersave_nap_sysctl(void) } __initcall(register_powersave_nap_sysctl); #endif - -int idle_setup(void) -{ - /* - * Move that junk to each platform specific file, eventually define - * a pSeries_idle for shared processor stuff - */ -#ifdef CONFIG_PPC_ISERIES - idle_loop = iSeries_idle; - return 1; -#else - idle_loop = default_idle; -#endif -#ifdef CONFIG_PPC_PSERIES - if (systemcfg->platform & PLATFORM_PSERIES) { - if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { - if (get_paca()->lppaca.shared_proc) { - printk(KERN_INFO "Using shared processor idle loop\n"); - idle_loop = shared_idle; - } else { - printk(KERN_INFO "Using dedicated idle loop\n"); - idle_loop = dedicated_idle; - } - } else { - printk(KERN_INFO "Using default idle loop\n"); - idle_loop = default_idle; - } - } -#endif /* CONFIG_PPC_PSERIES */ -#ifndef CONFIG_PPC_ISERIES - if (systemcfg->platform == PLATFORM_POWERMAC || - systemcfg->platform == PLATFORM_MAPLE) { - printk(KERN_INFO "Using native/NAP idle loop\n"); - idle_loop = native_idle; - } -#endif /* CONFIG_PPC_ISERIES */ - - return 1; -} diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index da8900b51f4..bb55b5a5691 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c @@ -177,6 +177,8 @@ void __init maple_setup_arch(void) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + + printk(KERN_INFO "Using native/NAP idle loop\n"); } /* @@ -297,4 +299,5 @@ struct machdep_calls __initdata maple_md = { .get_rtc_time = maple_get_rtc_time, .calibrate_decr = generic_calibrate_decr, .progress = maple_progress, + .idle_loop = native_idle, }; diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index f3dea0c5a88..59f4f997381 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -1124,9 +1124,11 @@ _GLOBAL(sys_call_table32) .llong .compat_sys_mq_getsetattr .llong .compat_sys_kexec_load .llong .sys32_add_key - .llong .sys32_request_key + .llong .sys32_request_key /* 270 */ .llong .compat_sys_keyctl .llong .compat_sys_waitid + .llong .sys32_ioprio_set + .llong .sys32_ioprio_get .balign 8 _GLOBAL(sys_call_table) @@ -1403,3 +1405,5 @@ _GLOBAL(sys_call_table) .llong .sys_request_key /* 270 */ .llong .sys_keyctl .llong .sys_waitid + .llong .sys_ioprio_set + .llong .sys_ioprio_get diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c index 66bd5ab7c25..b80e81984ba 100644 --- a/arch/ppc64/kernel/of_device.c +++ b/arch/ppc64/kernel/of_device.c @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <asm/errno.h> #include <asm/of_device.h> @@ -15,20 +16,20 @@ * Used by a driver to check whether an of_device present in the * system is in its list of supported devices. */ -const struct of_match * of_match_device(const struct of_match *matches, +const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct of_device *dev) { if (!dev->node) return NULL; - while (matches->name || matches->type || matches->compatible) { + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; - if (matches->name && matches->name != OF_ANY_MATCH) + if (matches->name[0]) match &= dev->node->name && !strcmp(matches->name, dev->node->name); - if (matches->type && matches->type != OF_ANY_MATCH) + if (matches->type[0]) match &= dev->node->type && !strcmp(matches->type, dev->node->type); - if (matches->compatible && matches->compatible != OF_ANY_MATCH) + if (matches->compatible[0]) match &= device_is_compatible(dev->node, matches->compatible); if (match) @@ -42,7 +43,7 @@ static int of_platform_bus_match(struct device *dev, struct device_driver *drv) { struct of_device * of_dev = to_of_device(dev); struct of_platform_driver * of_drv = to_of_platform_driver(drv); - const struct of_match * matches = of_drv->match_table; + const struct of_device_id * matches = of_drv->match_table; if (!matches) return 0; @@ -75,7 +76,7 @@ static int of_device_probe(struct device *dev) int error = -ENODEV; struct of_platform_driver *drv; struct of_device *of_dev; - const struct of_match *match; + const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); of_dev = to_of_device(dev); diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 44d9af72d22..5bec956e44a 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -19,6 +19,7 @@ #undef DEBUG #include <linux/config.h> +#include <linux/cpu.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -82,6 +83,9 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */ extern void pSeries_system_reset_exception(struct pt_regs *regs); extern int pSeries_machine_check_exception(struct pt_regs *regs); +static int pseries_shared_idle(void); +static int pseries_dedicated_idle(void); + static volatile void __iomem * chrp_int_ack_special; struct mpic *pSeries_mpic; @@ -229,6 +233,20 @@ static void __init pSeries_setup_arch(void) if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) vpa_init(boot_cpuid); + + /* Choose an idle loop */ + if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { + if (get_paca()->lppaca.shared_proc) { + printk(KERN_INFO "Using shared processor idle loop\n"); + ppc_md.idle_loop = pseries_shared_idle; + } else { + printk(KERN_INFO "Using dedicated idle loop\n"); + ppc_md.idle_loop = pseries_dedicated_idle; + } + } else { + printk(KERN_INFO "Using default idle loop\n"); + ppc_md.idle_loop = default_idle; + } } static int __init pSeries_init_panel(void) @@ -418,6 +436,144 @@ static int __init pSeries_probe(int platform) return 1; } +DECLARE_PER_CPU(unsigned long, smt_snooze_delay); + +static inline void dedicated_idle_sleep(unsigned int cpu) +{ + struct paca_struct *ppaca = &paca[cpu ^ 1]; + + /* Only sleep if the other thread is not idle */ + if (!(ppaca->lppaca.idle)) { + local_irq_disable(); + + /* + * We are about to sleep the thread and so wont be polling any + * more. + */ + clear_thread_flag(TIF_POLLING_NRFLAG); + + /* + * SMT dynamic mode. Cede will result in this thread going + * dormant, if the partner thread is still doing work. Thread + * wakes up if partner goes idle, an interrupt is presented, or + * a prod occurs. Returning from the cede enables external + * interrupts. + */ + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); + } else { + /* + * Give the HV an opportunity at the processor, since we are + * not doing any work. + */ + poll_pending(); + } +} + +static int pseries_dedicated_idle(void) +{ + long oldval; + struct paca_struct *lpaca = get_paca(); + unsigned int cpu = smp_processor_id(); + unsigned long start_snooze; + unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); + + while (1) { + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + lpaca->lppaca.idle = 1; + + oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); + if (!oldval) { + set_thread_flag(TIF_POLLING_NRFLAG); + + start_snooze = __get_tb() + + *smt_snooze_delay * tb_ticks_per_usec; + + while (!need_resched() && !cpu_is_offline(cpu)) { + ppc64_runlatch_off(); + + /* + * Go into low thread priority and possibly + * low power mode. + */ + HMT_low(); + HMT_very_low(); + + if (*smt_snooze_delay != 0 && + __get_tb() > start_snooze) { + HMT_medium(); + dedicated_idle_sleep(cpu); + } + + } + + HMT_medium(); + clear_thread_flag(TIF_POLLING_NRFLAG); + } else { + set_need_resched(); + } + + lpaca->lppaca.idle = 0; + ppc64_runlatch_on(); + + schedule(); + + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) + cpu_die(); + } +} + +static int pseries_shared_idle(void) +{ + struct paca_struct *lpaca = get_paca(); + unsigned int cpu = smp_processor_id(); + + while (1) { + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + lpaca->lppaca.idle = 1; + + while (!need_resched() && !cpu_is_offline(cpu)) { + local_irq_disable(); + ppc64_runlatch_off(); + + /* + * Yield the processor to the hypervisor. We return if + * an external interrupt occurs (which are driven prior + * to returning here) or if a prod occurs from another + * processor. When returning here, external interrupts + * are enabled. + * + * Check need_resched() again with interrupts disabled + * to avoid a race. + */ + if (!need_resched()) + cede_processor(); + else + local_irq_enable(); + + HMT_medium(); + } + + lpaca->lppaca.idle = 0; + ppc64_runlatch_on(); + + schedule(); + + if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) + cpu_die(); + } + + return 0; +} + struct machdep_calls __initdata pSeries_md = { .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 6cf03d387b9..3013cdb5f93 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -186,6 +186,8 @@ void __init pmac_setup_arch(void) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + + printk(KERN_INFO "Using native/NAP idle loop\n"); } #ifdef CONFIG_SCSI @@ -507,5 +509,6 @@ struct machdep_calls __initdata pmac_md = { .calibrate_decr = pmac_calibrate_decr, .feature_call = pmac_do_feature_call, .progress = pmac_progress, - .check_legacy_ioport = pmac_check_legacy_ioport + .check_legacy_ioport = pmac_check_legacy_ioport, + .idle_loop = native_idle, }; diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index d5e4866e9ac..d1b33f0b26c 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c @@ -96,7 +96,6 @@ extern void udbg_init_maple_realmode(void); extern unsigned long klimit; extern void mm_init_ppc64(void); -extern int idle_setup(void); extern void stab_initialize(unsigned long stab); extern void htab_initialize(void); extern void early_init_devtree(void *flat_dt); @@ -1081,8 +1080,11 @@ void __init setup_arch(char **cmdline_p) ppc_md.setup_arch(); - /* Select the correct idle loop for the platform. */ - idle_setup(); + /* Use the default idle loop if the platform hasn't provided one. */ + if (NULL == ppc_md.idle_loop) { + ppc_md.idle_loop = default_idle; + printk(KERN_INFO "Using default idle loop\n"); + } paging_init(); ppc64_boot_msg(0x15, "Setup Done"); diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 118436e8085..206619080e6 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -30,47 +30,26 @@ #include <linux/sem.h> #include <linux/msg.h> #include <linux/shm.h> -#include <linux/slab.h> -#include <linux/uio.h> -#include <linux/aio.h> -#include <linux/nfs_fs.h> -#include <linux/module.h> -#include <linux/sunrpc/svc.h> -#include <linux/nfsd/nfsd.h> -#include <linux/nfsd/cache.h> -#include <linux/nfsd/xdr.h> -#include <linux/nfsd/syscall.h> #include <linux/poll.h> #include <linux/personality.h> #include <linux/stat.h> -#include <linux/filter.h> -#include <linux/highmem.h> -#include <linux/highuid.h> #include <linux/mman.h> -#include <linux/ipv6.h> #include <linux/in.h> -#include <linux/icmpv6.h> #include <linux/syscalls.h> #include <linux/unistd.h> #include <linux/sysctl.h> #include <linux/binfmts.h> -#include <linux/dnotify.h> #include <linux/security.h> #include <linux/compat.h> #include <linux/ptrace.h> -#include <linux/aio_abi.h> #include <linux/elf.h> -#include <net/scm.h> -#include <net/sock.h> - #include <asm/ptrace.h> #include <asm/types.h> #include <asm/ipc.h> #include <asm/uaccess.h> #include <asm/unistd.h> #include <asm/semaphore.h> -#include <asm/ppcdebug.h> #include <asm/time.h> #include <asm/mmu_context.h> #include <asm/systemcfg.h> @@ -350,8 +329,6 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp) return ret; } - -/* These are here just in case some old sparc32 binary calls it. */ asmlinkage long sys32_pause(void) { current->state = TASK_INTERRUPTIBLE; @@ -360,8 +337,6 @@ asmlinkage long sys32_pause(void) return -ERESTARTNOHAND; } - - static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) { long usec; @@ -847,16 +822,6 @@ asmlinkage long sys32_getpgid(u32 pid) } -/* Note: it is necessary to treat which and who as unsigned ints, - * with the corresponding cast to a signed int to insure that the - * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) - * and the register representation of a signed int (msr in 64-bit mode) is performed. - */ -asmlinkage long sys32_getpriority(u32 which, u32 who) -{ - return sys_getpriority((int)which, (int)who); -} - /* Note: it is necessary to treat pid as an unsigned int, * with the corresponding cast to a signed int to insure that the @@ -1048,6 +1013,11 @@ asmlinkage long sys32_setpgid(u32 pid, u32 pgid) return sys_setpgid((int)pid, (int)pgid); } +long sys32_getpriority(u32 which, u32 who) +{ + /* sign extend which and who */ + return sys_getpriority((int)which, (int)who); +} long sys32_setpriority(u32 which, u32 who, u32 niceval) { @@ -1055,6 +1025,18 @@ long sys32_setpriority(u32 which, u32 who, u32 niceval) return sys_setpriority((int)which, (int)who, (int)niceval); } +long sys32_ioprio_get(u32 which, u32 who) +{ + /* sign extend which and who */ + return sys_ioprio_get((int)which, (int)who); +} + +long sys32_ioprio_set(u32 which, u32 who, u32 ioprio) +{ + /* sign extend which, who and ioprio */ + return sys_ioprio_set((int)which, (int)who, (int)ioprio); +} + /* Note: it is necessary to treat newmask as an unsigned int, * with the corresponding cast to a signed int to insure that the * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) @@ -1273,8 +1255,6 @@ long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, (u64)len_high << 32 | len_low, advice); } -extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *); - long ppc32_timer_create(clockid_t clock, struct compat_sigevent __user *ev32, timer_t __user *timer_id) diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 2f704a2cafb..02b8ac4e016 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -112,7 +112,6 @@ void ppc64_enable_pmcs(void) unsigned long hid0; #ifdef CONFIG_PPC_PSERIES unsigned long set, reset; - int ret; #endif /* CONFIG_PPC_PSERIES */ /* Only need to enable them once */ @@ -145,11 +144,7 @@ void ppc64_enable_pmcs(void) case PLATFORM_PSERIES_LPAR: set = 1UL << 63; reset = 0; - ret = plpar_hcall_norets(H_PERFMON, set, reset); - if (ret) - printk(KERN_ERR "H_PERFMON call on cpu %u " - "returned %d\n", - smp_processor_id(), ret); + plpar_hcall_norets(H_PERFMON, set, reset); break; #endif /* CONFIG_PPC_PSERIES */ @@ -161,13 +156,6 @@ void ppc64_enable_pmcs(void) /* instruct hypervisor to maintain PMCs */ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) get_paca()->lppaca.pmcregs_in_use = 1; - - /* - * On SMT machines we have to set the run latch in the ctrl register - * in order to make PMC6 spin. - */ - if (cpu_has_feature(CPU_FTR_SMT)) - ppc64_runlatch_on(); #endif /* CONFIG_PPC_PSERIES */ } diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S index 11290c902ba..6f87a916a39 100644 --- a/arch/ppc64/kernel/vdso32/vdso32.lds.S +++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S @@ -40,9 +40,9 @@ SECTIONS .gcc_except_table : { *(.gcc_except_table) } .fixup : { *(.fixup) } - .got ALIGN(4) : { *(.got.plt) *(.got) } - .dynamic : { *(.dynamic) } :text :dynamic + .got : { *(.got) } + .plt : { *(.plt) } _end = .; __end = .; diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 928ffeb0fab..025f4516e65 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -57,11 +57,11 @@ sys_call_table: /*180*/ .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall /*185*/ .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname /*190*/ .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl -/*195*/ .long sys_epoll_wait, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask +/*195*/ .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask /*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir /*205*/ .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64 /*210*/ .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo -/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex +/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid /*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 /*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_statfs64 diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index d78bc13ebbb..6a4733683f0 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -43,6 +43,25 @@ config SPARC64_PAGE_SIZE_4MB endchoice +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + depends on PROC_FS + default y + help + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via /proc/<pid>/seccomp, it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + + If unsure, say Y. Only embedded should say N here. + +source kernel/Kconfig.hz + source "init/Kconfig" config SYSVIPC_COMPAT diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S index b73a3c85877..538522848ad 100644 --- a/arch/sparc64/kernel/dtlb_backend.S +++ b/arch/sparc64/kernel/dtlb_backend.S @@ -16,7 +16,7 @@ #elif PAGE_SHIFT == 19 #define SZ_BITS _PAGE_SZ512K #elif PAGE_SHIFT == 22 -#define SZ_BITS _PAGE_SZ4M +#define SZ_BITS _PAGE_SZ4MB #endif #define VALID_SZ_BITS (_PAGE_VALID | SZ_BITS) diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index d3973d8a719..d781f10adc5 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -22,8 +22,6 @@ #include <asm/estate.h> #include <asm/auxio.h> -/* #define SYSCALL_TRACING 1 */ - #define curptr g6 #define NR_SYSCALLS 284 /* Each OS is different... */ @@ -1554,11 +1552,12 @@ sys_ptrace: add %sp, PTREGS_OFF, %o0 nop .align 32 1: ldx [%curptr + TI_FLAGS], %l5 - andcc %l5, _TIF_SYSCALL_TRACE, %g0 + andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 be,pt %icc, rtrap clr %l6 + add %sp, PTREGS_OFF, %o0 call syscall_trace - nop + mov 1, %o1 ba,pt %xcc, rtrap clr %l6 @@ -1642,18 +1641,20 @@ linux_sparc_ni_syscall: or %l7, %lo(sys_ni_syscall), %l7 linux_syscall_trace32: + add %sp, PTREGS_OFF, %o0 call syscall_trace - nop + clr %o1 srl %i0, 0, %o0 - mov %i4, %o4 + srl %i4, 0, %o4 srl %i1, 0, %o1 srl %i2, 0, %o2 b,pt %xcc, 2f srl %i3, 0, %o3 linux_syscall_trace: + add %sp, PTREGS_OFF, %o0 call syscall_trace - nop + clr %o1 mov %i0, %o0 mov %i1, %o1 mov %i2, %o2 @@ -1671,11 +1672,6 @@ linux_sparc_syscall32: bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI srl %i0, 0, %o0 ! IEU0 sll %g1, 2, %l4 ! IEU0 Group -#ifdef SYSCALL_TRACING - call syscall_trace_entry - add %sp, PTREGS_OFF, %o0 - srl %i0, 0, %o0 -#endif srl %i4, 0, %o4 ! IEU1 lduw [%l7 + %l4], %l7 ! Load srl %i1, 0, %o1 ! IEU0 Group @@ -1683,7 +1679,7 @@ linux_sparc_syscall32: srl %i5, 0, %o5 ! IEU1 srl %i2, 0, %o2 ! IEU0 Group - andcc %l0, _TIF_SYSCALL_TRACE, %g0 ! IEU0 Group + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 bne,pn %icc, linux_syscall_trace32 ! CTI mov %i0, %l5 ! IEU1 call %l7 ! CTI Group brk forced @@ -1699,11 +1695,6 @@ linux_sparc_syscall: bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI mov %i0, %o0 ! IEU0 sll %g1, 2, %l4 ! IEU0 Group -#ifdef SYSCALL_TRACING - call syscall_trace_entry - add %sp, PTREGS_OFF, %o0 - mov %i0, %o0 -#endif mov %i1, %o1 ! IEU1 lduw [%l7 + %l4], %l7 ! Load 4: mov %i2, %o2 ! IEU0 Group @@ -1711,7 +1702,7 @@ linux_sparc_syscall: mov %i3, %o3 ! IEU1 mov %i4, %o4 ! IEU0 Group - andcc %l0, _TIF_SYSCALL_TRACE, %g0 ! IEU1 Group+1 bubble + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 bne,pn %icc, linux_syscall_trace ! CTI Group mov %i0, %l5 ! IEU0 2: call %l7 ! CTI Group brk forced @@ -1720,12 +1711,6 @@ linux_sparc_syscall: 3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] ret_sys_call: -#ifdef SYSCALL_TRACING - mov %o0, %o1 - call syscall_trace_exit - add %sp, PTREGS_OFF, %o0 - mov %o1, %o0 -#endif ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc sra %o0, 0, %o0 @@ -1745,7 +1730,7 @@ ret_sys_call: 1: cmp %o0, -ERESTART_RESTARTBLOCK bgeu,pn %xcc, 1f - andcc %l0, _TIF_SYSCALL_TRACE, %l6 + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 80: /* System call success, clear Carry condition code. */ andn %g3, %g2, %g3 @@ -1760,7 +1745,7 @@ ret_sys_call: /* System call failure, set Carry condition code. * Also, get abs(errno) to return to the process. */ - andcc %l0, _TIF_SYSCALL_TRACE, %l6 + andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6 sub %g0, %o0, %o0 or %g3, %g2, %g3 stx %o0, [%sp + PTREGS_OFF + PT_V9_I0] @@ -1773,8 +1758,9 @@ ret_sys_call: b,pt %xcc, rtrap stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] linux_syscall_trace2: + add %sp, PTREGS_OFF, %o0 call syscall_trace - nop + mov 1, %o1 stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC] ba,pt %xcc, rtrap stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 74a2e0808cb..daa2fb93052 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -917,7 +917,8 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { struct ino_bucket *bp = ivector_table + (long)data; - struct irqaction *ap = bp->irq_info; + struct irq_desc *desc = bp->irq_info; + struct irqaction *ap = desc->action; cpumask_t mask; int len; @@ -935,11 +936,13 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off, static inline void set_intr_affinity(int irq, cpumask_t hw_aff) { struct ino_bucket *bp = ivector_table + irq; + struct irq_desc *desc = bp->irq_info; + struct irqaction *ap = desc->action; /* Users specify affinity in terms of hw cpu ids. * As soon as we do this, handler_irq() might see and take action. */ - put_smpaff_in_irqaction((struct irqaction *)bp->irq_info, hw_aff); + put_smpaff_in_irqaction(ap, hw_aff); /* Migration is simply done by the next cpu to service this * interrupt. diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 52f14e399b1..533104c7907 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -4,6 +4,8 @@ * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ +#define __KERNEL_SYSCALLS__ + #include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> @@ -17,7 +19,6 @@ #include <asm/ebus.h> #include <asm/auxio.h> -#define __KERNEL_SYSCALLS__ #include <linux/unistd.h> /* diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 80a76e2ad73..23ad839d113 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -19,6 +19,8 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/security.h> +#include <linux/seccomp.h> +#include <linux/audit.h> #include <linux/signal.h> #include <asm/asi.h> @@ -628,15 +630,27 @@ out: unlock_kernel(); } -asmlinkage void syscall_trace(void) +asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) { -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace\n", current->comm, current->pid); -#endif - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; + /* do the secure computing check first */ + secure_computing(regs->u_regs[UREG_G1]); + + if (unlikely(current->audit_context) && syscall_exit_p) { + unsigned long tstate = regs->tstate; + int result = AUDITSC_SUCCESS; + + if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) + result = AUDITSC_FAILURE; + + audit_syscall_exit(current, result, regs->u_regs[UREG_I0]); + } + if (!(current->ptrace & PT_PTRACED)) - return; + goto out; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); @@ -645,12 +659,20 @@ asmlinkage void syscall_trace(void) * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ -#ifdef DEBUG_PTRACE - printk("%s [%d]: syscall_trace exit= %x\n", current->comm, - current->pid, current->exit_code); -#endif if (current->exit_code) { - send_sig (current->exit_code, current, 1); + send_sig(current->exit_code, current, 1); current->exit_code = 0; } + +out: + if (unlikely(current->audit_context) && !syscall_exit_p) + audit_syscall_entry(current, + (test_thread_flag(TIF_32BIT) ? + AUDIT_ARCH_SPARC : + AUDIT_ARCH_SPARC64), + regs->u_regs[UREG_G1], + regs->u_regs[UREG_I0], + regs->u_regs[UREG_I1], + regs->u_regs[UREG_I2], + regs->u_regs[UREG_I3]); } diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index e5b9c7a2778..441fc2e52ce 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -45,8 +45,8 @@ extern void calibrate_delay(void); /* Please don't make this stuff initdata!!! --DaveM */ static unsigned char boot_cpu_id; -cpumask_t cpu_online_map = CPU_MASK_NONE; -cpumask_t phys_cpu_present_map = CPU_MASK_NONE; +cpumask_t cpu_online_map = CPU_MASK_NONE __read_mostly; +cpumask_t phys_cpu_present_map = CPU_MASK_NONE __read_mostly; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -155,7 +155,7 @@ void cpu_panic(void) panic("SMP bolixed\n"); } -static unsigned long current_tick_offset; +static unsigned long current_tick_offset __read_mostly; /* This tick register synchronization scheme is taken entirely from * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit. @@ -1193,8 +1193,8 @@ void smp_send_stop(void) { } -unsigned long __per_cpu_base; -unsigned long __per_cpu_shift; +unsigned long __per_cpu_base __read_mostly; +unsigned long __per_cpu_shift __read_mostly; EXPORT_SYMBOL(__per_cpu_base); EXPORT_SYMBOL(__per_cpu_shift); diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 56cd96f4a5c..9202d925a9c 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -79,7 +79,7 @@ extern void linux_sparc_syscall(void); extern void rtrap(void); extern void show_regs(struct pt_regs *); extern void solaris_syscall(void); -extern void syscall_trace(void); +extern void syscall_trace(struct pt_regs *, int); extern u32 sunos_sys_table[], sys_call_table32[]; extern void tl0_solaris(void); extern void sys_sigsuspend(void); diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 5a95e98c531..5f9e4fae612 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -135,6 +135,8 @@ SIGN2(sys32_shutdown, sys_shutdown, %o0, %o1) SIGN3(sys32_socketpair, sys_socketpair, %o0, %o1, %o2) SIGN1(sys32_getpeername, sys_getpeername, %o0) SIGN1(sys32_getsockname, sys_getsockname, %o0) +SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1) +SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2) .globl sys32_mmap2 sys32_mmap2: diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index a5e36a4c892..bceb91a8a2b 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -59,11 +59,11 @@ sys_call_table32: /*180*/ .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall .word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sparc64_newuname /*190*/ .word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl - .word sys32_epoll_wait, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask + .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask /*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64 /*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo - .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex + .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, sys32_adjtimex /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 /*230*/ .word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64 @@ -125,11 +125,11 @@ sys_call_table: /*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname /*190*/ .word sys_init_module, sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl - .word sys_epoll_wait, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask + .word sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_nis_syscall, sys_sgetmask /*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64 /*210*/ .word sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo - .word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex + .word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid /*230*/ .word sys_select, sys_nis_syscall, sys_nis_syscall, sys_stime, sys_statfs64 diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index b40db389f90..362b9c26871 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -73,7 +73,7 @@ static __initdata struct sparc64_tick_ops dummy_tick_ops = { .get_tick = dummy_get_tick, }; -struct sparc64_tick_ops *tick_ops = &dummy_tick_ops; +struct sparc64_tick_ops *tick_ops __read_mostly = &dummy_tick_ops; #define TICK_PRIV_BIT (1UL << 63) @@ -195,7 +195,7 @@ static unsigned long tick_add_tick(unsigned long adj, unsigned long offset) return new_tick; } -static struct sparc64_tick_ops tick_operations = { +static struct sparc64_tick_ops tick_operations __read_mostly = { .init_tick = tick_init_tick, .get_tick = tick_get_tick, .get_compare = tick_get_compare, @@ -276,7 +276,7 @@ static unsigned long stick_add_compare(unsigned long adj) return new_compare; } -static struct sparc64_tick_ops stick_operations = { +static struct sparc64_tick_ops stick_operations __read_mostly = { .init_tick = stick_init_tick, .get_tick = stick_get_tick, .get_compare = stick_get_compare, @@ -422,7 +422,7 @@ static unsigned long hbtick_add_compare(unsigned long adj) return val; } -static struct sparc64_tick_ops hbtick_operations = { +static struct sparc64_tick_ops hbtick_operations __read_mostly = { .init_tick = hbtick_init_tick, .get_tick = hbtick_get_tick, .get_compare = hbtick_get_compare, @@ -437,10 +437,9 @@ static struct sparc64_tick_ops hbtick_operations = { * NOTE: On SUN5 systems the ticker interrupt comes in using 2 * interrupts, one at level14 and one with softint bit 0. */ -unsigned long timer_tick_offset; -unsigned long timer_tick_compare; +unsigned long timer_tick_offset __read_mostly; -static unsigned long timer_ticks_per_nsec_quotient; +static unsigned long timer_ticks_per_nsec_quotient __read_mostly; #define TICK_SIZE (tick_nsec / 1000) @@ -464,7 +463,7 @@ static inline void timer_check_rtc(void) static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - unsigned long ticks, pstate; + unsigned long ticks, compare, pstate; write_seqlock(&xtime_lock); @@ -483,14 +482,14 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) : "=r" (pstate) : "i" (PSTATE_IE)); - timer_tick_compare = tick_ops->add_compare(timer_tick_offset); + compare = tick_ops->add_compare(timer_tick_offset); ticks = tick_ops->get_tick(); /* Restore PSTATE_IE. */ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : /* no outputs */ : "r" (pstate)); - } while (time_after_eq(ticks, timer_tick_compare)); + } while (time_after_eq(ticks, compare)); timer_check_rtc(); @@ -506,11 +505,6 @@ void timer_tick_interrupt(struct pt_regs *regs) do_timer(regs); - /* - * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR. - */ - timer_tick_compare = tick_ops->get_compare() + timer_tick_offset; - timer_check_rtc(); write_sequnlock(&xtime_lock); diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index 382fd6798bb..950423da8a6 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S @@ -32,6 +32,8 @@ SECTIONS .data1 : { *(.data1) } . = ALIGN(64); .data.cacheline_aligned : { *(.data.cacheline_aligned) } + . = ALIGN(64); + .data.read_mostly : { *(.data.read_mostly) } _edata = .; PROVIDE (edata = .); .fixup : { *(.fixup) } diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 3ffee7b51ae..52e9375288a 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -34,22 +34,6 @@ extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; /* - * To debug kernel during syscall entry. - */ -void syscall_trace_entry(struct pt_regs *regs) -{ - printk("scall entry: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]); -} - -/* - * To debug kernel during syscall exit. - */ -void syscall_trace_exit(struct pt_regs *regs) -{ - printk("scall exit: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]); -} - -/* * To debug kernel to catch accesses to certain virtual/physical addresses. * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints. * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses. diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S index 0cc9dad75c5..4b6ae583c0a 100644 --- a/arch/sparc64/solaris/entry64.S +++ b/arch/sparc64/solaris/entry64.S @@ -24,8 +24,9 @@ .text solaris_syscall_trace: + add %sp, PTREGS_OFF, %o0 call syscall_trace - nop + mov 0, %o1 srl %i0, 0, %o0 mov %i4, %o4 srl %i1, 0, %o1 @@ -159,8 +160,10 @@ ret_from_solaris: stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4 solaris_syscall_trace2: + add %sp, PTREGS_OFF, %o0 call syscall_trace - add %l1, 0x4, %l2 /* npc = npc+4 */ + mov 1, %o1 + add %l1, 0x4, %l2 /* npc = npc+4 */ andcc %l1, 1, %g0 bne,pn %icc, 2b nop diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 9469e77303e..6682c788364 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -128,7 +128,6 @@ config HOSTFS config HPPFS tristate "HoneyPot ProcFS (EXPERIMENTAL)" - depends on BROKEN help hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc entries to be overridden, removed, or fabricated from the host. @@ -141,8 +140,9 @@ config HPPFS You only need this if you are setting up a UML honeypot. Otherwise, it is safe to say 'N' here. - If you are actively using it, please ask for it to be fixed. In this - moment, it does not work on 2.6 (it works somehow on 2.4). + If you are actively using it, please report any problems, since it's + getting fixed. In this moment, it is experimental on 2.6 (it works on + 2.4). config MCONSOLE bool "Management console" diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386 index e41f3748d30..27c18a8d9d1 100644 --- a/arch/um/Kconfig_i386 +++ b/arch/um/Kconfig_i386 @@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES memory. All the memory that can't be mapped directly will be treated as high memory. +config STUB_CODE + hex + default 0xbfffe000 + +config STUB_DATA + hex + default 0xbffff000 + +config STUB_START + hex + default STUB_CODE + config ARCH_HAS_SC_SIGNALS bool default y diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64 index f162f50f0b1..735a047c890 100644 --- a/arch/um/Kconfig_x86_64 +++ b/arch/um/Kconfig_x86_64 @@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES bool default y +config STUB_CODE + hex + default 0x7fbfffe000 + +config STUB_DATA + hex + default 0x7fbffff000 + +config STUB_START + hex + default STUB_CODE + config ARCH_HAS_SC_SIGNALS bool default n diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 29e182d5a83..301059062a3 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y) endif endif -CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) +CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS) ARCH_USER_CFLAGS := ifneq ($(CONFIG_GPROF),y) diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 32144562c27..d80bd0052e6 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -4,7 +4,7 @@ SUBARCH_LIBS := arch/um/sys-x86_64/ START := 0x60000000 -CFLAGS += -U__$(SUBARCH)__ -fno-builtin +CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS) ARCH_USER_CFLAGS := -D__x86_64__ ELF_ARCH := i386:x86-64 diff --git a/arch/um/defconfig b/arch/um/defconfig index 4067c3aa5b6..80d30d19d75 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2 -# Sun Apr 24 19:46:10 2005 +# Linux kernel version: 2.6.12-rc6-mm1 +# Tue Jun 14 18:22:21 2005 # CONFIG_GENERIC_HARDIRQS=y CONFIG_UML=y @@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y # # UML-specific options # -CONFIG_MODE_TT=y +# CONFIG_MODE_TT is not set +# CONFIG_STATIC_LINK is not set CONFIG_MODE_SKAS=y CONFIG_UML_X86=y # CONFIG_64BIT is not set CONFIG_TOP_ADDR=0xc0000000 # CONFIG_3_LEVEL_PGTABLES is not set +CONFIG_STUB_CODE=0xbfffe000 +CONFIG_STUB_DATA=0xbffff000 +CONFIG_STUB_START=0xbfffe000 CONFIG_ARCH_HAS_SC_SIGNALS=y CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y -CONFIG_LD_SCRIPT_STATIC=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_LD_SCRIPT_DYN=y CONFIG_NET=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m -CONFIG_HOSTFS=y +# CONFIG_HOSTFS is not set CONFIG_MCONSOLE=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_HOST_2G_2G is not set -# CONFIG_SMP is not set CONFIG_NEST_LEVEL=0 CONFIG_KERNEL_HALF_GIGS=1 # CONFIG_HIGHMEM is not set @@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_PRINTK=y +CONFIG_BUG=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -81,6 +92,7 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y @@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m CONFIG_SOUND=m CONFIG_HOSTAUDIO=m CONFIG_UML_RANDOM=y +# CONFIG_MMAPPER is not set # # Block devices @@ -176,6 +189,17 @@ CONFIG_INET=y # CONFIG_INET_TUNNEL is not set CONFIG_IP_TCPDIAG=y # CONFIG_IP_TCPDIAG_IPV6 is not set + +# +# TCP congestion control +# +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_WESTWOOD=y +CONFIG_TCP_CONG_HTCP=y +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_KGDBOE is not set # CONFIG_NETPOLL is not set +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set # CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -227,6 +255,7 @@ CONFIG_PPP=m # CONFIG_PPP_SYNC_TTY is not set # CONFIG_PPP_DEFLATE is not set # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_MPPE is not set # CONFIG_PPPOE is not set CONFIG_SLIP=m # CONFIG_SLIP_COMPRESSED is not set @@ -240,10 +269,12 @@ CONFIG_SLIP=m # CONFIG_EXT2_FS=y # CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set +# CONFIG_REISER4_FS is not set CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set @@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y CONFIG_QUOTA=y # CONFIG_QFMT_V1 is not set # CONFIG_QFMT_V2 is not set @@ -265,6 +297,12 @@ CONFIG_AUTOFS_FS=m CONFIG_AUTOFS4_FS=m # +# Caches +# +# CONFIG_FSCACHE is not set +# CONFIG_FUSE_FS is not set + +# # CD-ROM/DVD Filesystems # CONFIG_ISO9660_FS=m @@ -291,6 +329,8 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_CONFIGFS_FS is not set +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -319,6 +359,7 @@ CONFIG_RAMFS=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -404,14 +445,15 @@ CONFIG_CRC32=m # CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_SLAB=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_INFO=y # CONFIG_DEBUG_FS is not set CONFIG_FRAME_POINTER=y -CONFIG_PT_PROXY=y +# CONFIG_GPROF is not set # CONFIG_GCOV is not set # CONFIG_SYSCALL_DEBUG is not set diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 2bb4c4f5dec..e0fdffa2d54 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -663,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set, return driver; } +static spinlock_t winch_handler_lock; +LIST_HEAD(winch_handlers); + void lines_init(struct line *lines, int nlines) { struct line *line; int i; + spin_lock_init(&winch_handler_lock); for(i = 0; i < nlines; i++){ line = &lines[i]; INIT_LIST_HEAD(&line->chan_list); @@ -724,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) return IRQ_HANDLED; } -DECLARE_MUTEX(winch_handler_sem); -LIST_HEAD(winch_handlers); - void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) { struct winch *winch; - down(&winch_handler_sem); winch = kmalloc(sizeof(*winch), GFP_KERNEL); if (winch == NULL) { printk("register_winch_irq - kmalloc failed\n"); - goto out; + return; } + *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), .fd = fd, .tty_fd = tty_fd, .pid = pid, .tty = tty }); + + spin_lock(&winch_handler_lock); list_add(&winch->list, &winch_handlers); + spin_unlock(&winch_handler_lock); + if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "winch", winch) < 0) printk("register_winch_irq - failed to register IRQ\n"); - out: - up(&winch_handler_sem); } static void unregister_winch(struct tty_struct *tty) @@ -756,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty) struct list_head *ele; struct winch *winch, *found = NULL; - down(&winch_handler_sem); + spin_lock(&winch_handler_lock); list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); if(winch->tty == tty){ @@ -764,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty) break; } } - if(found == NULL) - goto out; + goto err; + + list_del(&winch->list); + spin_unlock(&winch_handler_lock); if(winch->pid != -1) os_kill_process(winch->pid, 1); free_irq(WINCH_IRQ, winch); - list_del(&winch->list); kfree(winch); - out: - up(&winch_handler_sem); + + return; +err: + spin_unlock(&winch_handler_lock); } +/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup + * order... are we sure that nothing else is done on the list? */ static void winch_cleanup(void) { struct list_head *ele; @@ -786,6 +794,9 @@ static void winch_cleanup(void) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); if(winch->fd != -1){ + /* Why is this different from the above free_irq(), + * which deactivates SIGIO? This searches the FD + * somewhere else and removes it from the list... */ deactivate_fd(winch->fd, WINCH_IRQ); os_close_file(winch->fd); } diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index 10c46c38949..99d3ad4a03e 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -13,6 +13,7 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); extern int is_remapped(void *virt); extern int physmem_remove_mapping(void *virt); extern void physmem_forget_descriptor(int fd); +extern unsigned long to_phys(void *virt); #endif diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h index 8744abb5224..0a35e6d0baa 100644 --- a/arch/um/include/registers.h +++ b/arch/um/include/registers.h @@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs); extern void save_registers(int pid, union uml_pt_regs *regs); extern void restore_registers(int pid, union uml_pt_regs *regs); extern void init_registers(int pid); +extern void get_safe_registers(unsigned long * regs); #endif diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h index eca8066e7a4..899aa4b2a78 100644 --- a/arch/um/include/sysdep-i386/ptrace_user.h +++ b/arch/um/include/sysdep-i386/ptrace_user.h @@ -20,11 +20,24 @@ #define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) #define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) #define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) +#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP) #define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) +#define REGS_SYSCALL_NR EAX /* This is used before a system call */ +#define REGS_SYSCALL_ARG1 EBX +#define REGS_SYSCALL_ARG2 ECX +#define REGS_SYSCALL_ARG3 EDX +#define REGS_SYSCALL_ARG4 ESI +#define REGS_SYSCALL_ARG5 EDI +#define REGS_SYSCALL_ARG6 EBP + +#define REGS_IP_INDEX EIP +#define REGS_SP_INDEX UESP + #define PT_IP_OFFSET PT_OFFSET(EIP) #define PT_IP(regs) ((regs)[EIP]) +#define PT_SP_OFFSET PT_OFFSET(UESP) #define PT_SP(regs) ((regs)[UESP]) #ifndef FRAME_SIZE diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h new file mode 100644 index 00000000000..d3699fe1c61 --- /dev/null +++ b/arch/um/include/sysdep-i386/stub.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_STUB_H +#define __SYSDEP_STUB_H + +#include <asm/ptrace.h> +#include <asm/unistd.h> + +extern void stub_segv_handler(int sig); +extern void stub_clone_handler(void); + +#define STUB_SYSCALL_RET EAX +#define STUB_MMAP_NR __NR_mmap2 +#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT) + +static inline long stub_syscall2(long syscall, long arg1, long arg2) +{ + long ret; + + __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); + __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); + __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); + __asm__("int $0x80;" : : : "%eax"); + __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :); + return(ret); +} + +static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +{ + __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); + return(stub_syscall2(syscall, arg1, arg2)); +} + +static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, + long arg4) +{ + __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); + return(stub_syscall3(syscall, arg1, arg2, arg3)); +} + +static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + long ret; + __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); + __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); + __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); + __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); + __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); + __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi"); + __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; " + "int $0x80; popl %%ebp ; " + "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax"); + return(ret); +} + +static inline void trap_myself(void) +{ + __asm("int3"); +} + +#endif diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h index 31729973fb1..128faf02736 100644 --- a/arch/um/include/sysdep-x86_64/ptrace_user.h +++ b/arch/um/include/sysdep-x86_64/ptrace_user.h @@ -55,6 +55,20 @@ #define PTRACE_OLDSETOPTIONS 21 #endif +/* These are before the system call, so the the system call number is RAX + * rather than ORIG_RAX, and arg4 is R10 rather than RCX + */ +#define REGS_SYSCALL_NR PT_INDEX(RAX) +#define REGS_SYSCALL_ARG1 PT_INDEX(RDI) +#define REGS_SYSCALL_ARG2 PT_INDEX(RSI) +#define REGS_SYSCALL_ARG3 PT_INDEX(RDX) +#define REGS_SYSCALL_ARG4 PT_INDEX(R10) +#define REGS_SYSCALL_ARG5 PT_INDEX(R8) +#define REGS_SYSCALL_ARG6 PT_INDEX(R9) + +#define REGS_IP_INDEX PT_INDEX(RIP) +#define REGS_SP_INDEX PT_INDEX(RSP) + #endif /* diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h new file mode 100644 index 00000000000..f599058d826 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/stub.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_STUB_H +#define __SYSDEP_STUB_H + +#include <asm/ptrace.h> +#include <asm/unistd.h> +#include <sysdep/ptrace_user.h> + +extern void stub_segv_handler(int sig); +extern void stub_clone_handler(void); + +#define STUB_SYSCALL_RET PT_INDEX(RAX) +#define STUB_MMAP_NR __NR_mmap +#define MMAP_OFFSET(o) (o) + +static inline long stub_syscall2(long syscall, long arg1, long arg2) +{ + long ret; + + __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi"); + __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi"); + __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax"); + __asm__("syscall;" : : : "%rax", "%r11", "%rcx"); + __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :); + return(ret); +} + +static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +{ + __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx"); + return(stub_syscall2(syscall, arg1, arg2)); +} + +static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, + long arg4) +{ + __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10"); + return(stub_syscall3(syscall, arg1, arg2, arg3)); +} + +static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9"); + __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8"); + return(stub_syscall4(syscall, arg1, arg2, arg3, arg4)); +} + +static inline void trap_myself(void) +{ + __asm("int3"); +} + +#endif diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index f64ef77019a..17d7ef2141f 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -10,6 +10,7 @@ extern void timer(void); extern void switch_timers(int to_real); extern void idle_sleep(int secs); extern void enable_timer(void); +extern void prepare_timer(void * ptr); extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h index da1097285b8..c6f9628f39b 100644 --- a/arch/um/include/tlb.h +++ b/arch/um/include/tlb.h @@ -37,31 +37,25 @@ struct host_vm_op { extern void mprotect_kernel_vm(int w); extern void force_flush_all(void); extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, int data, - void (*do_ops)(int, struct host_vm_op *, int)); + unsigned long end_addr, int force, + void (*do_ops)(union mm_context *, + struct host_vm_op *, int)); extern int flush_tlb_kernel_range_common(unsigned long start, unsigned long end); extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x, struct host_vm_op *ops, int index, - int last_filled, int data, - void (*do_ops)(int, struct host_vm_op *, int)); + int last_filled, union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, + int)); extern int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, int index, int last_filled, - int data, void (*do_ops)(int, struct host_vm_op *, int)); + union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, + int)); extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, struct host_vm_op *ops, int index, - int last_filled, int data, - void (*do_ops)(int, struct host_vm_op *, int)); + int last_filled, union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, + int)); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 715b0838a68..3942a5f245d 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -67,6 +67,12 @@ SECTIONS *(.stub .text.* .gnu.linkonce.t.*) /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) + + . = ALIGN(4096); + __syscall_stub_start = .; + *(.__syscall_stub*) + __syscall_stub_end = .; + . = ALIGN(4096); } =0x90909090 .fini : { KEEP (*(.fini)) diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index 420e6d51fa0..a24e3b7f4bf 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +extern int __syscall_stub_start, __binary_start; + void setup_physmem(unsigned long start, unsigned long reserve_end, unsigned long len, unsigned long highmem) { @@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end, exit(1); } + /* Special kludge - This page will be mapped in to userspace processes + * from physmem_fd, so it needs to be written out there. + */ + os_seek_file(physmem_fd, __pa(&__syscall_stub_start)); + os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); + bootmap_size = init_bootmem(pfn, pfn + delta); free_bootmem(__pa(reserve_end) + bootmap_size, len - bootmap_size - reserve); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 1b5ef3e96c7..c45a60e9c92 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -32,6 +32,7 @@ #include "uml-config.h" #include "choose-mode.h" #include "mode.h" +#include "tempfile.h" #ifdef UML_CONFIG_MODE_SKAS #include "skas.h" #include "skas_ptrace.h" @@ -358,11 +359,16 @@ void forward_pending_sigio(int target) kill(target, SIGIO); } +int ptrace_faultinfo = 0; +int proc_mm = 1; + +extern void *__syscall_stub_start, __syscall_stub_end; + #ifdef UML_CONFIG_MODE_SKAS -static inline int check_skas3_ptrace_support(void) +static inline void check_skas3_ptrace_support(void) { struct ptrace_faultinfo fi; - int pid, n, ret = 1; + int pid, n; printf("Checking for the skas3 patch in the host..."); pid = start_ptraced_child(); @@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void) else { perror("not found"); } - ret = 0; - } else { + } + else { + ptrace_faultinfo = 1; printf("found\n"); } init_registers(pid); stop_ptraced_child(pid, 1, 1); - - return(ret); } int can_do_skas(void) { - int ret = 1; - printf("Checking for /proc/mm..."); if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { + proc_mm = 0; printf("not found\n"); - ret = 0; goto out; - } else { + } + else { printf("found\n"); } - ret = check_skas3_ptrace_support(); out: - return ret; + check_skas3_ptrace_support(); + return 1; } #else int can_do_skas(void) diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index ff69c4b312c..d296d55ade4 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,11 +3,14 @@ # Licensed under the GPL # -obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ +obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ subdir- := util -USER_OBJS := process.o +USER_OBJS := process.o clone.o include arch/um/scripts/Makefile.rules + +# clone.o is in the stub, so it can't be built with profiling +$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c new file mode 100644 index 00000000000..4dc55f10cd1 --- /dev/null +++ b/arch/um/kernel/skas/clone.c @@ -0,0 +1,44 @@ +#include <sched.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <asm/unistd.h> +#include <asm/page.h> +#include "ptrace_user.h" +#include "skas.h" +#include "stub-data.h" +#include "uml-config.h" +#include "sysdep/stub.h" + +/* This is in a separate file because it needs to be compiled with any + * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled + */ +void __attribute__ ((__section__ (".__syscall_stub"))) +stub_clone_handler(void) +{ + long err; + struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA; + + err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, + UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 - + sizeof(void *)); + if(err != 0) + goto out; + + err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); + if(err) + goto out; + + err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, + (long) &from->timer, 0); + if(err) + goto out; + + err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, + from->fd, from->offset); + out: + /* save current result. Parent: pid; child: retcode of mmap */ + from->err = err; + trap_myself(); +} diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c index c6b4d5dba78..77ed7bbab21 100644 --- a/arch/um/kernel/skas/exec_kern.c +++ b/arch/um/kernel/skas/exec_kern.c @@ -18,7 +18,7 @@ void flush_thread_skas(void) { force_flush_all(); - switch_mm_skas(current->mm->context.skas.mm_fd); + switch_mm_skas(¤t->mm->context.skas.id); } void start_thread_skas(struct pt_regs *regs, unsigned long eip, diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h new file mode 100644 index 00000000000..48dd0989dda --- /dev/null +++ b/arch/um/kernel/skas/include/mm_id.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MM_ID_H +#define __MM_ID_H + +struct mm_id { + union { + int mm_fd; + int pid; + } u; + unsigned long stack; +}; + +#endif diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h index 4cd60d7213f..278b72f1d9a 100644 --- a/arch/um/kernel/skas/include/mmu-skas.h +++ b/arch/um/kernel/skas/include/mmu-skas.h @@ -6,10 +6,15 @@ #ifndef __SKAS_MMU_H #define __SKAS_MMU_H +#include "mm_id.h" + struct mmu_context_skas { - int mm_fd; + struct mm_id id; + unsigned long last_page_table; }; +extern void switch_mm_skas(struct mm_id * mm_idp); + #endif /* diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index 96b51dba347..d983ea84254 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -6,9 +6,11 @@ #ifndef __SKAS_H #define __SKAS_H +#include "mm_id.h" #include "sysdep/ptrace.h" extern int userspace_pid[]; +extern int proc_mm, ptrace_faultinfo; extern void switch_threads(void *me, void *next); extern void thread_wait(void *sw, void *fb); @@ -22,16 +24,18 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig)); extern void remove_sigstack(void); extern void new_thread_handler(int sig); extern void handle_syscall(union uml_pt_regs *regs); -extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, - int x, int phys_fd, unsigned long long offset); -extern int unmap(int fd, void *addr, unsigned long len); -extern int protect(int fd, unsigned long addr, unsigned long len, - int r, int w, int x); +extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, + int r, int w, int x, int phys_fd, unsigned long long offset); +extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len); +extern int protect(struct mm_id * mm_idp, unsigned long addr, + unsigned long len, int r, int w, int x); extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern int new_mm(int from); -extern void start_userspace(int cpu); +extern int start_userspace(unsigned long stub_stack); +extern int copy_context_skas0(unsigned long stack, int pid); extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); +extern unsigned long current_stub_stack(void); #endif diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h new file mode 100644 index 00000000000..f6ed92c3727 --- /dev/null +++ b/arch/um/kernel/skas/include/stub-data.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __STUB_DATA_H +#define __STUB_DATA_H + +#include <sys/time.h> + +struct stub_data { + long offset; + int fd; + struct itimerval timer; + long err; +}; + +#endif diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 438db2f4345..147466d7ff4 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -5,7 +5,9 @@ #include "linux/config.h" #include "linux/mm.h" +#include "asm/pgtable.h" #include "mem_user.h" +#include "skas.h" unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, unsigned long *task_size_out) @@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, *task_size_out = CONFIG_HOST_TASK_SIZE; #else *host_size_out = top; - *task_size_out = top; + if (proc_mm && ptrace_faultinfo) + *task_size_out = top; + else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; #endif return(((unsigned long) set_task_sizes_skas) & ~0xffffff); } diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c index 1310bf1e88d..b0980ff3bd9 100644 --- a/arch/um/kernel/skas/mem_user.c +++ b/arch/um/kernel/skas/mem_user.c @@ -3,100 +3,171 @@ * Licensed under the GPL */ +#include <signal.h> #include <errno.h> #include <sys/mman.h> +#include <sys/wait.h> +#include <asm/page.h> +#include <asm/unistd.h> #include "mem_user.h" #include "mem.h" +#include "mm_id.h" #include "user.h" #include "os.h" #include "proc_mm.h" - -void map(int fd, unsigned long virt, unsigned long len, int r, int w, - int x, int phys_fd, unsigned long long offset) +#include "ptrace_user.h" +#include "user_util.h" +#include "kern_util.h" +#include "task.h" +#include "registers.h" +#include "uml-config.h" +#include "sysdep/ptrace.h" +#include "sysdep/stub.h" +#include "skas.h" + +extern unsigned long syscall_stub, __syscall_stub_start; + +extern void wait_stub_done(int pid, int sig, char * fname); + +static long run_syscall_stub(struct mm_id * mm_idp, int syscall, + unsigned long *args) { - struct proc_mm_op map; - int prot, n; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - - map = ((struct proc_mm_op) { .op = MM_MMAP, - .u = - { .mmap = - { .addr = virt, - .len = len, - .prot = prot, - .flags = MAP_SHARED | - MAP_FIXED, - .fd = phys_fd, - .offset = offset - } } } ); - n = os_write_file(fd, &map, sizeof(map)); - if(n != sizeof(map)) - printk("map : /proc/mm map failed, err = %d\n", -n); + int n, pid = mm_idp->u.pid; + unsigned long regs[MAX_REG_NR]; + + get_safe_registers(regs); + regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + + ((unsigned long) &syscall_stub - + (unsigned long) &__syscall_stub_start); + /* XXX Don't have a define for starting a syscall */ + regs[REGS_SYSCALL_NR] = syscall; + regs[REGS_SYSCALL_ARG1] = args[0]; + regs[REGS_SYSCALL_ARG2] = args[1]; + regs[REGS_SYSCALL_ARG3] = args[2]; + regs[REGS_SYSCALL_ARG4] = args[3]; + regs[REGS_SYSCALL_ARG5] = args[4]; + regs[REGS_SYSCALL_ARG6] = args[5]; + n = ptrace_setregs(pid, regs); + if(n < 0){ + printk("run_syscall_stub : PTRACE_SETREGS failed, " + "errno = %d\n", n); + return(n); + } + + wait_stub_done(pid, 0, "run_syscall_stub"); + + return(*((unsigned long *) mm_idp->stack)); } -int unmap(int fd, void *addr, unsigned long len) +int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, + int r, int w, int x, int phys_fd, unsigned long long offset) { - struct proc_mm_op unmap; - int n; - - unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, - .u = - { .munmap = - { .addr = (unsigned long) addr, - .len = len } } } ); - n = os_write_file(fd, &unmap, sizeof(unmap)); - if(n != sizeof(unmap)) { - if(n < 0) - return(n); - else if(n > 0) - return(-EIO); - } - - return(0); + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + if(proc_mm){ + struct proc_mm_op map; + int fd = mm_idp->u.mm_fd; + map = ((struct proc_mm_op) { .op = MM_MMAP, + .u = + { .mmap = + { .addr = virt, + .len = len, + .prot = prot, + .flags = MAP_SHARED | + MAP_FIXED, + .fd = phys_fd, + .offset= offset + } } } ); + n = os_write_file(fd, &map, sizeof(map)); + if(n != sizeof(map)) + printk("map : /proc/mm map failed, err = %d\n", -n); + } + else { + long res; + unsigned long args[] = { virt, len, prot, + MAP_SHARED | MAP_FIXED, phys_fd, + MMAP_OFFSET(offset) }; + + res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args); + if((void *) res == MAP_FAILED) + printk("mmap stub failed, errno = %d\n", res); + } + + return 0; } -int protect(int fd, unsigned long addr, unsigned long len, int r, int w, - int x, int must_succeed) +int unmap(struct mm_id *mm_idp, void *addr, unsigned long len) { - struct proc_mm_op protect; - int prot, n; - - prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | - (x ? PROT_EXEC : 0); - - protect = ((struct proc_mm_op) { .op = MM_MPROTECT, - .u = - { .mprotect = - { .addr = (unsigned long) addr, - .len = len, - .prot = prot } } } ); - - n = os_write_file(fd, &protect, sizeof(protect)); - if(n != sizeof(protect)) { - if(n == 0) return(0); - - if(must_succeed) - panic("protect failed, err = %d", -n); - - return(-EIO); - } + int n; + + if(proc_mm){ + struct proc_mm_op unmap; + int fd = mm_idp->u.mm_fd; + unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, + .u = + { .munmap = + { .addr = + (unsigned long) addr, + .len = len } } } ); + n = os_write_file(fd, &unmap, sizeof(unmap)); + if(n != sizeof(unmap)) { + if(n < 0) + return(n); + else if(n > 0) + return(-EIO); + } + } + else { + int res; + unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, + 0 }; + + res = run_syscall_stub(mm_idp, __NR_munmap, args); + if(res < 0) + printk("munmap stub failed, errno = %d\n", res); + } + + return(0); +} - return(0); +int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, + int r, int w, int x) +{ + struct proc_mm_op protect; + int prot, n; + + prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | + (x ? PROT_EXEC : 0); + + if(proc_mm){ + int fd = mm_idp->u.mm_fd; + protect = ((struct proc_mm_op) { .op = MM_MPROTECT, + .u = + { .mprotect = + { .addr = + (unsigned long) addr, + .len = len, + .prot = prot } } } ); + + n = os_write_file(fd, &protect, sizeof(protect)); + if(n != sizeof(protect)) + panic("protect failed, err = %d", -n); + } + else { + int res; + unsigned long args[] = { addr, len, prot, 0, 0, 0 }; + + res = run_syscall_stub(mm_idp, __NR_mprotect, args); + if(res < 0) + panic("mprotect stub failed, errno = %d\n", res); + } + + return(0); } void before_mem_skas(unsigned long unused) { } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 6cb9a6d028a..d232daa42c3 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -3,46 +3,143 @@ * Licensed under the GPL */ +#include "linux/config.h" #include "linux/sched.h" #include "linux/list.h" #include "linux/spinlock.h" #include "linux/slab.h" +#include "linux/errno.h" +#include "linux/mm.h" #include "asm/current.h" #include "asm/segment.h" #include "asm/mmu.h" +#include "asm/pgalloc.h" +#include "asm/pgtable.h" #include "os.h" #include "skas.h" +extern int __syscall_stub_start; + +static int init_stub_pte(struct mm_struct *mm, unsigned long proc, + unsigned long kernel) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + spin_lock(&mm->page_table_lock); + pgd = pgd_offset(mm, proc); + pud = pud_alloc(mm, pgd, proc); + if (!pud) + goto out; + + pmd = pmd_alloc(mm, pud, proc); + if (!pmd) + goto out_pmd; + + pte = pte_alloc_map(mm, pmd, proc); + if (!pte) + goto out_pte; + + /* There's an interaction between the skas0 stub pages, stack + * randomization, and the BUG at the end of exit_mmap. exit_mmap + * checks that the number of page tables freed is the same as had + * been allocated. If the stack is on the last page table page, + * then the stack pte page will be freed, and if not, it won't. To + * avoid having to know where the stack is, or if the process mapped + * something at the top of its address space for some other reason, + * we set TASK_SIZE to end at the start of the last page table. + * This keeps exit_mmap off the last page, but introduces a leak + * of that page. So, we hang onto it here and free it in + * destroy_context_skas. + */ + + mm->context.skas.last_page_table = pmd_page_kernel(*pmd); + + *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); + *pte = pte_mkexec(*pte); + *pte = pte_wrprotect(*pte); + spin_unlock(&mm->page_table_lock); + return(0); + + out_pmd: + pud_free(pud); + out_pte: + pmd_free(pmd); + out: + spin_unlock(&mm->page_table_lock); + return(-ENOMEM); +} + int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) { - int from; + struct mm_struct *cur_mm = current->mm; + struct mm_id *cur_mm_id = &cur_mm->context.skas.id; + struct mm_id *mm_id = &mm->context.skas.id; + unsigned long stack; + int from, ret; - if((current->mm != NULL) && (current->mm != &init_mm)) - from = current->mm->context.skas.mm_fd; - else from = -1; + if(proc_mm){ + if((cur_mm != NULL) && (cur_mm != &init_mm)) + from = cur_mm->context.skas.id.u.mm_fd; + else from = -1; - mm->context.skas.mm_fd = new_mm(from); - if(mm->context.skas.mm_fd < 0){ - printk("init_new_context_skas - new_mm failed, errno = %d\n", - mm->context.skas.mm_fd); - return(mm->context.skas.mm_fd); + ret = new_mm(from); + if(ret < 0){ + printk("init_new_context_skas - new_mm failed, " + "errno = %d\n", ret); + return ret; + } + mm_id->u.mm_fd = ret; } + else { + /* This zeros the entry that pgd_alloc didn't, needed since + * we are about to reinitialize it, and want mm.nr_ptes to + * be accurate. + */ + mm->pgd[USER_PTRS_PER_PGD] = __pgd(0); - return(0); + ret = init_stub_pte(mm, CONFIG_STUB_CODE, + (unsigned long) &__syscall_stub_start); + if(ret) + goto out; + + ret = -ENOMEM; + stack = get_zeroed_page(GFP_KERNEL); + if(stack == 0) + goto out; + mm_id->stack = stack; + + ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack); + if(ret) + goto out_free; + + mm->nr_ptes--; + + if((cur_mm != NULL) && (cur_mm != &init_mm)) + mm_id->u.pid = copy_context_skas0(stack, + cur_mm_id->u.pid); + else mm_id->u.pid = start_userspace(stack); + } + + return 0; + + out_free: + free_page(mm_id->stack); + out: + return ret; } void destroy_context_skas(struct mm_struct *mm) { - os_close_file(mm->context.skas.mm_fd); -} + struct mmu_context_skas *mmu = &mm->context.skas; -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ + if(proc_mm) + os_close_file(mmu->id.u.mm_fd); + else { + os_kill_ptraced_process(mmu->id.u.pid, 1); + free_page(mmu->id.stack); + free_page(mmu->last_page_table); + } +} diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 773cd2b525f..ba671dab887 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -13,7 +13,9 @@ #include <sys/wait.h> #include <sys/mman.h> #include <sys/user.h> +#include <sys/time.h> #include <asm/unistd.h> +#include <asm/types.h> #include "user.h" #include "ptrace_user.h" #include "time_user.h" @@ -21,13 +23,18 @@ #include "user_util.h" #include "kern_util.h" #include "skas.h" +#include "stub-data.h" +#include "mm_id.h" #include "sysdep/sigcontext.h" +#include "sysdep/stub.h" #include "os.h" #include "proc_mm.h" #include "skas_ptrace.h" #include "chan_user.h" #include "signal_user.h" #include "registers.h" +#include "mem.h" +#include "uml-config.h" #include "process.h" int is_skas_winch(int pid, int fd, void *data) @@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data) return(1); } -void get_skas_faultinfo(int pid, struct faultinfo * fi) +void wait_stub_done(int pid, int sig, char * fname) { - int err; - - err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); - if(err) - panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " - "errno = %d\n", errno); + int n, status, err; + + do { + if ( sig != -1 ) { + err = ptrace(PTRACE_CONT, pid, 0, sig); + if(err) + panic("%s : continue failed, errno = %d\n", + fname, errno); + } + sig = 0; + + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); + } while((n >= 0) && WIFSTOPPED(status) && + (WSTOPSIG(status) == SIGVTALRM)); + + if((n < 0) || !WIFSTOPPED(status) || + (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){ + panic("%s : failed to wait for SIGUSR1/SIGTRAP, " + "pid = %d, n = %d, errno = %d, status = 0x%x\n", + fname, pid, n, errno, status); + } +} - /* Special handling for i386, which has different structs */ - if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) - memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, - sizeof(struct faultinfo) - - sizeof(struct ptrace_faultinfo)); +void get_skas_faultinfo(int pid, struct faultinfo * fi) +{ + int err; + + if(ptrace_faultinfo){ + err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); + if(err) + panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " + "errno = %d\n", errno); + + /* Special handling for i386, which has different structs */ + if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) + memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, + sizeof(struct faultinfo) - + sizeof(struct ptrace_faultinfo)); + } + else { + wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); + + /* faultinfo is prepared by the stub-segv-handler at start of + * the stub stack page. We just have to copy it. + */ + memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); + } } static void handle_segv(int pid, union uml_pt_regs * regs) @@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu handle_syscall(regs); } -static int userspace_tramp(void *arg) +extern int __syscall_stub_start; + +static int userspace_tramp(void *stack) { - init_new_thread_signals(0); - enable_timer(); + void *addr; + ptrace(PTRACE_TRACEME, 0, 0, 0); + + init_new_thread_signals(1); + enable_timer(); + + if(!proc_mm){ + /* This has a pte, but it can't be mapped in with the usual + * tlb_flush mechanism because this is part of that mechanism + */ + int fd; + __u64 offset; + + fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); + addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(), + PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); + if(addr == MAP_FAILED){ + printk("mapping mmap stub failed, errno = %d\n", + errno); + exit(1); + } + + if(stack != NULL){ + fd = phys_mapping(to_phys(stack), &offset); + addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(), + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, offset); + if(addr == MAP_FAILED){ + printk("mapping segfault stack failed, " + "errno = %d\n", errno); + exit(1); + } + } + } + if(!ptrace_faultinfo && (stack != NULL)){ + unsigned long v = UML_CONFIG_STUB_CODE + + (unsigned long) stub_segv_handler - + (unsigned long) &__syscall_stub_start; + + set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size()); + set_handler(SIGSEGV, (void *) v, SA_ONSTACK, + SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, + SIGUSR1, -1); + } + os_stop_process(os_getpid()); return(0); } @@ -105,11 +192,11 @@ static int userspace_tramp(void *arg) #define NR_CPUS 1 int userspace_pid[NR_CPUS]; -void start_userspace(int cpu) +int start_userspace(unsigned long stub_stack) { void *stack; unsigned long sp; - int pid, status, n; + int pid, status, n, flags; stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -117,8 +204,9 @@ void start_userspace(int cpu) panic("start_userspace : mmap failed, errno = %d", errno); sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); - pid = clone(userspace_tramp, (void *) sp, - CLONE_FILES | CLONE_VM | SIGCHLD, NULL); + flags = CLONE_FILES | SIGCHLD; + if(proc_mm) flags |= CLONE_VM; + pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); if(pid < 0) panic("start_userspace : clone failed, errno = %d", errno); @@ -140,7 +228,7 @@ void start_userspace(int cpu) if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); - userspace_pid[cpu] = pid; + return(pid); } void userspace(union uml_pt_regs *regs) @@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs) if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: - handle_segv(pid, regs); + if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) + user_signal(SIGSEGV, regs, pid); + else handle_segv(pid, regs); break; case SIGTRAP + 0x80: handle_trap(pid, regs, local_using_sysemu); @@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs) printk("userspace - child stopped with signal " "%d\n", WSTOPSIG(status)); } + pid = userspace_pid[0]; interrupt_end(); /* Avoid -ERESTARTSYS handling in host */ @@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs) #define INIT_JMP_HALT 3 #define INIT_JMP_REBOOT 4 + +int copy_context_skas0(unsigned long new_stack, int pid) +{ + int err; + unsigned long regs[MAX_REG_NR]; + unsigned long current_stack = current_stub_stack(); + struct stub_data *data = (struct stub_data *) current_stack; + struct stub_data *child_data = (struct stub_data *) new_stack; + __u64 new_offset; + int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); + + /* prepare offset and fd of child's stack as argument for parent's + * and child's mmap2 calls + */ + *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), + .fd = new_fd, + .timer = ((struct itimerval) + { { 0, 1000000 / hz() }, + { 0, 1000000 / hz() }})}); + get_safe_registers(regs); + + /* Set parent's instruction pointer to start of clone-stub */ + regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + + (unsigned long) stub_clone_handler - + (unsigned long) &__syscall_stub_start; + regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - + sizeof(void *); + err = ptrace_setregs(pid, regs); + if(err < 0) + panic("copy_context_skas0 : PTRACE_SETREGS failed, " + "pid = %d, errno = %d\n", pid, errno); + + /* set a well known return code for detection of child write failure */ + child_data->err = 12345678; + + /* Wait, until parent has finished its work: read child's pid from + * parent's stack, and check, if bad result. + */ + wait_stub_done(pid, 0, "copy_context_skas0"); + + pid = data->err; + if(pid < 0) + panic("copy_context_skas0 - stub-parent reports error %d\n", + pid); + + /* Wait, until child has finished too: read child's result from + * child's stack and check it. + */ + wait_stub_done(pid, -1, "copy_context_skas0"); + if (child_data->err != UML_CONFIG_STUB_DATA) + panic("copy_context_skas0 - stub-child reports error %d\n", + child_data->err); + + if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + (void *)PTRACE_O_TRACESYSGOOD) < 0) + panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, " + "errno = %d\n", errno); + + return pid; +} + void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { @@ -334,21 +486,19 @@ void reboot_skas(void) siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); } -void switch_mm_skas(int mm_fd) +void switch_mm_skas(struct mm_id *mm_idp) { int err; #warning need cpu pid in switch_mm_skas - err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); - if(err) - panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", - errno); -} - -void kill_off_processes_skas(void) -{ -#warning need to loop over userspace_pids in kill_off_processes_skas - os_kill_ptraced_process(userspace_pid[0], 1); + if(proc_mm){ + err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, + mm_idp->u.mm_fd); + if(err) + panic("switch_mm_skas - PTRACE_SWITCH_MM failed, " + "errno = %d\n", errno); + } + else userspace_pid[0] = mm_idp->u.pid; } /* diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 0a7b8aa55db..cbabab104ac 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused) return(0); } +extern int userspace_pid[]; + int start_uml_skas(void) { - start_userspace(0); + if(proc_mm) + userspace_pid[0] = start_userspace(0); init_new_thread_signals(1); @@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task) #warning Need to look up userspace_pid by cpu return(userspace_pid[0]); } + +void kill_off_processes_skas(void) +{ + if(proc_mm) +#warning need to loop over userspace_pids in kill_off_processes_skas + os_kill_ptraced_process(userspace_pid[0], 1); + else { + struct task_struct *p; + int pid, me; + + me = os_getpid(); + for_each_process(p){ + if(p->mm == NULL) + continue; + + pid = p->mm->context.skas.id.u.pid; + os_kill_ptraced_process(pid, 1); + } + } +} + +unsigned long current_stub_stack(void) +{ + if(current->mm == NULL) + return(0); + + return(current->mm->context.skas.id.stack); +} diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c index b8c5e71763d..6230999c672 100644 --- a/arch/um/kernel/skas/tlb.c +++ b/arch/um/kernel/skas/tlb.c @@ -6,6 +6,7 @@ #include "linux/stddef.h" #include "linux/sched.h" +#include "linux/config.h" #include "linux/mm.h" #include "asm/page.h" #include "asm/pgtable.h" @@ -17,7 +18,7 @@ #include "os.h" #include "tlb.h" -static void do_ops(int fd, struct host_vm_op *ops, int last) +static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last) { struct host_vm_op *op; int i; @@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last) op = &ops[i]; switch(op->type){ case MMAP: - map(fd, op->u.mmap.addr, op->u.mmap.len, + map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len, op->u.mmap.r, op->u.mmap.w, op->u.mmap.x, op->u.mmap.fd, op->u.mmap.offset); break; case MUNMAP: - unmap(fd, (void *) op->u.munmap.addr, + unmap(&mmu->skas.id, (void *) op->u.munmap.addr, op->u.munmap.len); break; case MPROTECT: - protect(fd, op->u.mprotect.addr, op->u.mprotect.len, - op->u.mprotect.r, op->u.mprotect.w, - op->u.mprotect.x); + protect(&mmu->skas.id, op->u.mprotect.addr, + op->u.mprotect.len, op->u.mprotect.r, + op->u.mprotect.w, op->u.mprotect.x); break; default: printk("Unknown op type %d in do_ops\n", op->type); @@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last) } } +extern int proc_mm; + static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { - int fd = mm->context.skas.mm_fd; + if(!proc_mm && (end_addr > CONFIG_STUB_START)) + end_addr = CONFIG_STUB_START; - fix_range_common(mm, start_addr, end_addr, force, fd, do_ops); + fix_range_common(mm, start_addr, end_addr, force, do_ops); } void __flush_tlb_one_skas(unsigned long addr) @@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start, void flush_tlb_mm_skas(struct mm_struct *mm) { + unsigned long end; + /* Don't bother flushing if this address space is about to be * destroyed. */ if(atomic_read(&mm->mm_users) == 0) return; - fix_range(mm, 0, host_task_size, 0); - flush_tlb_kernel_range_common(start_vm, end_vm); + end = proc_mm ? task_size : CONFIG_STUB_START; + fix_range(mm, 0, end, 0); } void force_flush_all_skas(void) { - fix_range(current->mm, 0, host_task_size, 1); + unsigned long end = proc_mm ? task_size : CONFIG_STUB_START; + fix_range(current->mm, 0, end, 1); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index f829b309b63..c40b611e3d9 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -48,6 +48,13 @@ void enable_timer(void) set_interval(ITIMER_VIRTUAL); } +void prepare_timer(void * ptr) +{ + int usec = 1000000/hz(); + *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec }, + { 0, usec }}); +} + void disable_timer(void) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index eda477edfdf..83ec8d4747f 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -18,13 +18,15 @@ #define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) void fix_range_common(struct mm_struct *mm, unsigned long start_addr, - unsigned long end_addr, int force, int data, - void (*do_ops)(int, struct host_vm_op *, int)) + unsigned long end_addr, int force, + void (*do_ops)(union mm_context *, struct host_vm_op *, + int)) { pgd_t *npgd; pud_t *npud; pmd_t *npmd; pte_t *npte; + union mm_context *mmu = &mm->context; unsigned long addr, end; int r, w, x; struct host_vm_op ops[16]; @@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, end = end_addr; if(force || pgd_newpage(*npgd)){ op_index = add_munmap(addr, end - addr, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); pgd_mkuptodate(*npgd); } @@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, end = end_addr; if(force || pud_newpage(*npud)){ op_index = add_munmap(addr, end - addr, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); pud_mkuptodate(*npud); } @@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, end = end_addr; if(force || pmd_newpage(*npmd)){ op_index = add_munmap(addr, end - addr, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); pmd_mkuptodate(*npmd); } @@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, op_index = add_mmap(addr, pte_val(*npte) & PAGE_MASK, PAGE_SIZE, r, w, x, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); else op_index = add_munmap(addr, PAGE_SIZE, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); } else if(pte_newprot(*npte)) op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, - op_index, last_op, data, + op_index, last_op, mmu, do_ops); *npte = pte_mkuptodate(*npte); addr += PAGE_SIZE; } - (*do_ops)(data, ops, op_index); + (*do_ops)(mmu, ops, op_index); } int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) @@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) return(updated); } -void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) -{ - address &= PAGE_MASK; - flush_tlb_range(vma, address, address + PAGE_SIZE); -} - -void flush_tlb_all(void) -{ - flush_tlb_mm(current->mm); -} - -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, - flush_tlb_kernel_range_common, start, end); -} - -void flush_tlb_kernel_vm(void) -{ - CHOOSE_MODE(flush_tlb_kernel_vm_tt(), - flush_tlb_kernel_range_common(start_vm, end_vm)); -} - -void __flush_tlb_one(unsigned long addr) -{ - CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); -} - -void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, - unsigned long end) -{ - CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, - end); -} - -void flush_tlb_mm(struct mm_struct *mm) -{ - CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); -} - -void force_flush_all(void) -{ - CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); -} - pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) { return(pgd_offset(mm, address)); @@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr) } int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, - int r, int w, int x, struct host_vm_op *ops, int index, - int last_filled, int data, - void (*do_ops)(int, struct host_vm_op *, int)) + int r, int w, int x, struct host_vm_op *ops, int index, + int last_filled, union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, int)) { __u64 offset; struct host_vm_op *last; @@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, } if(index == last_filled){ - (*do_ops)(data, ops, last_filled); + (*do_ops)(mmu, ops, last_filled); index = -1; } @@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, } int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, - int index, int last_filled, int data, - void (*do_ops)(int, struct host_vm_op *, int)) + int index, int last_filled, union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, int)) { struct host_vm_op *last; @@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, } if(index == last_filled){ - (*do_ops)(data, ops, last_filled); + (*do_ops)(mmu, ops, last_filled); index = -1; } @@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, } int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, - struct host_vm_op *ops, int index, int last_filled, int data, - void (*do_ops)(int, struct host_vm_op *, int)) + struct host_vm_op *ops, int index, int last_filled, + union mm_context *mmu, + void (*do_ops)(union mm_context *, struct host_vm_op *, int)) { struct host_vm_op *last; @@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, } if(index == last_filled){ - (*do_ops)(data, ops, last_filled); + (*do_ops)(mmu, ops, last_filled); index = -1; } @@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, .x = x } } }); return(index); } + +void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) +{ + address &= PAGE_MASK; + flush_tlb_range(vma, address, address + PAGE_SIZE); +} + +void flush_tlb_all(void) +{ + flush_tlb_mm(current->mm); +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt, + flush_tlb_kernel_range_common, start, end); +} + +void flush_tlb_kernel_vm(void) +{ + CHOOSE_MODE(flush_tlb_kernel_vm_tt(), + flush_tlb_kernel_range_common(start_vm, end_vm)); +} + +void __flush_tlb_one(unsigned long addr) +{ + CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start, + end); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); +} + +void force_flush_all(void) +{ + CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); +} + diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c index 203216ad86f..2eefb43bc9c 100644 --- a/arch/um/kernel/tt/tlb.c +++ b/arch/um/kernel/tt/tlb.c @@ -17,7 +17,7 @@ #include "os.h" #include "tlb.h" -static void do_ops(int unused, struct host_vm_op *ops, int last) +static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last) { struct host_vm_op *op; int i; @@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr, panic("fix_range fixing wrong address space, current = 0x%p", current); - fix_range_common(mm, start_addr, end_addr, force, 0, do_ops); + fix_range_common(mm, start_addr, end_addr, force, do_ops); } atomic_t vmchange_seq = ATOMIC_INIT(1); diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 61dfd4fef75..163476a8cb1 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -30,6 +30,7 @@ SECTIONS _einittext = .; } . = ALIGN(4096); + .text : { *(.text) @@ -39,6 +40,12 @@ SECTIONS /* .gnu.warning sections are handled specially by elf32.em. */ *(.gnu.warning) *(.gnu.linkonce.t*) + + . = ALIGN(4096); + __syscall_stub_start = .; + *(.__syscall_stub*) + __syscall_stub_end = .; + . = ALIGN(4096); } #include "asm/common.lds.S" diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 9a0ad094d92..3125d320722 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -121,6 +121,11 @@ void init_registers(int pid) err); } +void get_safe_registers(unsigned long *regs) +{ + memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index 6286c974bbe..44438d15c3d 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c @@ -69,6 +69,11 @@ void init_registers(int pid) err); } +void get_safe_registers(unsigned long *regs) +{ + memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long)); +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 7459d09c233..17f305b6bad 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -16,6 +16,11 @@ define unprofile endef +# The stubs and unmap.o can't try to call mcount or update basic block data +define unprofile + $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) +endef + quiet_cmd_make_link = SYMLINK $@ cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@ diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index 095bcdb0b9c..77c3c4d29f5 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,6 +1,6 @@ obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ - sys_call_table.o + ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \ + syscalls.o sysrq.o sys_call_table.o obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_MODULES) += module.o @@ -16,6 +16,14 @@ semaphore.c-dir = kernel highmem.c-dir = mm module.c-dir = kernel +STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) + +# _cflags works with kernel files, not with userspace ones, but c_flags does, +# why ask why? +$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS) + +$(obj)/stub.o : a_flags = $(STUB_CFLAGS) + subdir- := util include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S new file mode 100644 index 00000000000..2f2c70a8f04 --- /dev/null +++ b/arch/um/sys-i386/stub.S @@ -0,0 +1,8 @@ +#include "uml-config.h" + + .globl syscall_stub +.section .__syscall_stub, "x" +syscall_stub: + int $0x80 + mov %eax, UML_CONFIG_STUB_DATA + int3 diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c new file mode 100644 index 00000000000..b251442ad0b --- /dev/null +++ b/arch/um/sys-i386/stub_segv.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <signal.h> +#include <asm/sigcontext.h> +#include <asm/unistd.h> +#include "uml-config.h" +#include "sysdep/sigcontext.h" +#include "sysdep/faultinfo.h" + +void __attribute__ ((__section__ (".__syscall_stub"))) +stub_segv_handler(int sig) +{ + struct sigcontext *sc = (struct sigcontext *) (&sig + 1); + + GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), + sc); + + __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid)); + __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;" + "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1)); + /* Pop the frame pointer and return address since we need to leave + * the stack in its original form when we do the sigreturn here, by + * hand. + */ + __asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; " + "int $0x80" : : "g" (__NR_sigreturn)); +} diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 2bc6f684901..7488206ce6f 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -6,8 +6,8 @@ #XXX: why into lib-y? lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ - ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ - syscalls.o sysrq.o thunk.o syscall_table.o + ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \ + stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o obj-y := ksyms.o obj-$(CONFIG_MODULES) += module.o um_module.o @@ -28,6 +28,14 @@ semaphore.c-dir = kernel thunk.S-dir = lib module.c-dir = kernel +STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) + +# _cflags works with kernel files, not with userspace ones, but c_flags does, +# why ask why? +$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS) + +$(obj)/stub.o : a_flags = $(STUB_CFLAGS) + subdir- := util include arch/um/scripts/Makefile.unmap diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S new file mode 100644 index 00000000000..31c14925716 --- /dev/null +++ b/arch/um/sys-x86_64/stub.S @@ -0,0 +1,15 @@ +#include "uml-config.h" + + .globl syscall_stub +.section .__syscall_stub, "x" +syscall_stub: + syscall + /* We don't have 64-bit constants, so this constructs the address + * we need. + */ + movq $(UML_CONFIG_STUB_DATA >> 32), %rbx + salq $32, %rbx + movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx + or %rcx, %rbx + movq %rax, (%rbx) + int3 diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c new file mode 100644 index 00000000000..161d1fe9c03 --- /dev/null +++ b/arch/um/sys-x86_64/stub_segv.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include <signal.h> +#include <linux/compiler.h> +#include <asm/unistd.h> +#include "uml-config.h" +#include "sysdep/sigcontext.h" +#include "sysdep/faultinfo.h" + +void __attribute__ ((__section__ (".__syscall_stub"))) +stub_segv_handler(int sig) +{ + struct ucontext *uc; + + __asm__("movq %%rdx, %0" : "=g" (uc) :); + GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), + &uc->uc_mcontext); + + __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid)); + __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;" + "syscall": : "g" (__NR_kill), "g" (SIGUSR1)); + /* Two popqs to restore the stack to the state just before entering + * the handler, one pops the return address, the other pops the frame + * pointer. + */ + __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g" + (__NR_rt_sigreturn)); +} diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 8a73794f9b9..42891569767 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -65,7 +65,9 @@ CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o libs-y += arch/x86_64/lib/ -core-y += arch/x86_64/kernel/ arch/x86_64/mm/ +core-y += arch/x86_64/kernel/ \ + arch/x86_64/mm/ \ + arch/x86_64/crypto/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ drivers-$(CONFIG_PCI) += arch/x86_64/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/ diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile new file mode 100644 index 00000000000..426d20f4b72 --- /dev/null +++ b/arch/x86_64/crypto/Makefile @@ -0,0 +1,9 @@ +# +# x86_64/crypto/Makefile +# +# Arch-specific CryptoAPI modules. +# + +obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o + +aes-x86_64-y := aes-x86_64-asm.o aes.o diff --git a/arch/x86_64/crypto/aes-x86_64-asm.S b/arch/x86_64/crypto/aes-x86_64-asm.S new file mode 100644 index 00000000000..483cbb23ab8 --- /dev/null +++ b/arch/x86_64/crypto/aes-x86_64-asm.S @@ -0,0 +1,186 @@ +/* AES (Rijndael) implementation (FIPS PUB 197) for x86_64 + * + * Copyright (C) 2005 Andreas Steinmetz, <ast@domdv.de> + * + * License: + * This code can be distributed under the terms of the GNU General Public + * License (GPL) Version 2 provided that the above header down to and + * including this sentence is retained in full. + */ + +.extern aes_ft_tab +.extern aes_it_tab +.extern aes_fl_tab +.extern aes_il_tab + +.text + +#define R1 %rax +#define R1E %eax +#define R1X %ax +#define R1H %ah +#define R1L %al +#define R2 %rbx +#define R2E %ebx +#define R2X %bx +#define R2H %bh +#define R2L %bl +#define R3 %rcx +#define R3E %ecx +#define R3X %cx +#define R3H %ch +#define R3L %cl +#define R4 %rdx +#define R4E %edx +#define R4X %dx +#define R4H %dh +#define R4L %dl +#define R5 %rsi +#define R5E %esi +#define R6 %rdi +#define R6E %edi +#define R7 %rbp +#define R7E %ebp +#define R8 %r8 +#define R9 %r9 +#define R10 %r10 +#define R11 %r11 + +#define prologue(FUNC,BASE,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \ + .global FUNC; \ + .type FUNC,@function; \ + .align 8; \ +FUNC: movq r1,r2; \ + movq r3,r4; \ + leaq BASE+52(r8),r9; \ + movq r10,r11; \ + movl (r7),r5 ## E; \ + movl 4(r7),r1 ## E; \ + movl 8(r7),r6 ## E; \ + movl 12(r7),r7 ## E; \ + movl (r8),r10 ## E; \ + xorl -48(r9),r5 ## E; \ + xorl -44(r9),r1 ## E; \ + xorl -40(r9),r6 ## E; \ + xorl -36(r9),r7 ## E; \ + cmpl $24,r10 ## E; \ + jb B128; \ + leaq 32(r9),r9; \ + je B192; \ + leaq 32(r9),r9; + +#define epilogue(r1,r2,r3,r4,r5,r6,r7,r8,r9) \ + movq r1,r2; \ + movq r3,r4; \ + movl r5 ## E,(r9); \ + movl r6 ## E,4(r9); \ + movl r7 ## E,8(r9); \ + movl r8 ## E,12(r9); \ + ret; + +#define round(TAB,OFFSET,r1,r2,r3,r4,r5,r6,r7,r8,ra,rb,rc,rd) \ + movzbl r2 ## H,r5 ## E; \ + movzbl r2 ## L,r6 ## E; \ + movl TAB+1024(,r5,4),r5 ## E;\ + movw r4 ## X,r2 ## X; \ + movl TAB(,r6,4),r6 ## E; \ + roll $16,r2 ## E; \ + shrl $16,r4 ## E; \ + movzbl r4 ## H,r7 ## E; \ + movzbl r4 ## L,r4 ## E; \ + xorl OFFSET(r8),ra ## E; \ + xorl OFFSET+4(r8),rb ## E; \ + xorl TAB+3072(,r7,4),r5 ## E;\ + xorl TAB+2048(,r4,4),r6 ## E;\ + movzbl r1 ## L,r7 ## E; \ + movzbl r1 ## H,r4 ## E; \ + movl TAB+1024(,r4,4),r4 ## E;\ + movw r3 ## X,r1 ## X; \ + roll $16,r1 ## E; \ + shrl $16,r3 ## E; \ + xorl TAB(,r7,4),r5 ## E; \ + movzbl r3 ## H,r7 ## E; \ + movzbl r3 ## L,r3 ## E; \ + xorl TAB+3072(,r7,4),r4 ## E;\ + xorl TAB+2048(,r3,4),r5 ## E;\ + movzbl r1 ## H,r7 ## E; \ + movzbl r1 ## L,r3 ## E; \ + shrl $16,r1 ## E; \ + xorl TAB+3072(,r7,4),r6 ## E;\ + movl TAB+2048(,r3,4),r3 ## E;\ + movzbl r1 ## H,r7 ## E; \ + movzbl r1 ## L,r1 ## E; \ + xorl TAB+1024(,r7,4),r6 ## E;\ + xorl TAB(,r1,4),r3 ## E; \ + movzbl r2 ## H,r1 ## E; \ + movzbl r2 ## L,r7 ## E; \ + shrl $16,r2 ## E; \ + xorl TAB+3072(,r1,4),r3 ## E;\ + xorl TAB+2048(,r7,4),r4 ## E;\ + movzbl r2 ## H,r1 ## E; \ + movzbl r2 ## L,r2 ## E; \ + xorl OFFSET+8(r8),rc ## E; \ + xorl OFFSET+12(r8),rd ## E; \ + xorl TAB+1024(,r1,4),r3 ## E;\ + xorl TAB(,r2,4),r4 ## E; + +#define move_regs(r1,r2,r3,r4) \ + movl r3 ## E,r1 ## E; \ + movl r4 ## E,r2 ## E; + +#define entry(FUNC,BASE,B128,B192) \ + prologue(FUNC,BASE,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11) + +#define return epilogue(R8,R2,R9,R7,R5,R6,R3,R4,R11) + +#define encrypt_round(TAB,OFFSET) \ + round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) \ + move_regs(R1,R2,R5,R6) + +#define encrypt_final(TAB,OFFSET) \ + round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) + +#define decrypt_round(TAB,OFFSET) \ + round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) \ + move_regs(R1,R2,R5,R6) + +#define decrypt_final(TAB,OFFSET) \ + round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) + +/* void aes_encrypt(void *ctx, u8 *out, const u8 *in) */ + + entry(aes_encrypt,0,enc128,enc192) + encrypt_round(aes_ft_tab,-96) + encrypt_round(aes_ft_tab,-80) +enc192: encrypt_round(aes_ft_tab,-64) + encrypt_round(aes_ft_tab,-48) +enc128: encrypt_round(aes_ft_tab,-32) + encrypt_round(aes_ft_tab,-16) + encrypt_round(aes_ft_tab, 0) + encrypt_round(aes_ft_tab, 16) + encrypt_round(aes_ft_tab, 32) + encrypt_round(aes_ft_tab, 48) + encrypt_round(aes_ft_tab, 64) + encrypt_round(aes_ft_tab, 80) + encrypt_round(aes_ft_tab, 96) + encrypt_final(aes_fl_tab,112) + return + +/* void aes_decrypt(void *ctx, u8 *out, const u8 *in) */ + + entry(aes_decrypt,240,dec128,dec192) + decrypt_round(aes_it_tab,-96) + decrypt_round(aes_it_tab,-80) +dec192: decrypt_round(aes_it_tab,-64) + decrypt_round(aes_it_tab,-48) +dec128: decrypt_round(aes_it_tab,-32) + decrypt_round(aes_it_tab,-16) + decrypt_round(aes_it_tab, 0) + decrypt_round(aes_it_tab, 16) + decrypt_round(aes_it_tab, 32) + decrypt_round(aes_it_tab, 48) + decrypt_round(aes_it_tab, 64) + decrypt_round(aes_it_tab, 80) + decrypt_round(aes_it_tab, 96) + decrypt_final(aes_il_tab,112) + return diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes.c new file mode 100644 index 00000000000..2b5c4010ce3 --- /dev/null +++ b/arch/x86_64/crypto/aes.c @@ -0,0 +1,324 @@ +/* + * Cryptographic API. + * + * AES Cipher Algorithm. + * + * Based on Brian Gladman's code. + * + * Linux developers: + * Alexander Kjeldaas <astor@fast.no> + * Herbert Valerio Riedel <hvr@hvrlab.org> + * Kyle McMartin <kyle@debian.org> + * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API). + * Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler) + * + * 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. + * + * --------------------------------------------------------------------------- + * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * All rights reserved. + * + * LICENSE TERMS + * + * The free distribution and use of this software in both source and binary + * form is allowed (with or without changes) provided that: + * + * 1. distributions of this source code include the above copyright + * notice, this list of conditions and the following disclaimer; + * + * 2. distributions in binary form include the above copyright + * notice, this list of conditions and the following disclaimer + * in the documentation and/or other associated materials; + * + * 3. the copyright holder's name is not used to endorse products + * built using this software without specific written permission. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * DISCLAIMER + * + * This software is provided 'as is' with no explicit or implied warranties + * in respect of its properties, including, but not limited to, correctness + * and/or fitness for purpose. + * --------------------------------------------------------------------------- + */ + +/* Some changes from the Gladman version: + s/RIJNDAEL(e_key)/E_KEY/g + s/RIJNDAEL(d_key)/D_KEY/g +*/ + +#include <asm/byteorder.h> +#include <linux/bitops.h> +#include <linux/crypto.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define AES_BLOCK_SIZE 16 + +/* + * #define byte(x, nr) ((unsigned char)((x) >> (nr*8))) + */ +static inline u8 byte(const u32 x, const unsigned n) +{ + return x >> (n << 3); +} + +#define u32_in(x) le32_to_cpu(*(const __le32 *)(x)) + +struct aes_ctx +{ + u32 key_length; + u32 E[60]; + u32 D[60]; +}; + +#define E_KEY ctx->E +#define D_KEY ctx->D + +static u8 pow_tab[256] __initdata; +static u8 log_tab[256] __initdata; +static u8 sbx_tab[256] __initdata; +static u8 isb_tab[256] __initdata; +static u32 rco_tab[10]; +u32 aes_ft_tab[4][256]; +u32 aes_it_tab[4][256]; + +u32 aes_fl_tab[4][256]; +u32 aes_il_tab[4][256]; + +static inline u8 f_mult(u8 a, u8 b) +{ + u8 aa = log_tab[a], cc = aa + log_tab[b]; + + return pow_tab[cc + (cc < aa ? 1 : 0)]; +} + +#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0) + +#define ls_box(x) \ + (aes_fl_tab[0][byte(x, 0)] ^ \ + aes_fl_tab[1][byte(x, 1)] ^ \ + aes_fl_tab[2][byte(x, 2)] ^ \ + aes_fl_tab[3][byte(x, 3)]) + +static void __init gen_tabs(void) +{ + u32 i, t; + u8 p, q; + + /* log and power tables for GF(2**8) finite field with + 0x011b as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables */ + + for (i = 0, p = 1; i < 256; ++i) { + pow_tab[i] = (u8)p; + log_tab[p] = (u8)i; + + p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + log_tab[1] = 0; + + for (i = 0, p = 1; i < 10; ++i) { + rco_tab[i] = p; + + p = (p << 1) ^ (p & 0x80 ? 0x01b : 0); + } + + for (i = 0; i < 256; ++i) { + p = (i ? pow_tab[255 - log_tab[i]] : 0); + q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2)); + p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2)); + sbx_tab[i] = p; + isb_tab[p] = (u8)i; + } + + for (i = 0; i < 256; ++i) { + p = sbx_tab[i]; + + t = p; + aes_fl_tab[0][i] = t; + aes_fl_tab[1][i] = rol32(t, 8); + aes_fl_tab[2][i] = rol32(t, 16); + aes_fl_tab[3][i] = rol32(t, 24); + + t = ((u32)ff_mult(2, p)) | + ((u32)p << 8) | + ((u32)p << 16) | ((u32)ff_mult(3, p) << 24); + + aes_ft_tab[0][i] = t; + aes_ft_tab[1][i] = rol32(t, 8); + aes_ft_tab[2][i] = rol32(t, 16); + aes_ft_tab[3][i] = rol32(t, 24); + + p = isb_tab[i]; + + t = p; + aes_il_tab[0][i] = t; + aes_il_tab[1][i] = rol32(t, 8); + aes_il_tab[2][i] = rol32(t, 16); + aes_il_tab[3][i] = rol32(t, 24); + + t = ((u32)ff_mult(14, p)) | + ((u32)ff_mult(9, p) << 8) | + ((u32)ff_mult(13, p) << 16) | + ((u32)ff_mult(11, p) << 24); + + aes_it_tab[0][i] = t; + aes_it_tab[1][i] = rol32(t, 8); + aes_it_tab[2][i] = rol32(t, 16); + aes_it_tab[3][i] = rol32(t, 24); + } +} + +#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) + +#define imix_col(y, x) \ + u = star_x(x); \ + v = star_x(u); \ + w = star_x(v); \ + t = w ^ (x); \ + (y) = u ^ v ^ w; \ + (y) ^= ror32(u ^ t, 8) ^ \ + ror32(v ^ t, 16) ^ \ + ror32(t, 24) + +/* initialise the key schedule from the user supplied key */ + +#define loop4(i) \ +{ \ + t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \ + t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \ + t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \ + t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \ +} + +#define loop6(i) \ +{ \ + t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \ + t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \ + t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \ + t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \ + t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \ + t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \ +} + +#define loop8(i) \ +{ \ + t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \ + t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \ + t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \ + t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \ + t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \ + t = E_KEY[8 * i + 4] ^ ls_box(t); \ + E_KEY[8 * i + 12] = t; \ + t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \ + t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \ + t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \ +} + +static int aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len, + u32 *flags) +{ + struct aes_ctx *ctx = ctx_arg; + u32 i, j, t, u, v, w; + + if (key_len != 16 && key_len != 24 && key_len != 32) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->key_length = key_len; + + D_KEY[key_len + 24] = E_KEY[0] = u32_in(in_key); + D_KEY[key_len + 25] = E_KEY[1] = u32_in(in_key + 4); + D_KEY[key_len + 26] = E_KEY[2] = u32_in(in_key + 8); + D_KEY[key_len + 27] = E_KEY[3] = u32_in(in_key + 12); + + switch (key_len) { + case 16: + t = E_KEY[3]; + for (i = 0; i < 10; ++i) + loop4(i); + break; + + case 24: + E_KEY[4] = u32_in(in_key + 16); + t = E_KEY[5] = u32_in(in_key + 20); + for (i = 0; i < 8; ++i) + loop6 (i); + break; + + case 32: + E_KEY[4] = u32_in(in_key + 16); + E_KEY[5] = u32_in(in_key + 20); + E_KEY[6] = u32_in(in_key + 24); + t = E_KEY[7] = u32_in(in_key + 28); + for (i = 0; i < 7; ++i) + loop8(i); + break; + } + + D_KEY[0] = E_KEY[key_len + 24]; + D_KEY[1] = E_KEY[key_len + 25]; + D_KEY[2] = E_KEY[key_len + 26]; + D_KEY[3] = E_KEY[key_len + 27]; + + for (i = 4; i < key_len + 24; ++i) { + j = key_len + 24 - (i & ~3) + (i & 3); + imix_col(D_KEY[j], E_KEY[i]); + } + + return 0; +} + +extern void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in); +extern void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in); + +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt + } + } +}; + +static int __init aes_init(void) +{ + gen_tabs(); + return crypto_register_alg(&aes_alg); +} + +static void __exit aes_fini(void) +{ + crypto_unregister_alg(&aes_alg); +} + +module_init(aes_init); +module_exit(aes_fini); + +MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); +MODULE_LICENSE("GPL"); diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index b02d921da4f..5fd03225058 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -1076,6 +1076,10 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c) #ifdef CONFIG_X86_MCE mcheck_init(c); #endif + if (c == &boot_cpu_data) + mtrr_bp_init(); + else + mtrr_ap_init(); #ifdef CONFIG_NUMA if (c != &boot_cpu_data) numa_add_cpu(c - cpu_data); diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index 6c0f402e3a8..0612640d91b 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -119,6 +119,7 @@ void __restore_processor_state(struct saved_context *ctxt) fix_processor_context(); do_fpu_end(); + mtrr_ap_init(); } void restore_processor_state(void) diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 73389f51c4e..61c12758ca7 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -56,6 +56,10 @@ SECTIONS .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { *(.data.cacheline_aligned) } + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { + *(.data.read_mostly) + } #define VSYSCALL_ADDR (-10*1024*1024) #define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c index abc8ed6c702..7270509c44d 100644 --- a/arch/xtensa/kernel/syscalls.c +++ b/arch/xtensa/kernel/syscalls.c @@ -42,12 +42,9 @@ #include <asm/mman.h> #include <asm/shmparam.h> #include <asm/page.h> -#include <asm/ipc.h> extern void do_syscall_trace(void); typedef int (*syscall_t)(void *a0,...); -extern int (*do_syscalls)(struct pt_regs *regs, syscall_t fun, - int narg); extern syscall_t sys_call_table[]; extern unsigned char sys_narg_table[]; @@ -72,10 +69,8 @@ int sys_pipe(int __user *userfds) /* * Common code for old and new mmaps. */ - -static inline long do_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) +long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long pgoff) { int error = -EBADF; struct file * file = NULL; @@ -97,29 +92,6 @@ out: return error; } -unsigned long old_mmap(unsigned long addr, size_t len, int prot, - int flags, int fd, off_t offset) -{ - return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); -} - -long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - -int sys_fork(struct pt_regs *regs) -{ - return do_fork(SIGCHLD, regs->areg[1], regs, 0, NULL, NULL); -} - -int sys_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD, regs->areg[1], - regs, 0, NULL, NULL); -} - int sys_clone(struct pt_regs *regs) { unsigned long clone_flags; @@ -162,30 +134,6 @@ int sys_uname(struct old_utsname * name) return -EFAULT; } -int sys_olduname(struct oldold_utsname * name) -{ - int error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) - return -EFAULT; - - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); - error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); - error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); - error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); - error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); - error -= __put_user(0,name->machine+__OLD_UTS_LEN); - - return error ? -EFAULT : 0; -} - - /* * Build the string table for the builtin "poor man's strace". */ @@ -319,100 +267,3 @@ void system_call (struct pt_regs *regs) regs->areg[2] = res; do_syscall_trace(); } - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ - -int sys_ipc (uint call, int first, int second, - int third, void __user *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - ret = -ENOSYS; - - switch (call) { - case SEMOP: - ret = sys_semtimedop (first, (struct sembuf __user *)ptr, - second, NULL); - break; - - case SEMTIMEDOP: - ret = sys_semtimedop (first, (struct sembuf __user *)ptr, - second, (const struct timespec *) fifth); - break; - - case SEMGET: - ret = sys_semget (first, second, third); - break; - - case SEMCTL: { - union semun fourth; - - if (ptr && !get_user(fourth.__pad, (void *__user *) ptr)) - ret = sys_semctl (first, second, third, fourth); - break; - } - - case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf __user*) ptr, - second, third); - break; - - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - - if (ptr && !copy_from_user(&tmp, - (struct ipc_kludge *) ptr, - sizeof (tmp))) - ret = sys_msgrcv (first, tmp.msgp, second, - tmp.msgtyp, third); - break; - } - - default: - ret = sys_msgrcv (first, (struct msgbuf __user *) ptr, - second, 0, third); - break; - } - break; - - case MSGGET: - ret = sys_msgget ((key_t) first, second); - break; - - case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds __user*) ptr); - break; - - case SHMAT: { - ulong raddr; - ret = do_shmat (first, (char __user *) ptr, second, &raddr); - - if (!ret) - ret = put_user (raddr, (ulong __user *) third); - - break; - } - - case SHMDT: - ret = sys_shmdt ((char __user *)ptr); - break; - - case SHMGET: - ret = sys_shmget (first, second, third); - break; - - case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds __user*) ptr); - break; - } - return ret; -} - diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h index 5b3f75f50fe..07580696b60 100644 --- a/arch/xtensa/kernel/syscalls.h +++ b/arch/xtensa/kernel/syscalls.h @@ -25,20 +25,19 @@ */ SYSCALL(0, 0) /* 00 */ - SYSCALL(sys_exit, 1) -SYSCALL(sys_fork, 0) +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_read, 3) SYSCALL(sys_write, 3) SYSCALL(sys_open, 3) /* 05 */ SYSCALL(sys_close, 1) -SYSCALL(sys_waitpid, 3) +SYSCALL(sys_ni_syscall, 3) SYSCALL(sys_creat, 2) SYSCALL(sys_link, 2) SYSCALL(sys_unlink, 1) /* 10 */ SYSCALL(sys_execve, 0) SYSCALL(sys_chdir, 1) -SYSCALL(sys_time, 1) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_mknod, 3) SYSCALL(sys_chmod, 2) /* 15 */ SYSCALL(sys_lchown, 3) @@ -47,19 +46,19 @@ SYSCALL(sys_stat, 2) SYSCALL(sys_lseek, 3) SYSCALL(sys_getpid, 0) /* 20 */ SYSCALL(sys_mount, 5) -SYSCALL(sys_oldumount, 1) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_setuid, 1) SYSCALL(sys_getuid, 0) -SYSCALL(sys_stime, 1) /* 25 */ +SYSCALL(sys_ni_syscall, 1) /* 25 */ SYSCALL(sys_ptrace, 4) -SYSCALL(sys_alarm, 1) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_fstat, 2) -SYSCALL(sys_pause, 0) +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_utime, 2) /* 30 */ SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_access, 2) -SYSCALL(sys_nice, 1) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_ni_syscall, 0) /* 35 */ SYSCALL(sys_sync, 0) SYSCALL(sys_kill, 2) @@ -73,7 +72,7 @@ SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_brk, 1) /* 45 */ SYSCALL(sys_setgid, 1) SYSCALL(sys_getgid, 0) -SYSCALL(sys_ni_syscall, 0) /* was signal(2) */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_geteuid, 0) SYSCALL(sys_getegid, 0) /* 50 */ SYSCALL(sys_acct, 1) @@ -84,21 +83,21 @@ SYSCALL(sys_fcntl, 3) /* 55 */ SYSCALL(sys_ni_syscall, 2) SYSCALL(sys_setpgid, 2) SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_olduname, 1) +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_umask, 1) /* 60 */ SYSCALL(sys_chroot, 1) SYSCALL(sys_ustat, 2) SYSCALL(sys_dup2, 2) SYSCALL(sys_getppid, 0) -SYSCALL(sys_getpgrp, 0) /* 65 */ +SYSCALL(sys_ni_syscall, 0) /* 65 */ SYSCALL(sys_setsid, 0) SYSCALL(sys_sigaction, 3) -SYSCALL(sys_sgetmask, 0) -SYSCALL(sys_ssetmask, 1) +SYSCALL(sys_ni_syscall, 0) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_setreuid, 2) /* 70 */ SYSCALL(sys_setregid, 2) SYSCALL(sys_sigsuspend, 0) -SYSCALL(sys_sigpending, 1) +SYSCALL(sys_ni_syscall, 1) SYSCALL(sys_sethostname, 2) SYSCALL(sys_setrlimit, 2) /* 75 */ SYSCALL(sys_getrlimit, 2) @@ -107,15 +106,15 @@ SYSCALL(sys_gettimeofday, 2) SYSCALL(sys_settimeofday, 2) SYSCALL(sys_getgroups, 2) /* 80 */ SYSCALL(sys_setgroups, 2) -SYSCALL(sys_ni_syscall, 0) /* old_select */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_symlink, 2) SYSCALL(sys_lstat, 2) SYSCALL(sys_readlink, 3) /* 85 */ SYSCALL(sys_uselib, 1) SYSCALL(sys_swapon, 2) SYSCALL(sys_reboot, 3) -SYSCALL(old_readdir, 3) -SYSCALL(old_mmap, 6) /* 90 */ +SYSCALL(sys_ni_syscall, 3) +SYSCALL(sys_ni_syscall, 6) /* 90 */ SYSCALL(sys_munmap, 2) SYSCALL(sys_truncate, 2) SYSCALL(sys_ftruncate, 2) @@ -127,7 +126,7 @@ SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_statfs, 2) SYSCALL(sys_fstatfs, 2) /* 100 */ SYSCALL(sys_ni_syscall, 3) -SYSCALL(sys_socketcall, 2) +SYSCALL(sys_ni_syscall, 2) SYSCALL(sys_syslog, 3) SYSCALL(sys_setitimer, 3) SYSCALL(sys_getitimer, 2) /* 105 */ @@ -137,32 +136,32 @@ SYSCALL(sys_newfstat, 2) SYSCALL(sys_uname, 1) SYSCALL(sys_ni_syscall, 0) /* 110 */ SYSCALL(sys_vhangup, 0) -SYSCALL(sys_ni_syscall, 0) /* was sys_idle() */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_wait4, 4) SYSCALL(sys_swapoff, 1) /* 115 */ SYSCALL(sys_sysinfo, 1) -SYSCALL(sys_ipc, 5) /* 6 really, but glibc uses only 5) */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_fsync, 1) SYSCALL(sys_sigreturn, 0) SYSCALL(sys_clone, 0) /* 120 */ SYSCALL(sys_setdomainname, 2) SYSCALL(sys_newuname, 1) -SYSCALL(sys_ni_syscall, 0) /* sys_modify_ldt */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_adjtimex, 1) SYSCALL(sys_mprotect, 3) /* 125 */ -SYSCALL(sys_sigprocmask, 3) -SYSCALL(sys_ni_syscall, 2) /* old sys_create_module */ +SYSCALL(sys_ni_syscall, 3) +SYSCALL(sys_ni_syscall, 2) SYSCALL(sys_init_module, 2) SYSCALL(sys_delete_module, 1) -SYSCALL(sys_ni_syscall, 1) /* old sys_get_kernel_sysm */ /* 130 */ +SYSCALL(sys_ni_syscall, 1) /* 130 */ SYSCALL(sys_quotactl, 0) SYSCALL(sys_getpgid, 1) SYSCALL(sys_fchdir, 1) SYSCALL(sys_bdflush, 2) SYSCALL(sys_sysfs, 3) /* 135 */ SYSCALL(sys_personality, 1) -SYSCALL(sys_ni_syscall, 0) /* for afs_syscall */ +SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_setfsuid, 1) SYSCALL(sys_setfsgid, 1) SYSCALL(sys_llseek, 5) /* 140 */ @@ -212,7 +211,7 @@ SYSCALL(sys_socket, 3) SYSCALL(sys_socketpair, 4) SYSCALL(sys_setresuid, 3) /* 185 */ SYSCALL(sys_getresuid, 3) -SYSCALL(sys_ni_syscall, 5) /* old sys_query_module */ +SYSCALL(sys_ni_syscall, 5) SYSCALL(sys_poll, 3) SYSCALL(sys_nfsservctl, 3) SYSCALL(sys_setresgid, 3) /* 190 */ @@ -235,7 +234,7 @@ SYSCALL(sys_sigaltstack, 0) SYSCALL(sys_sendfile, 4) SYSCALL(sys_ni_syscall, 0) SYSCALL(sys_ni_syscall, 0) -SYSCALL(sys_mmap2, 6) /* 210 */ +SYSCALL(sys_mmap, 6) /* 210 */ SYSCALL(sys_truncate64, 2) SYSCALL(sys_ftruncate64, 2) SYSCALL(sys_stat64, 2) @@ -245,4 +244,4 @@ SYSCALL(sys_pivot_root, 2) SYSCALL(sys_mincore, 3) SYSCALL(sys_madvise, 3) SYSCALL(sys_getdents64, 3) -SYSCALL(sys_vfork, 0) /* 220 */ +SYSCALL(sys_ni_syscall, 0) /* 220 */ |