diff options
Diffstat (limited to 'arch')
260 files changed, 5546 insertions, 3578 deletions
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c index 468b76ce66a..8ac08311f5a 100644 --- a/arch/alpha/kernel/pci-noop.c +++ b/arch/alpha/kernel/pci-noop.c @@ -165,7 +165,7 @@ dma_alloc_coherent(struct device *dev, size_t size, ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret) { memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); + *dma_handle = virt_to_phys(ret); } return ret; } @@ -184,7 +184,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents, BUG_ON(!sg_page(sg)); va = sg_virt(sg); - sg_dma_address(sg) = (dma_addr_t)virt_to_bus(va); + sg_dma_address(sg) = (dma_addr_t)virt_to_phys(va); sg_dma_len(sg) = sg->length; } diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 2d00a08d3f0..26d3789dfdd 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -9,6 +9,7 @@ #include <linux/bootmem.h> #include <linux/scatterlist.h> #include <linux/log2.h> +#include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/hwrpb.h> @@ -470,22 +471,29 @@ EXPORT_SYMBOL(pci_free_consistent); #define SG_ENT_PHYS_ADDRESS(SG) __pa(SG_ENT_VIRT_ADDRESS(SG)) static void -sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) +sg_classify(struct device *dev, struct scatterlist *sg, struct scatterlist *end, + int virt_ok) { unsigned long next_paddr; struct scatterlist *leader; long leader_flag, leader_length; + unsigned int max_seg_size; leader = sg; leader_flag = 0; leader_length = leader->length; next_paddr = SG_ENT_PHYS_ADDRESS(leader) + leader_length; + /* we will not marge sg without device. */ + max_seg_size = dev ? dma_get_max_seg_size(dev) : 0; for (++sg; sg < end; ++sg) { unsigned long addr, len; addr = SG_ENT_PHYS_ADDRESS(sg); len = sg->length; + if (leader_length + len > max_seg_size) + goto new_segment; + if (next_paddr == addr) { sg->dma_address = -1; leader_length += len; @@ -494,6 +502,7 @@ sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) leader_flag = 1; leader_length += len; } else { +new_segment: leader->dma_address = leader_flag; leader->dma_length = leader_length; leader = sg; @@ -512,7 +521,7 @@ sg_classify(struct scatterlist *sg, struct scatterlist *end, int virt_ok) in the blanks. */ static int -sg_fill(struct scatterlist *leader, struct scatterlist *end, +sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end, struct scatterlist *out, struct pci_iommu_arena *arena, dma_addr_t max_dma, int dac_allowed) { @@ -562,8 +571,8 @@ sg_fill(struct scatterlist *leader, struct scatterlist *end, /* Otherwise, break up the remaining virtually contiguous hunks into individual direct maps and retry. */ - sg_classify(leader, end, 0); - return sg_fill(leader, end, out, arena, max_dma, dac_allowed); + sg_classify(dev, leader, end, 0); + return sg_fill(dev, leader, end, out, arena, max_dma, dac_allowed); } out->dma_address = arena->dma_base + dma_ofs*PAGE_SIZE + paddr; @@ -619,12 +628,15 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, struct pci_iommu_arena *arena; dma_addr_t max_dma; int dac_allowed; + struct device *dev; if (direction == PCI_DMA_NONE) BUG(); dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0; + dev = pdev ? &pdev->dev : NULL; + /* Fast path single entry scatterlists. */ if (nents == 1) { sg->dma_length = sg->length; @@ -638,7 +650,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, end = sg + nents; /* First, prepare information about the entries. */ - sg_classify(sg, end, alpha_mv.mv_pci_tbi != 0); + sg_classify(dev, sg, end, alpha_mv.mv_pci_tbi != 0); /* Second, figure out where we're going to map things. */ if (alpha_mv.mv_pci_tbi) { @@ -658,7 +670,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, for (out = sg; sg < end; ++sg) { if ((int) sg->dma_address < 0) continue; - if (sg_fill(sg, end, out, arena, max_dma, dac_allowed) < 0) + if (sg_fill(dev, sg, end, out, arena, max_dma, dac_allowed) < 0) goto error; out++; } diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index bd5e68cd61e..beff6297f78 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -58,7 +58,6 @@ static struct notifier_block alpha_panic_block = { #include <asm/system.h> #include <asm/hwrpb.h> #include <asm/dma.h> -#include <asm/io.h> #include <asm/mmu_context.h> #include <asm/console.h> diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index 79de99e32c3..ba914af18c4 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -495,7 +495,7 @@ sys_call_table: .quad sys_epoll_pwait .quad sys_utimensat /* 475 */ .quad sys_signalfd - .quad sys_timerfd + .quad sys_ni_syscall .quad sys_eventfd .size sys_call_table, . - sys_call_table diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 471637002e8..e19e7744e36 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -35,6 +35,11 @@ config GENERIC_CLOCKEVENTS bool default n +config GENERIC_CLOCKEVENTS_BROADCAST + bool + depends on GENERIC_CLOCKEVENTS + default y if SMP && !LOCAL_TIMERS + config MMU bool default y @@ -187,6 +192,8 @@ config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARM_AMBA select ICST307 + select GENERIC_TIME + select GENERIC_CLOCKEVENTS help This enables support for ARM Ltd RealView boards. @@ -378,6 +385,7 @@ config ARCH_PXA depends on MMU select ARCH_MTD_XIP select GENERIC_GPIO + select HAVE_GPIO_LIB select GENERIC_TIME select GENERIC_CLOCKEVENTS select TICK_ONESHOT @@ -623,7 +631,7 @@ source "kernel/time/Kconfig" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" - depends on EXPERIMENTAL && REALVIEW_MPCORE + depends on EXPERIMENTAL && REALVIEW_EB_ARM11MP help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -656,7 +664,7 @@ config HOTPLUG_CPU config LOCAL_TIMERS bool "Use local timer interrupts" - depends on SMP && REALVIEW_MPCORE + depends on SMP && REALVIEW_EB_ARM11MP default y help Enable support for local timers on SMP platforms, rather then the @@ -912,6 +920,13 @@ config KEXEC initially work for you. It may help to enable device hotplugging support. +config ATAGS_PROC + bool "Export atags in procfs" + default n + help + Should the atags used to boot the kernel be exported in an "atags" + file in procfs. Useful with kexec. + endmenu if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX || ARCH_PXA) @@ -1108,6 +1123,8 @@ source "drivers/i2c/Kconfig" source "drivers/spi/Kconfig" +source "drivers/gpio/Kconfig" + source "drivers/w1/Kconfig" source "drivers/power/Kconfig" diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c index 34038eccbba..d544da41473 100644 --- a/arch/arm/common/time-acorn.c +++ b/arch/arm/common/time-acorn.c @@ -69,9 +69,7 @@ void __init ioctime_init(void) static irqreturn_t ioc_timer_interrupt(int irq, void *dev_id) { - write_seqlock(&xtime_lock); timer_tick(); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index db850a5689e..efa0485d2f7 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -1,69 +1,96 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.15 -# Tue Jan 3 03:20:40 2006 +# Linux kernel version: 2.6.24 +# Sun Jan 27 07:33:38 2008 # CONFIG_ARM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_MMU=y -CONFIG_UID16=y +# CONFIG_NO_IOPORT is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # -# Code maturity level options +# General setup # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y # CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y # CONFIG_BSD_PROCESS_ACCT_V3 is not set -CONFIG_SYSCTL=y +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set # CONFIG_AUDIT is not set -# CONFIG_HOTPLUG is not set -CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y +CONFIG_ANON_INODES=y CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y # CONFIG_MODULE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y CONFIG_MODVERSIONS=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -81,28 +108,39 @@ CONFIG_DEFAULT_IOSCHED="anticipatory" # # System Type # +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_AT91 is not set # CONFIG_ARCH_CLPS7500 is not set # CONFIG_ARCH_CLPS711X is not set # CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set # CONFIG_ARCH_FOOTBRIDGE is not set -# CONFIG_ARCH_INTEGRATOR is not set -# CONFIG_ARCH_IOP3XX is not set -CONFIG_ARCH_IXP4XX=y +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set # CONFIG_ARCH_IXP2000 is not set +CONFIG_ARCH_IXP4XX=y # CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_PNX4008 is not set # CONFIG_ARCH_PXA is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C2410 is not set # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_DAVINCI is not set # CONFIG_ARCH_OMAP is not set -# CONFIG_ARCH_VERSATILE is not set -# CONFIG_ARCH_REALVIEW is not set -# CONFIG_ARCH_IMX is not set -# CONFIG_ARCH_H720X is not set -# CONFIG_ARCH_AAEC2000 is not set CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # @@ -112,8 +150,12 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y # # IXP4xx Platforms # -CONFIG_ARCH_AVILA=y +CONFIG_MACH_NSLU2=y +CONFIG_MACH_AVILA=y +CONFIG_MACH_LOFT=y CONFIG_ARCH_ADI_COYOTE=y +CONFIG_MACH_GATEWAY7001=y +CONFIG_MACH_WG302V2=y CONFIG_ARCH_IXDP425=y CONFIG_MACH_IXDPG425=y CONFIG_MACH_IXDP465=y @@ -121,15 +163,27 @@ CONFIG_MACH_KIXRP435=y CONFIG_ARCH_IXCDP1100=y CONFIG_ARCH_PRPMC1100=y CONFIG_MACH_NAS100D=y +CONFIG_MACH_DSMG600=y CONFIG_ARCH_IXDP4XX=y CONFIG_CPU_IXP46X=y CONFIG_CPU_IXP43X=y -# CONFIG_MACH_GTWX5715 is not set +CONFIG_MACH_GTWX5715=y # # IXP4xx Options # +CONFIG_DMABOUNCE=y # CONFIG_IXP4XX_INDIRECT_PCI is not set +CONFIG_IXP4XX_QMGR=y +CONFIG_IXP4XX_NPE=y + +# +# Boot options +# + +# +# Power management +# # # Processor Type @@ -140,33 +194,40 @@ CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5T=y CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y # # Processor Features # # CONFIG_ARM_THUMB is not set CONFIG_CPU_BIG_ENDIAN=y +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_OUTER_CACHE is not set +# CONFIG_IWMMXT is not set CONFIG_XSCALE_PMU=y -CONFIG_DMABOUNCE=y # # Bus support # -CONFIG_ISA_DMA_API=y CONFIG_PCI=y -CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_SYSCALL=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_PCI_LEGACY=y # CONFIG_PCI_DEBUG is not set - -# -# PCCARD (PCMCIA/CardBus) support -# # CONFIG_PCCARD is not set # # Kernel Features # +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y # CONFIG_PREEMPT is not set -# CONFIG_NO_IDLE_HZ is not set +CONFIG_HZ=100 +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set CONFIG_SELECT_MEMORY_MODEL=y CONFIG_FLATMEM_MANUAL=y @@ -175,7 +236,12 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set CONFIG_SPLIT_PTLOCK_CPUS=4096 +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y +CONFIG_VIRT_TO_BUS=y CONFIG_ALIGNMENT_TRAP=y # @@ -185,6 +251,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyS0,115200 ip=bootp root=/dev/nfs" # CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set # # Floating point emulation @@ -203,13 +270,12 @@ CONFIG_FPE_NWFPE=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_AOUT is not set # CONFIG_BINFMT_MISC is not set -# CONFIG_ARTHUR is not set # # Power management options # # CONFIG_PM is not set -# CONFIG_APM is not set +CONFIG_SUSPEND_UP_POSSIBLE=y # # Networking @@ -219,11 +285,13 @@ CONFIG_NET=y # # Networking options # -CONFIG_PACKET=m +CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set # CONFIG_NET_KEY is not set CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -232,9 +300,7 @@ CONFIG_ASK_IP_FIB_HASH=y # CONFIG_IP_FIB_TRIE is not set CONFIG_IP_FIB_HASH=y CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_FWMARK=y CONFIG_IP_ROUTE_MULTIPATH=y -# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y @@ -251,15 +317,18 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set -CONFIG_INET_TUNNEL=m +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y - -# -# IP: Virtual Server Configuration -# +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set CONFIG_IP_VS=m CONFIG_IP_VS_DEBUG=y CONFIG_IP_VS_TAB_BITS=12 @@ -290,6 +359,9 @@ CONFIG_IP_VS_SH=m # IPVS application helper # # CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -298,70 +370,57 @@ CONFIG_BRIDGE_NETFILTER=y # Core Netfilter Configuration # # CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NF_CONNTRACK_ENABLED is not set +# CONFIG_NF_CONNTRACK is not set +CONFIG_NETFILTER_XTABLES=m +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set # # IP: Netfilter Configuration # -CONFIG_IP_NF_CONNTRACK=m -# CONFIG_IP_NF_CT_ACCT is not set -# CONFIG_IP_NF_CONNTRACK_MARK is not set -# CONFIG_IP_NF_CONNTRACK_EVENTS is not set -# CONFIG_IP_NF_CT_PROTO_SCTP is not set -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -# CONFIG_IP_NF_NETBIOS_NS is not set -# CONFIG_IP_NF_TFTP is not set -# CONFIG_IP_NF_AMANDA is not set -# CONFIG_IP_NF_PPTP is not set CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m # CONFIG_IP_NF_MATCH_IPRANGE is not set -CONFIG_IP_NF_MATCH_MAC=m -# CONFIG_IP_NF_MATCH_PKTTYPE is not set -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m # CONFIG_IP_NF_MATCH_RECENT is not set # CONFIG_IP_NF_MATCH_ECN is not set -# CONFIG_IP_NF_MATCH_DSCP is not set -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m +# CONFIG_IP_NF_MATCH_AH is not set CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -# CONFIG_IP_NF_MATCH_HELPER is not set -CONFIG_IP_NF_MATCH_STATE=m -# CONFIG_IP_NF_MATCH_CONNTRACK is not set CONFIG_IP_NF_MATCH_OWNER=m -# CONFIG_IP_NF_MATCH_PHYSDEV is not set # CONFIG_IP_NF_MATCH_ADDRTYPE is not set -# CONFIG_IP_NF_MATCH_REALM is not set -# CONFIG_IP_NF_MATCH_SCTP is not set -# CONFIG_IP_NF_MATCH_DCCP is not set -# CONFIG_IP_NF_MATCH_COMMENT is not set -# CONFIG_IP_NF_MATCH_HASHLIMIT is not set -# CONFIG_IP_NF_MATCH_STRING is not set CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -# CONFIG_IP_NF_TARGET_NFQUEUE is not set -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -# CONFIG_IP_NF_TARGET_NETMAP is not set -# CONFIG_IP_NF_TARGET_SAME is not set -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_TOS=m # CONFIG_IP_NF_TARGET_ECN is not set -# CONFIG_IP_NF_TARGET_DSCP is not set -CONFIG_IP_NF_TARGET_MARK=m -# CONFIG_IP_NF_TARGET_CLASSIFY is not set # CONFIG_IP_NF_TARGET_TTL is not set # CONFIG_IP_NF_RAW is not set CONFIG_IP_NF_ARPTABLES=m @@ -372,16 +431,9 @@ CONFIG_IP_NF_ARPFILTER=m # Bridge: Netfilter Configuration # # CONFIG_BRIDGE_NF_EBTABLES is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# # CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set CONFIG_ATM=y CONFIG_ATM_CLIP=y # CONFIG_ATM_CLIP_NO_ICMP is not set @@ -397,25 +449,17 @@ CONFIG_LLC=m CONFIG_IPX=m # CONFIG_IPX_INTERN is not set CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=y +CONFIG_DEV_APPLETALK=m CONFIG_IPDDP=m CONFIG_IPDDP_ENCAP=y CONFIG_IPDDP_DECAP=y CONFIG_X25=m CONFIG_LAPB=m -# CONFIG_NET_DIVERT is not set CONFIG_ECONET=m CONFIG_ECONET_AUNUDP=y CONFIG_ECONET_NATIVE=y CONFIG_WAN_ROUTER=m - -# -# QoS and/or fair queueing -# CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CLK_JIFFIES=y -# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set -# CONFIG_NET_SCH_CLK_CPU is not set # # Queueing/Scheduling @@ -425,6 +469,7 @@ CONFIG_NET_SCH_HTB=m # CONFIG_NET_SCH_HFSC is not set # CONFIG_NET_SCH_ATM is not set CONFIG_NET_SCH_PRIO=m +# CONFIG_NET_SCH_RR is not set CONFIG_NET_SCH_RED=m CONFIG_NET_SCH_SFQ=m CONFIG_NET_SCH_TEQL=m @@ -449,10 +494,17 @@ CONFIG_NET_CLS_U32=m CONFIG_NET_CLS_RSVP=m CONFIG_NET_CLS_RSVP6=m # CONFIG_NET_EMATCH is not set -# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set CONFIG_NET_CLS_POLICE=y # CONFIG_NET_CLS_IND is not set -CONFIG_NET_ESTIMATOR=y +CONFIG_NET_SCH_FIFO=y # # Network testing @@ -461,7 +513,18 @@ CONFIG_NET_PKTGEN=m # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y + +# +# Wireless +# +# CONFIG_CFG80211 is not set +# CONFIG_WIRELESS_EXT is not set +# CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -470,19 +533,14 @@ CONFIG_NET_PKTGEN=m # # Generic Driver Options # +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set +CONFIG_FW_LOADER=y # CONFIG_DEBUG_DRIVER is not set - -# -# Connector - unified userspace <-> kernelspace linker -# +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set # CONFIG_CONNECTOR is not set - -# -# Memory Technology Devices (MTD) -# CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_CONCAT is not set @@ -498,11 +556,14 @@ CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 # User Modules And Translation Layers # CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y CONFIG_MTD_BLOCK=y # CONFIG_FTL is not set # CONFIG_NFTL is not set # CONFIG_INFTL is not set # CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_MTD_OOPS is not set # # RAM/ROM/Flash chip drivers @@ -528,7 +589,6 @@ CONFIG_MTD_CFI_UTIL=y # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_XIP is not set # # Mapping drivers for chip access @@ -538,6 +598,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y # CONFIG_MTD_ARM_INTEGRATOR is not set CONFIG_MTD_IXP4XX=y # CONFIG_MTD_PCI is not set +# CONFIG_MTD_INTEL_VR_NOR is not set # CONFIG_MTD_PLATRAM is not set # @@ -547,7 +608,6 @@ CONFIG_MTD_IXP4XX=y # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set -# CONFIG_MTD_BLKMTD is not set # CONFIG_MTD_BLOCK2MTD is not set # @@ -556,33 +616,24 @@ CONFIG_MTD_IXP4XX=y # CONFIG_MTD_DOC2000 is not set # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set - -# -# NAND Flash Device Drivers -# CONFIG_MTD_NAND=m # CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set CONFIG_MTD_NAND_IDS=m # CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_CAFE is not set # CONFIG_MTD_NAND_NANDSIM is not set - -# -# OneNAND Flash Device Drivers -# +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set # CONFIG_MTD_ONENAND is not set # -# Parallel port support +# UBI - Unsorted block images # +# CONFIG_MTD_UBI is not set # CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -592,17 +643,20 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# ATA/ATAPI/MFM/RLL support -# +CONFIG_MISC_DEVICES=y +# CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set CONFIG_IDE=y +CONFIG_IDE_MAX_HWIFS=4 CONFIG_BLK_DEV_IDE=y # @@ -614,24 +668,28 @@ CONFIG_BLK_DEV_IDEDISK=y # CONFIG_BLK_DEV_IDECD is not set # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_IDE_TASK_IOCTL is not set +CONFIG_IDE_PROC_FS=y # # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y +# CONFIG_BLK_DEV_PLATFORM is not set + +# +# PCI IDE chipsets support +# CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_PCIBUS_ORDER=y # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_GENERIC is not set # CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_SL82C105 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y -# CONFIG_BLK_DEV_IDEDMA_FORCED is not set -# CONFIG_IDEDMA_PCI_AUTO is not set # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD74XX is not set CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -639,93 +697,163 @@ CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set CONFIG_BLK_DEV_HPT366=y +# CONFIG_BLK_DEV_JMICRON is not set # CONFIG_BLK_DEV_SC1200 is not set # CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_IT8213 is not set # CONFIG_BLK_DEV_IT821X is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set CONFIG_BLK_DEV_PDC202XX_NEW=y -# CONFIG_PDC202XX_FORCE is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SL82C105 is not set # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_TC86C001 is not set # CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_IDEDMA_IVB is not set -# CONFIG_IDEDMA_AUTO is not set +CONFIG_IDE_ARCH_OBSOLETE_INIT=y # CONFIG_BLK_DEV_HD is not set # # SCSI device support # # CONFIG_RAID_ATTRS is not set -# CONFIG_SCSI is not set - -# -# Multi-device support (RAID and LVM) -# +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# 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 +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_ATA=y +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_SVW is not set +# CONFIG_ATA_PIIX is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +CONFIG_PATA_ARTOP=y +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_PLATFORM is not set +CONFIG_PATA_IXP4XX_CF=y # CONFIG_MD is not set - -# -# Fusion MPT device support -# # CONFIG_FUSION is not set # # IEEE 1394 (FireWire) support # +# CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_IFB is not set CONFIG_DUMMY=y # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set - -# -# ARCnet devices -# +# CONFIG_VETH is not set # CONFIG_ARCNET is not set - -# -# PHY device support -# # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=y +CONFIG_IXP4XX_ETH=y +# CONFIG_AX88796 is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set # CONFIG_DM9000 is not set - -# -# Tulip family network device support -# # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 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=y # CONFIG_E100 is not set # CONFIG_FEALNX is not set @@ -738,93 +866,76 @@ CONFIG_EEPRO100=y # CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set - -# -# Ethernet (1000 Mbit) -# +# CONFIG_SC92031 is not set +CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IP1000 is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set # CONFIG_SIS190 is not set # CONFIG_SKGE is not set +# CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set - -# -# Ethernet (10000 Mbit) -# +# CONFIG_QLA3XXX is not set +# CONFIG_ATL1 is not set +CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGBE is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set - -# -# Token Ring devices -# +# CONFIG_MYRI10GE is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NIU is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_TEHUTI is not set # CONFIG_TR is not set # -# Wireless LAN (non-hamradio) -# -CONFIG_NET_RADIO=y - -# -# Obsolete Wireless cards support (pre-802.11) -# -# CONFIG_STRIP is not set - -# -# Wireless 802.11b ISA/PCI cards support -# -# CONFIG_AIRO is not set -CONFIG_HERMES=y -# CONFIG_PLX_HERMES is not set -# CONFIG_TMD_HERMES is not set -# CONFIG_NORTEL_HERMES is not set -CONFIG_PCI_HERMES=y -# CONFIG_ATMEL is not set - -# -# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support +# Wireless LAN # -# CONFIG_PRISM54 is not set -# CONFIG_HOSTAP is not set -CONFIG_NET_WIRELESS=y +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set # -# Wan interfaces +# USB Network Adapters # +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set CONFIG_WAN=y -# CONFIG_DSCC4 is not set # CONFIG_LANMEDIA is not set -# CONFIG_SYNCLINK_SYNCPPP is not set CONFIG_HDLC=m -CONFIG_HDLC_RAW=y +CONFIG_HDLC_RAW=m # CONFIG_HDLC_RAW_ETH is not set -CONFIG_HDLC_CISCO=y -CONFIG_HDLC_FR=y -CONFIG_HDLC_PPP=y -CONFIG_HDLC_X25=y +CONFIG_HDLC_CISCO=m +CONFIG_HDLC_FR=m +CONFIG_HDLC_PPP=m +CONFIG_HDLC_X25=m # CONFIG_PCI200SYN is not set # CONFIG_WANXL is not set # CONFIG_PC300 is not set +# CONFIG_PC300TOO is not set # CONFIG_FARSYNC is not set +# CONFIG_DSCC4 is not set +# CONFIG_IXP4XX_HSS is not set CONFIG_DLCI=m -CONFIG_DLCI_COUNT=24 CONFIG_DLCI_MAX=8 -CONFIG_WAN_ROUTER_DRIVERS=y +CONFIG_WAN_ROUTER_DRIVERS=m # CONFIG_CYCLADES_SYNC is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set - -# -# ATM drivers -# +CONFIG_ATM_DRIVERS=y # CONFIG_ATM_DUMMY is not set CONFIG_ATM_TCP=m # CONFIG_ATM_LANAI is not set @@ -842,20 +953,19 @@ CONFIG_ATM_TCP=m # CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set +# CONFIG_NET_FC is not set # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set # # Input device support # CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -865,7 +975,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set @@ -875,8 +984,16 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set # CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_IXP4XX_BEEPER=y +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_UINPUT is not set # # Hardware I/O ports @@ -895,7 +1012,9 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_PCI=y CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 # CONFIG_SERIAL_8250_EXTENDED is not set # @@ -907,51 +1026,17 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -CONFIG_WATCHDOG=y -# CONFIG_WATCHDOG_NOWAYOUT is not set - -# -# Watchdog Device Drivers -# -# CONFIG_SOFT_WATCHDOG is not set -CONFIG_IXP4XX_WATCHDOG=y - -# -# PCI-based Watchdog Cards -# -# CONFIG_PCIPCWATCHDOG is not set -# CONFIG_WDTPCI is not set +CONFIG_HW_RANDOM=m +CONFIG_HW_RANDOM_IXP4XX=m # CONFIG_NVRAM is not set -# CONFIG_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 -# CONFIG_TELCLOCK is not set - -# -# I2C support -# +CONFIG_DEVPORT=y CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y CONFIG_I2C_CHARDEV=y # @@ -969,57 +1054,68 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_ALI15X3 is not set # CONFIG_I2C_AMD756 is not set # CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_GPIO is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_IOP3XX is not set CONFIG_I2C_IXP4XX=y # CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set -# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIMTEC is not set # CONFIG_I2C_SIS5595 is not set # CONFIG_I2C_SIS630 is not set # CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_TAOS_EVM is not set # CONFIG_I2C_STUB is not set +# CONFIG_I2C_TINY_USB is not set # CONFIG_I2C_VIA is not set # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set -# CONFIG_I2C_PCA_ISA is not set # # Miscellaneous I2C Chip support # # CONFIG_SENSORS_DS1337 is not set # CONFIG_SENSORS_DS1374 is not set +# CONFIG_DS1682 is not set CONFIG_SENSORS_EEPROM=y # 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_SENSORS_MAX6875 is not set -# CONFIG_RTC_X1205_I2C is not set +# CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set # CONFIG_I2C_DEBUG_CHIP is not set # -# Hardware Monitoring support +# SPI support # +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_AD7418 is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ADM9240 is not set -# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ADT7470 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 +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set @@ -1033,67 +1129,268 @@ CONFIG_HWMON=y # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set # CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_THMC50 is not set # CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set # CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set # -# Misc devices +# Watchdog Device Drivers # +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_IXP4XX_WATCHDOG=y # -# Multimedia Capabilities Port drivers +# PCI-based Watchdog Cards # +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set # -# Multimedia devices +# USB-based Watchdog Cards # -# CONFIG_VIDEO_DEV is not set +# CONFIG_USBPCWATCHDOG is not set # -# Digital Video Broadcasting Devices +# Sonics Silicon Backplane # -# CONFIG_DVB is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set # # Graphics support # +# CONFIG_DRM is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set # # Sound # # CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set # -# USB support +# USB Input Devices # +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y -# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_SPLIT_ISO is not set +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # # +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set + +# +# USB DSL modem support +# +# CONFIG_USB_ATM is not set + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set +# CONFIG_MMC is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y # -# MMC/SD Card support +# LED drivers +# +# CONFIG_LEDS_IXP4XX is not set +CONFIG_LEDS_GPIO=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_IDE_DISK=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +CONFIG_RTC_DRV_X1205=y +CONFIG_RTC_DRV_PCF8563=y +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers # -# CONFIG_MMC is not set # # File systems @@ -1107,16 +1404,19 @@ CONFIG_EXT3_FS=y CONFIG_EXT3_FS_XATTR=y CONFIG_EXT3_FS_POSIX_ACL=y # CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT4DEV_FS is not set CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -1140,11 +1440,12 @@ CONFIG_DNOTIFY=y # Pseudo filesystems # CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y CONFIG_SYSFS=y CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -1156,13 +1457,15 @@ CONFIG_RAMFS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set -# CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 CONFIG_JFFS2_FS_WRITEBUFFER=y +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set # CONFIG_JFFS2_SUMMARY is not set +# CONFIG_JFFS2_FS_XATTR is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y +# CONFIG_JFFS2_LZO is not set CONFIG_JFFS2_RTIME=y # CONFIG_JFFS2_RUBIN is not set # CONFIG_CRAMFS is not set @@ -1171,10 +1474,7 @@ CONFIG_JFFS2_RTIME=y # CONFIG_QNX4FS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set - -# -# Network File Systems -# +CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V3_ACL is not set @@ -1186,6 +1486,7 @@ CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y +# CONFIG_SUNRPC_BIND34 is not set # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set @@ -1193,7 +1494,6 @@ CONFIG_SUNRPC=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 @@ -1213,37 +1513,53 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set # CONFIG_EFI_PARTITION is not set - -# -# Native Language Support -# +# CONFIG_SYSV68_PARTITION is not set # CONFIG_NLS is not set - -# -# Profiling support -# +# CONFIG_DLM is not set +CONFIG_INSTRUMENTATION=y # CONFIG_PROFILING is not set +# CONFIG_MARKERS is not set # # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y CONFIG_MAGIC_SYSRQ=y -CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set CONFIG_DETECT_SOFTLOCKUP=y +CONFIG_SCHED_DEBUG=y # CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_SG is not set CONFIG_FRAME_POINTER=y +CONFIG_FORCED_INLINING=y +# CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_SAMPLES is not set # CONFIG_DEBUG_USER is not set CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_LL=y @@ -1254,22 +1570,22 @@ CONFIG_DEBUG_LL=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# +# CONFIG_SECURITY_FILE_CAPABILITIES is not set # CONFIG_CRYPTO is not set # -# Hardware crypto devices -# - -# # Library routines # +CONFIG_BITREVERSE=y # CONFIG_CRC_CCITT is not set # CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index faa76192115..00d44c6fbfe 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o +obj-$(CONFIG_ATAGS_PROC) += atags.o obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c new file mode 100644 index 00000000000..e2e934c3808 --- /dev/null +++ b/arch/arm/kernel/atags.c @@ -0,0 +1,86 @@ +#include <linux/slab.h> +#include <linux/kexec.h> +#include <linux/proc_fs.h> +#include <asm/setup.h> +#include <asm/types.h> +#include <asm/page.h> + +struct buffer { + size_t size; + char *data; +}; +static struct buffer tags_buffer; + +static int +read_buffer(char* page, char** start, off_t off, int count, + int* eof, void* data) +{ + struct buffer *buffer = (struct buffer *)data; + + if (off >= buffer->size) { + *eof = 1; + return 0; + } + + count = min((int) (buffer->size - off), count); + + memcpy(page, &buffer->data[off], count); + + return count; +} + + +static int +create_proc_entries(void) +{ + struct proc_dir_entry* tags_entry; + + tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer); + if (!tags_entry) + return -ENOMEM; + + return 0; +} + + +static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE]; +static char __initdata *atags_copy; + +void __init save_atags(const struct tag *tags) +{ + atags_copy = atags_copy_buf; + memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE); +} + + +static int __init init_atags_procfs(void) +{ + struct tag *tag; + int error; + + if (!atags_copy) { + printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n"); + return -EIO; + } + + for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag)) + ; + + tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr); + tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL); + if (tags_buffer.data == NULL) + return -ENOMEM; + memcpy(tags_buffer.data, atags_copy, tags_buffer.size); + + error = create_proc_entries(); + if (error) { + printk(KERN_ERR "Exporting ATAGs: not enough memory\n"); + kfree(tags_buffer.data); + tags_buffer.size = 0; + tags_buffer.data = NULL; + } + + return error; +} + +arch_initcall(init_atags_procfs); diff --git a/arch/arm/kernel/atags.h b/arch/arm/kernel/atags.h new file mode 100644 index 00000000000..e5f028d214a --- /dev/null +++ b/arch/arm/kernel/atags.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_ATAGS_PROC +extern void save_atags(struct tag *tags); +#else +static inline void save_atags(struct tag *tags) { } +#endif diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index cecf658e362..283e14fff99 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -359,7 +359,7 @@ CALL(sys_kexec_load) CALL(sys_utimensat) CALL(sys_signalfd) -/* 350 */ CALL(sys_timerfd) +/* 350 */ CALL(sys_ni_syscall) CALL(sys_eventfd) CALL(sys_fallocate) #ifndef syscalls_counted diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 863c66454f2..db8f54a3451 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -21,6 +21,7 @@ extern void setup_mm_for_reboot(char mode); extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; extern unsigned long kexec_mach_type; +extern unsigned long kexec_boot_atags; /* * Provide a dummy crash_notes definition while crash dump arrives to arm. @@ -62,6 +63,7 @@ void machine_kexec(struct kimage *image) kexec_start_address = image->start; kexec_indirection_page = page_list; kexec_mach_type = machine_arch_type; + kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET; /* copy our kernel relocation code to the control code page */ memcpy(reboot_code_buffer, diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S index 062c111c572..61930eb0902 100644 --- a/arch/arm/kernel/relocate_kernel.S +++ b/arch/arm/kernel/relocate_kernel.S @@ -7,23 +7,6 @@ .globl relocate_new_kernel relocate_new_kernel: - /* Move boot params back to where the kernel expects them */ - - ldr r0,kexec_boot_params_address - teq r0,#0 - beq 8f - - ldr r1,kexec_boot_params_copy - mov r6,#KEXEC_BOOT_PARAMS_SIZE/4 -7: - ldr r5,[r1],#4 - str r5,[r0],#4 - subs r6,r6,#1 - bne 7b - -8: - /* Boot params moved, now go on with the kernel */ - ldr r0,kexec_indirection_page ldr r1,kexec_start_address @@ -67,7 +50,7 @@ relocate_new_kernel: mov lr,r1 mov r0,#0 ldr r1,kexec_mach_type - ldr r2,kexec_boot_params_address + ldr r2,kexec_boot_atags mov pc,lr .globl kexec_start_address @@ -82,14 +65,9 @@ kexec_indirection_page: kexec_mach_type: .long 0x0 - /* phy addr where new kernel will expect to find boot params */ - .globl kexec_boot_params_address -kexec_boot_params_address: - .long 0x0 - - /* phy addr where old kernel put a copy of orig boot params */ - .globl kexec_boot_params_copy -kexec_boot_params_copy: + /* phy addr of the atags for the new kernel */ + .globl kexec_boot_atags +kexec_boot_atags: .long 0x0 relocate_new_kernel_end: diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index bf56eb337df..d3941a7b045 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -24,7 +24,6 @@ #include <linux/interrupt.h> #include <linux/smp.h> #include <linux/fs.h> -#include <linux/kexec.h> #include <asm/cpu.h> #include <asm/elf.h> @@ -39,6 +38,7 @@ #include <asm/mach/time.h> #include "compat.h" +#include "atags.h" #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -62,6 +62,7 @@ extern int root_mountflags; extern void _stext, _text, _etext, __data_start, _edata, _end; unsigned int processor_id; +EXPORT_SYMBOL(processor_id); unsigned int __machine_arch_type; EXPORT_SYMBOL(__machine_arch_type); @@ -784,23 +785,6 @@ static int __init customize_machine(void) } arch_initcall(customize_machine); -#ifdef CONFIG_KEXEC - -/* Physical addr of where the boot params should be for this machine */ -extern unsigned long kexec_boot_params_address; - -/* Physical addr of the buffer into which the boot params are copied */ -extern unsigned long kexec_boot_params_copy; - -/* Pointer to the boot params buffer, for manipulation and display */ -unsigned long kexec_boot_params; -EXPORT_SYMBOL(kexec_boot_params); - -/* The buffer itself - make sure it is sized correctly */ -static unsigned long kexec_boot_params_buf[(KEXEC_BOOT_PARAMS_SIZE + 3) / 4]; - -#endif - void __init setup_arch(char **cmdline_p) { struct tag *tags = (struct tag *)&init_tags; @@ -819,18 +803,6 @@ void __init setup_arch(char **cmdline_p) else if (mdesc->boot_params) tags = phys_to_virt(mdesc->boot_params); -#ifdef CONFIG_KEXEC - kexec_boot_params_copy = virt_to_phys(kexec_boot_params_buf); - kexec_boot_params = (unsigned long)kexec_boot_params_buf; - if (__atags_pointer) { - kexec_boot_params_address = __atags_pointer; - memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE); - } else if (mdesc->boot_params) { - kexec_boot_params_address = mdesc->boot_params; - memcpy((void *)kexec_boot_params, tags, KEXEC_BOOT_PARAMS_SIZE); - } -#endif - /* * If we have the old style parameters, convert them to * a tag list. @@ -846,6 +818,7 @@ void __init setup_arch(char **cmdline_p) if (tags->hdr.tag == ATAG_CORE) { if (meminfo.nr_banks != 0) squash_mem_tags(tags); + save_atags(tags); parse_tags(tags); } diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index eafbb2b05eb..eefae1de334 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -150,7 +150,7 @@ int __cpuinit __cpu_up(unsigned int cpu) secondary_data.pgdir = 0; *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); - pgd_free(pgd); + pgd_free(&init_mm, pgd); if (ret) { printk(KERN_CRIT "CPU%u: processor failed to boot\n", cpu); @@ -290,6 +290,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) local_irq_enable(); local_fiq_enable(); + /* + * Setup local timer for this CPU. + */ + local_timer_setup(cpu); + calibrate_delay(); smp_store_cpu_info(cpu); @@ -300,11 +305,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) cpu_set(cpu, cpu_online_map); /* - * Setup local timer for this CPU. - */ - local_timer_setup(cpu); - - /* * OK, it's off to the idle thread for us */ cpu_idle(); @@ -454,6 +454,27 @@ int smp_call_function(void (*func)(void *info), void *info, int retry, } EXPORT_SYMBOL_GPL(smp_call_function); +int smp_call_function_single(int cpu, void (*func)(void *info), void *info, + int retry, int wait) +{ + /* prevent preemption and reschedule on another processor */ + int current_cpu = get_cpu(); + int ret = 0; + + if (cpu == current_cpu) { + local_irq_disable(); + func(info); + local_irq_enable(); + } else + ret = smp_call_function_on_cpu(func, info, retry, wait, + cpumask_of_cpu(cpu)); + + put_cpu(); + + return ret; +} +EXPORT_SYMBOL_GPL(smp_call_function_single); + void show_ipi_list(struct seq_file *p) { unsigned int cpu; @@ -481,8 +502,7 @@ void show_local_irqs(struct seq_file *p) static void ipi_timer(void) { irq_enter(); - profile_tick(CPU_PROFILING); - update_process_times(user_mode(get_irq_regs())); + local_timer_interrupt(); irq_exit(); } @@ -621,6 +641,11 @@ void smp_send_timer(void) send_ipi_message(mask, IPI_TIMER); } +void smp_timer_broadcast(cpumask_t mask) +{ + send_ipi_message(mask, IPI_TIMER); +} + void smp_send_stop(void) { cpumask_t mask = cpu_online_map; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 5b0422cdde7..074dcd5d9a7 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -253,6 +253,36 @@ config AT91_TIMER_HZ system clock (of at least several MHz), rounding is less of a problem so it can be safer to use a decimal values like 100. +choice + prompt "Select a UART for early kernel messages" + +config AT91_EARLY_DBGU + bool "DBGU" + +config AT91_EARLY_USART0 + bool "USART0" + +config AT91_EARLY_USART1 + bool "USART1" + +config AT91_EARLY_USART2 + bool "USART2" + depends on ! ARCH_AT91X40 + +config AT91_EARLY_USART3 + bool "USART3" + depends on (ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9260) + +config AT91_EARLY_USART4 + bool "USART4" + depends on ARCH_AT91SAM9260 + +config AT91_EARLY_USART5 + bool "USART5" + depends on ARCH_AT91SAM9260 + +endchoice + endmenu endif diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c index 5c090c9442f..e38d2377099 100644 --- a/arch/arm/mach-at91/at91sam926x_time.c +++ b/arch/arm/mach-at91/at91sam926x_time.c @@ -49,8 +49,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) volatile long nr_ticks; if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */ - write_seqlock(&xtime_lock); - /* Get number to ticks performed before interrupt and clear PIT interrupt */ nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR)); do { @@ -58,7 +56,6 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) nr_ticks--; } while (nr_ticks); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } else return IRQ_NONE; /* not handled */ diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h index b5daf7f5e01..7b9ce7a336b 100644 --- a/arch/arm/mach-at91/generic.h +++ b/arch/arm/mach-at91/generic.h @@ -47,6 +47,9 @@ extern void at91_irq_resume(void); #define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */ struct at91_gpio_bank { + unsigned chipbase; /* bank's first GPIO number */ + void __iomem *regbase; /* base of register bank */ + struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */ unsigned short id; /* peripheral ID */ unsigned long offset; /* offset from system peripheral base */ struct clk *clock; /* associated clock */ diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 6aeddd68d8a..f629c2b5f0c 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -33,12 +33,10 @@ static int gpio_banks; static inline void __iomem *pin_to_controller(unsigned pin) { - void __iomem *sys_base = (void __iomem *) AT91_VA_BASE_SYS; - pin -= PIN_BASE; pin /= 32; if (likely(pin < gpio_banks)) - return sys_base + gpio[pin].offset; + return gpio[pin].regbase; return NULL; } @@ -294,11 +292,11 @@ void at91_gpio_suspend(void) int i; for (i = 0; i < gpio_banks; i++) { - u32 pio = gpio[i].offset; + void __iomem *pio = gpio[i].regbase; - backups[i] = at91_sys_read(pio + PIO_IMR); - at91_sys_write(pio + PIO_IDR, backups[i]); - at91_sys_write(pio + PIO_IER, wakeups[i]); + backups[i] = __raw_readl(pio + PIO_IMR); + __raw_writel(backups[i], pio + PIO_IDR); + __raw_writel(wakeups[i], pio + PIO_IER); if (!wakeups[i]) clk_disable(gpio[i].clock); @@ -315,13 +313,13 @@ void at91_gpio_resume(void) int i; for (i = 0; i < gpio_banks; i++) { - u32 pio = gpio[i].offset; + void __iomem *pio = gpio[i].regbase; if (!wakeups[i]) clk_enable(gpio[i].clock); - at91_sys_write(pio + PIO_IDR, wakeups[i]); - at91_sys_write(pio + PIO_IER, backups[i]); + __raw_writel(wakeups[i], pio + PIO_IDR); + __raw_writel(backups[i], pio + PIO_IER); } } @@ -361,7 +359,13 @@ static void gpio_irq_unmask(unsigned pin) static int gpio_irq_type(unsigned pin, unsigned type) { - return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL; + switch (type) { + case IRQ_TYPE_NONE: + case IRQ_TYPE_EDGE_BOTH: + return 0; + default: + return -EINVAL; + } } static struct irq_chip gpio_irqchip = { @@ -376,20 +380,30 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { unsigned pin; struct irq_desc *gpio; + struct at91_gpio_bank *bank; void __iomem *pio; u32 isr; - pio = get_irq_chip_data(irq); + bank = get_irq_chip_data(irq); + pio = bank->regbase; /* temporarily mask (level sensitive) parent IRQ */ desc->chip->ack(irq); for (;;) { - /* reading ISR acks the pending (edge triggered) GPIO interrupt */ + /* Reading ISR acks pending (edge triggered) GPIO interrupts. + * When there none are pending, we're finished unless we need + * to process multiple banks (like ID_PIOCDE on sam9263). + */ isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR); - if (!isr) - break; + if (!isr) { + if (!bank->next) + break; + bank = bank->next; + pio = bank->regbase; + continue; + } - pin = (unsigned) get_irq_data(irq); + pin = bank->chipbase; gpio = &irq_desc[pin]; while (isr) { @@ -481,24 +495,21 @@ postcore_initcall(at91_gpio_debugfs_init); */ void __init at91_gpio_irq_setup(void) { - unsigned pioc, pin; + unsigned pioc, pin; + struct at91_gpio_bank *this, *prev; - for (pioc = 0, pin = PIN_BASE; - pioc < gpio_banks; - pioc++) { - void __iomem *controller; - unsigned id = gpio[pioc].id; + for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL; + pioc++ < gpio_banks; + prev = this, this++) { + unsigned id = this->id; unsigned i; - clk_enable(gpio[pioc].clock); /* enable PIO controller's clock */ - - controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset; - __raw_writel(~0, controller + PIO_IDR); + /* enable PIO controller's clock */ + clk_enable(this->clock); - set_irq_data(id, (void *) pin); - set_irq_chip_data(id, controller); + __raw_writel(~0, this->regbase + PIO_IDR); - for (i = 0; i < 32; i++, pin++) { + for (i = 0, pin = this->chipbase; i < 32; i++, pin++) { /* * Can use the "simple" and not "edge" handler since it's * shorter, and the AIC handles interrupts sanely. @@ -508,6 +519,14 @@ void __init at91_gpio_irq_setup(void) set_irq_flags(pin, IRQF_VALID); } + /* The toplevel handler handles one bank of GPIOs, except + * AT91SAM9263_ID_PIOCDE handles three... PIOC is first in + * the list, so we only set up that handler. + */ + if (prev && prev->next == this) + continue; + + set_irq_chip_data(id, this); set_irq_chained_handler(id, gpio_irq_handler); } pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks); @@ -518,8 +537,20 @@ void __init at91_gpio_irq_setup(void) */ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) { + unsigned i; + struct at91_gpio_bank *last; + BUG_ON(nr_banks > MAX_GPIO_BANKS); gpio = data; gpio_banks = nr_banks; + + for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) { + data->chipbase = PIN_BASE + i * 32; + data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS; + + /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ + if (last && last->id == data->id) + last->next = data; + } } diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 61b2dfcb89d..e774447c059 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -189,6 +189,20 @@ config IXP4XX_INDIRECT_PCI need to use the indirect method instead. If you don't know what you need, leave this option unselected. +config IXP4XX_QMGR + tristate "IXP4xx Queue Manager support" + help + This driver supports IXP4xx built-in hardware queue manager + and is automatically selected by Ethernet and HSS drivers. + +config IXP4XX_NPE + tristate "IXP4xx Network Processor Engine support" + select HOTPLUG + select FW_LOADER + help + This driver supports IXP4xx built-in network coprocessors + and is automatically selected by Ethernet and HSS drivers. + endmenu endif diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile index 77e00ade558..c1956882c48 100644 --- a/arch/arm/mach-ixp4xx/Makefile +++ b/arch/arm/mach-ixp4xx/Makefile @@ -23,10 +23,12 @@ obj-$(CONFIG_MACH_AVILA) += avila-setup.o obj-$(CONFIG_MACH_IXDPG425) += coyote-setup.o obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o -obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o -obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o -obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o +obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o +obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o +obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o +obj-$(CONFIG_IXP4XX_QMGR) += ixp4xx_qmgr.o +obj-$(CONFIG_IXP4XX_NPE) += ixp4xx_npe.o diff --git a/arch/arm/mach-ixp4xx/dsmg600-power.c b/arch/arm/mach-ixp4xx/dsmg600-power.c deleted file mode 100644 index 34717872d07..00000000000 --- a/arch/arm/mach-ixp4xx/dsmg600-power.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * arch/arm/mach-ixp4xx/dsmg600-power.c - * - * DSM-G600 Power/Reset driver - * Author: Michael Westerhof <mwester@dls.net> - * - * Based on nslu2-power.c - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * which was based on nslu2-io.c - * Copyright (C) 2004 Karen Spearel - * - * Maintainers: http://www.nslu2-linux.org/ - * - * 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/module.h> -#include <linux/reboot.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/jiffies.h> -#include <linux/timer.h> - -#include <asm/mach-types.h> - -extern void ctrl_alt_del(void); - -/* This is used to make sure the power-button pusher is serious. The button - * must be held until the value of this counter reaches zero. - */ -static volatile int power_button_countdown; - -/* Must hold the button down for at least this many counts to be processed */ -#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ - -static void dsmg600_power_handler(unsigned long data); -static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0); - -static void dsmg600_power_handler(unsigned long data) -{ - /* This routine is called twice per second to check the - * state of the power button. - */ - - if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) { - - /* IO Pin is 1 (button pushed) */ - if (power_button_countdown == 0) { - /* Signal init to do the ctrlaltdel action, this will bypass - * init if it hasn't started and do a kernel_restart. - */ - ctrl_alt_del(); - - /* Change the state of the power LED to "blink" */ - gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW); - } - power_button_countdown--; - - } else { - power_button_countdown = PBUTTON_HOLDDOWN_COUNT; - } - - mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); -} - -static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id) -{ - /* This is the paper-clip reset, it shuts the machine down directly. */ - machine_power_off(); - - return IRQ_HANDLED; -} - -static int __init dsmg600_power_init(void) -{ - if (!(machine_is_dsmg600())) - return 0; - - if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler, - IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button", - NULL) < 0) { - - printk(KERN_DEBUG "Reset Button IRQ %d not available\n", - DSMG600_RB_IRQ); - - return -EIO; - } - - /* The power button on the D-Link DSM-G600 is on GPIO 15, but - * it cannot handle interrupts on that GPIO line. So we'll - * have to poll it with a kernel timer. - */ - - /* Make sure that the power button GPIO is set up as an input */ - gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN); - - /* Set the initial value for the power button IRQ handler */ - power_button_countdown = PBUTTON_HOLDDOWN_COUNT; - - mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); - - return 0; -} - -static void __exit dsmg600_power_exit(void) -{ - if (!(machine_is_dsmg600())) - return; - - del_timer_sync(&dsmg600_power_timer); - - free_irq(DSMG600_RB_IRQ, NULL); -} - -module_init(dsmg600_power_init); -module_exit(dsmg600_power_exit); - -MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>"); -MODULE_DESCRIPTION("DSM-G600 Power/Reset driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index c473d408aa7..688659668bd 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -1,25 +1,37 @@ /* * DSM-G600 board-setup * + * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au> * Copyright (C) 2006 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> * - * based ixdp425-setup.c: + * based on ixdp425-setup.c: * Copyright (C) 2003-2004 MontaVista Software, Inc. + * based on nslu2-power.c: + * Copyright (C) 2005 Tower Technologies + * based on nslu2-io.c: + * Copyright (C) 2004 Karen Spearel * * Author: Alessandro Zummo <a.zummo@towertech.it> + * Author: Michael Westerhof <mwester@dls.net> + * Author: Rod Whitby <rod@whitby.id.au> * Maintainers: http://www.nslu2-linux.org/ */ -#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include <linux/serial.h> #include <linux/serial_8250.h> +#include <linux/leds.h> +#include <linux/reboot.h> +#include <linux/i2c.h> #include <linux/i2c-gpio.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> #include <asm/mach/time.h> +#include <asm/gpio.h> static struct flash_platform_data dsmg600_flash_data = { .map_name = "cfi_probe", @@ -51,29 +63,34 @@ static struct platform_device dsmg600_i2c_gpio = { }, }; -#ifdef CONFIG_LEDS_CLASS -static struct resource dsmg600_led_resources[] = { +static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = { + { + I2C_BOARD_INFO("rtc-pcf8563", 0x51), + }, +}; + +static struct gpio_led dsmg600_led_pins[] = { { - .name = "power", - .start = DSMG600_LED_PWR_GPIO, - .end = DSMG600_LED_PWR_GPIO, - .flags = IXP4XX_GPIO_HIGH, + .name = "power", + .gpio = DSMG600_LED_PWR_GPIO, }, { - .name = "wlan", - .start = DSMG600_LED_WLAN_GPIO, - .end = DSMG600_LED_WLAN_GPIO, - .flags = IXP4XX_GPIO_LOW, + .name = "wlan", + .gpio = DSMG600_LED_WLAN_GPIO, + .active_low = true, }, }; +static struct gpio_led_platform_data dsmg600_led_data = { + .num_leds = ARRAY_SIZE(dsmg600_led_pins), + .leds = dsmg600_led_pins, +}; + static struct platform_device dsmg600_leds = { - .name = "IXP4XX-GPIO-LED", - .id = -1, - .num_resources = ARRAY_SIZE(dsmg600_led_resources), - .resource = dsmg600_led_resources, + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &dsmg600_led_data, }; -#endif static struct resource dsmg600_uart_resources[] = { { @@ -121,6 +138,7 @@ static struct platform_device dsmg600_uart = { static struct platform_device *dsmg600_devices[] __initdata = { &dsmg600_i2c_gpio, &dsmg600_flash, + &dsmg600_leds, }; static void dsmg600_power_off(void) @@ -132,6 +150,57 @@ static void dsmg600_power_off(void) gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH); } +/* This is used to make sure the power-button pusher is serious. The button + * must be held until the value of this counter reaches zero. + */ +static int power_button_countdown; + +/* Must hold the button down for at least this many counts to be processed */ +#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ + +static void dsmg600_power_handler(unsigned long data); +static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0); + +static void dsmg600_power_handler(unsigned long data) +{ + /* This routine is called twice per second to check the + * state of the power button. + */ + + if (gpio_get_value(DSMG600_PB_GPIO)) { + + /* IO Pin is 1 (button pushed) */ + if (power_button_countdown > 0) + power_button_countdown--; + + } else { + + /* Done on button release, to allow for auto-power-on mods. */ + if (power_button_countdown == 0) { + /* Signal init to do the ctrlaltdel action, + * this will bypass init if it hasn't started + * and do a kernel_restart. + */ + ctrl_alt_del(); + + /* Change the state of the power LED to "blink" */ + gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + } else { + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + } + } + + mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); +} + +static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id) +{ + /* This is the paper-clip reset, it shuts the machine down directly. */ + machine_power_off(); + + return IRQ_HANDLED; +} + static void __init dsmg600_timer_init(void) { /* The xtal on this machine is non-standard. */ @@ -156,7 +225,8 @@ static void __init dsmg600_init(void) dsmg600_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; - pm_power_off = dsmg600_power_off; + i2c_register_board_info(0, dsmg600_i2c_board_info, + ARRAY_SIZE(dsmg600_i2c_board_info)); /* The UART is required on the DSM-G600 (Redboot cannot use the * NIC) -- do it here so that it does *not* get removed if @@ -166,10 +236,28 @@ static void __init dsmg600_init(void) platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices)); -#ifdef CONFIG_LEDS_CLASS - /* We don't care whether or not this works. */ - (void)platform_device_register(&dsmg600_leds); -#endif + pm_power_off = dsmg600_power_off; + + if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler, + IRQF_DISABLED | IRQF_TRIGGER_LOW, + "DSM-G600 reset button", NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + gpio_to_irq(DSMG600_RB_GPIO)); + } + + /* The power button on the D-Link DSM-G600 is on GPIO 15, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Make sure that the power button GPIO is set up as an input */ + gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500)); } MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index e89070da28b..44584afb34a 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -177,6 +177,31 @@ static struct platform_device ixdp425_uart = { .resource = ixdp425_uart_resources }; +/* Built-in 10/100 Ethernet MAC interfaces */ +static struct eth_plat_info ixdp425_plat_eth[] = { + { + .phy = 0, + .rxq = 3, + .txreadyq = 20, + }, { + .phy = 1, + .rxq = 4, + .txreadyq = 21, + } +}; + +static struct platform_device ixdp425_eth[] = { + { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEB, + .dev.platform_data = ixdp425_plat_eth, + }, { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEC, + .dev.platform_data = ixdp425_plat_eth + 1, + } +}; + static struct platform_device *ixdp425_devices[] __initdata = { &ixdp425_i2c_gpio, &ixdp425_flash, @@ -184,7 +209,9 @@ static struct platform_device *ixdp425_devices[] __initdata = { defined(CONFIG_MTD_NAND_PLATFORM_MODULE) &ixdp425_flash_nand, #endif - &ixdp425_uart + &ixdp425_uart, + &ixdp425_eth[0], + &ixdp425_eth[1], }; static void __init ixdp425_init(void) diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c new file mode 100644 index 00000000000..83c137ec582 --- /dev/null +++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c @@ -0,0 +1,741 @@ +/* + * Intel IXP4xx Network Processor Engine driver for Linux + * + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * The code is based on publicly available information: + * - Intel IXP4xx Developer's Manual and other e-papers + * - Intel IXP400 Access Library Software (BSD license) + * - previous works by Christian Hohnstaedt <chohnstaedt@innominate.com> + * Thanks, Christian. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/firmware.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/arch/npe.h> + +#define DEBUG_MSG 0 +#define DEBUG_FW 0 + +#define NPE_COUNT 3 +#define MAX_RETRIES 1000 /* microseconds */ +#define NPE_42X_DATA_SIZE 0x800 /* in dwords */ +#define NPE_46X_DATA_SIZE 0x1000 +#define NPE_A_42X_INSTR_SIZE 0x1000 +#define NPE_B_AND_C_42X_INSTR_SIZE 0x800 +#define NPE_46X_INSTR_SIZE 0x1000 +#define REGS_SIZE 0x1000 + +#define NPE_PHYS_REG 32 + +#define FW_MAGIC 0xFEEDF00D +#define FW_BLOCK_TYPE_INSTR 0x0 +#define FW_BLOCK_TYPE_DATA 0x1 +#define FW_BLOCK_TYPE_EOF 0xF + +/* NPE exec status (read) and command (write) */ +#define CMD_NPE_STEP 0x01 +#define CMD_NPE_START 0x02 +#define CMD_NPE_STOP 0x03 +#define CMD_NPE_CLR_PIPE 0x04 +#define CMD_CLR_PROFILE_CNT 0x0C +#define CMD_RD_INS_MEM 0x10 /* instruction memory */ +#define CMD_WR_INS_MEM 0x11 +#define CMD_RD_DATA_MEM 0x12 /* data memory */ +#define CMD_WR_DATA_MEM 0x13 +#define CMD_RD_ECS_REG 0x14 /* exec access register */ +#define CMD_WR_ECS_REG 0x15 + +#define STAT_RUN 0x80000000 +#define STAT_STOP 0x40000000 +#define STAT_CLEAR 0x20000000 +#define STAT_ECS_K 0x00800000 /* pipeline clean */ + +#define NPE_STEVT 0x1B +#define NPE_STARTPC 0x1C +#define NPE_REGMAP 0x1E +#define NPE_CINDEX 0x1F + +#define INSTR_WR_REG_SHORT 0x0000C000 +#define INSTR_WR_REG_BYTE 0x00004000 +#define INSTR_RD_FIFO 0x0F888220 +#define INSTR_RESET_MBOX 0x0FAC8210 + +#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */ +#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */ +#define ECS_BG_CTXT_REG_2 0x02 +#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */ +#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */ +#define ECS_PRI_1_CTXT_REG_2 0x06 +#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */ +#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */ +#define ECS_PRI_2_CTXT_REG_2 0x0A +#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */ +#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */ +#define ECS_DBG_CTXT_REG_2 0x0E +#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */ + +#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */ +#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */ +#define ECS_REG_0_LDUR_BITS 8 +#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */ +#define ECS_REG_1_CCTXT_BITS 16 +#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */ +#define ECS_REG_1_SELCTXT_BITS 0 +#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */ +#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */ +#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */ + +/* NPE watchpoint_fifo register bit */ +#define WFIFO_VALID 0x80000000 + +/* NPE messaging_status register bit definitions */ +#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */ +#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */ +#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */ +#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */ +#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */ +#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */ +#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */ +#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */ + +/* NPE messaging_control register bit definitions */ +#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */ +#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */ +#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */ +#define MSGCTL_IN_FIFO_WRITE 0x02000000 + +/* NPE mailbox_status value for reset */ +#define RESET_MBOX_STAT 0x0000F0F0 + +const char *npe_names[] = { "NPE-A", "NPE-B", "NPE-C" }; + +#define print_npe(pri, npe, fmt, ...) \ + printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__) + +#if DEBUG_MSG +#define debug_msg(npe, fmt, ...) \ + print_npe(KERN_DEBUG, npe, fmt, ## __VA_ARGS__) +#else +#define debug_msg(npe, fmt, ...) +#endif + +static struct { + u32 reg, val; +} ecs_reset[] = { + { ECS_BG_CTXT_REG_0, 0xA0000000 }, + { ECS_BG_CTXT_REG_1, 0x01000000 }, + { ECS_BG_CTXT_REG_2, 0x00008000 }, + { ECS_PRI_1_CTXT_REG_0, 0x20000080 }, + { ECS_PRI_1_CTXT_REG_1, 0x01000000 }, + { ECS_PRI_1_CTXT_REG_2, 0x00008000 }, + { ECS_PRI_2_CTXT_REG_0, 0x20000080 }, + { ECS_PRI_2_CTXT_REG_1, 0x01000000 }, + { ECS_PRI_2_CTXT_REG_2, 0x00008000 }, + { ECS_DBG_CTXT_REG_0, 0x20000000 }, + { ECS_DBG_CTXT_REG_1, 0x00000000 }, + { ECS_DBG_CTXT_REG_2, 0x001E0000 }, + { ECS_INSTRUCT_REG, 0x1003C00F }, +}; + +static struct npe npe_tab[NPE_COUNT] = { + { + .id = 0, + .regs = (struct npe_regs __iomem *)IXP4XX_NPEA_BASE_VIRT, + .regs_phys = IXP4XX_NPEA_BASE_PHYS, + }, { + .id = 1, + .regs = (struct npe_regs __iomem *)IXP4XX_NPEB_BASE_VIRT, + .regs_phys = IXP4XX_NPEB_BASE_PHYS, + }, { + .id = 2, + .regs = (struct npe_regs __iomem *)IXP4XX_NPEC_BASE_VIRT, + .regs_phys = IXP4XX_NPEC_BASE_PHYS, + } +}; + +int npe_running(struct npe *npe) +{ + return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0; +} + +static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data) +{ + __raw_writel(data, &npe->regs->exec_data); + __raw_writel(addr, &npe->regs->exec_addr); + __raw_writel(cmd, &npe->regs->exec_status_cmd); +} + +static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd) +{ + __raw_writel(addr, &npe->regs->exec_addr); + __raw_writel(cmd, &npe->regs->exec_status_cmd); + /* Iintroduce extra read cycles after issuing read command to NPE + so that we read the register after the NPE has updated it. + This is to overcome race condition between XScale and NPE */ + __raw_readl(&npe->regs->exec_data); + __raw_readl(&npe->regs->exec_data); + return __raw_readl(&npe->regs->exec_data); +} + +static void npe_clear_active(struct npe *npe, u32 reg) +{ + u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG); + npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE); +} + +static void npe_start(struct npe *npe) +{ + /* ensure only Background Context Stack Level is active */ + npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0); + npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0); + npe_clear_active(npe, ECS_DBG_CTXT_REG_0); + + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); + __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd); +} + +static void npe_stop(struct npe *npe) +{ + __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd); + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/ +} + +static int __must_check npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, + u32 ldur) +{ + u32 wc; + int i; + + /* set the Active bit, and the LDUR, in the debug level */ + npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, + ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS)); + + /* set CCTXT at ECS DEBUG L3 to specify in which context to execute + the instruction, and set SELCTXT at ECS DEBUG Level to specify + which context store to access. + Debug ECS Level Reg 1 has form 0x000n000n, where n = context number + */ + npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG, + (ctx << ECS_REG_1_CCTXT_BITS) | + (ctx << ECS_REG_1_SELCTXT_BITS)); + + /* clear the pipeline */ + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); + + /* load NPE instruction into the instruction register */ + npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr); + + /* we need this value later to wait for completion of NPE execution + step */ + wc = __raw_readl(&npe->regs->watch_count); + + /* issue a Step One command via the Execution Control register */ + __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd); + + /* Watch Count register increments when NPE completes an instruction */ + for (i = 0; i < MAX_RETRIES; i++) { + if (wc != __raw_readl(&npe->regs->watch_count)) + return 0; + udelay(1); + } + + print_npe(KERN_ERR, npe, "reset: npe_debug_instr(): timeout\n"); + return -ETIMEDOUT; +} + +static int __must_check npe_logical_reg_write8(struct npe *npe, u32 addr, + u8 val, u32 ctx) +{ + /* here we build the NPE assembler instruction: mov8 d0, #0 */ + u32 instr = INSTR_WR_REG_BYTE | /* OpCode */ + addr << 9 | /* base Operand */ + (val & 0x1F) << 4 | /* lower 5 bits to immediate data */ + (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */ + return npe_debug_instr(npe, instr, ctx, 1); /* execute it */ +} + +static int __must_check npe_logical_reg_write16(struct npe *npe, u32 addr, + u16 val, u32 ctx) +{ + /* here we build the NPE assembler instruction: mov16 d0, #0 */ + u32 instr = INSTR_WR_REG_SHORT | /* OpCode */ + addr << 9 | /* base Operand */ + (val & 0x1F) << 4 | /* lower 5 bits to immediate data */ + (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */ + return npe_debug_instr(npe, instr, ctx, 1); /* execute it */ +} + +static int __must_check npe_logical_reg_write32(struct npe *npe, u32 addr, + u32 val, u32 ctx) +{ + /* write in 16 bit steps first the high and then the low value */ + if (npe_logical_reg_write16(npe, addr, val >> 16, ctx)) + return -ETIMEDOUT; + return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx); +} + +static int npe_reset(struct npe *npe) +{ + u32 val, ctl, exec_count, ctx_reg2; + int i; + + ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) & + 0x3F3FFFFF; + + /* disable parity interrupt */ + __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control); + + /* pre exec - debug instruction */ + /* turn off the halt bit by clearing Execution Count register. */ + exec_count = __raw_readl(&npe->regs->exec_count); + __raw_writel(0, &npe->regs->exec_count); + /* ensure that IF and IE are on (temporarily), so that we don't end up + stepping forever */ + ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG); + npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 | + ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE); + + /* clear the FIFOs */ + while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID) + ; + while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) + /* read from the outFIFO until empty */ + print_npe(KERN_DEBUG, npe, "npe_reset: read FIFO = 0x%X\n", + __raw_readl(&npe->regs->in_out_fifo)); + + while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) + /* step execution of the NPE intruction to read inFIFO using + the Debug Executing Context stack */ + if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0)) + return -ETIMEDOUT; + + /* reset the mailbox reg from the XScale side */ + __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status); + /* from NPE side */ + if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0)) + return -ETIMEDOUT; + + /* Reset the physical registers in the NPE register file */ + for (val = 0; val < NPE_PHYS_REG; val++) { + if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0)) + return -ETIMEDOUT; + /* address is either 0 or 4 */ + if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0)) + return -ETIMEDOUT; + } + + /* Reset the context store = each context's Context Store registers */ + + /* Context 0 has no STARTPC. Instead, this value is used to set NextPC + for Background ECS, to set where NPE starts executing code */ + val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG); + val &= ~ECS_REG_0_NEXTPC_MASK; + val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK; + npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val); + + for (i = 0; i < 16; i++) { + if (i) { /* Context 0 has no STEVT nor STARTPC */ + /* STEVT = off, 0x80 */ + if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i)) + return -ETIMEDOUT; + if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i)) + return -ETIMEDOUT; + } + /* REGMAP = d0->p0, d8->p2, d16->p4 */ + if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i)) + return -ETIMEDOUT; + if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i)) + return -ETIMEDOUT; + } + + /* post exec */ + /* clear active bit in debug level */ + npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0); + /* clear the pipeline */ + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); + /* restore previous values */ + __raw_writel(exec_count, &npe->regs->exec_count); + npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2); + + /* write reset values to Execution Context Stack registers */ + for (val = 0; val < ARRAY_SIZE(ecs_reset); val++) + npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG, + ecs_reset[val].val); + + /* clear the profile counter */ + __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd); + + __raw_writel(0, &npe->regs->exec_count); + __raw_writel(0, &npe->regs->action_points[0]); + __raw_writel(0, &npe->regs->action_points[1]); + __raw_writel(0, &npe->regs->action_points[2]); + __raw_writel(0, &npe->regs->action_points[3]); + __raw_writel(0, &npe->regs->watch_count); + + val = ixp4xx_read_feature_bits(); + /* reset the NPE */ + ixp4xx_write_feature_bits(val & + ~(IXP4XX_FEATURE_RESET_NPEA << npe->id)); + for (i = 0; i < MAX_RETRIES; i++) { + if (!(ixp4xx_read_feature_bits() & + (IXP4XX_FEATURE_RESET_NPEA << npe->id))) + break; /* reset completed */ + udelay(1); + } + if (i == MAX_RETRIES) + return -ETIMEDOUT; + + /* deassert reset */ + ixp4xx_write_feature_bits(val | + (IXP4XX_FEATURE_RESET_NPEA << npe->id)); + for (i = 0; i < MAX_RETRIES; i++) { + if (ixp4xx_read_feature_bits() & + (IXP4XX_FEATURE_RESET_NPEA << npe->id)) + break; /* NPE is back alive */ + udelay(1); + } + if (i == MAX_RETRIES) + return -ETIMEDOUT; + + npe_stop(npe); + + /* restore NPE configuration bus Control Register - parity settings */ + __raw_writel(ctl, &npe->regs->messaging_control); + return 0; +} + + +int npe_send_message(struct npe *npe, const void *msg, const char *what) +{ + const u32 *send = msg; + int cycles = 0; + + debug_msg(npe, "Trying to send message %s [%08X:%08X]\n", + what, send[0], send[1]); + + if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) { + debug_msg(npe, "NPE input FIFO not empty\n"); + return -EIO; + } + + __raw_writel(send[0], &npe->regs->in_out_fifo); + + if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) { + debug_msg(npe, "NPE input FIFO full\n"); + return -EIO; + } + + __raw_writel(send[1], &npe->regs->in_out_fifo); + + while ((cycles < MAX_RETRIES) && + (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) { + udelay(1); + cycles++; + } + + if (cycles == MAX_RETRIES) { + debug_msg(npe, "Timeout sending message\n"); + return -ETIMEDOUT; + } + + debug_msg(npe, "Sending a message took %i cycles\n", cycles); + return 0; +} + +int npe_recv_message(struct npe *npe, void *msg, const char *what) +{ + u32 *recv = msg; + int cycles = 0, cnt = 0; + + debug_msg(npe, "Trying to receive message %s\n", what); + + while (cycles < MAX_RETRIES) { + if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) { + recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo); + if (cnt == 2) + break; + } else { + udelay(1); + cycles++; + } + } + + switch(cnt) { + case 1: + debug_msg(npe, "Received [%08X]\n", recv[0]); + break; + case 2: + debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]); + break; + } + + if (cycles == MAX_RETRIES) { + debug_msg(npe, "Timeout waiting for message\n"); + return -ETIMEDOUT; + } + + debug_msg(npe, "Receiving a message took %i cycles\n", cycles); + return 0; +} + +int npe_send_recv_message(struct npe *npe, void *msg, const char *what) +{ + int result; + u32 *send = msg, recv[2]; + + if ((result = npe_send_message(npe, msg, what)) != 0) + return result; + if ((result = npe_recv_message(npe, recv, what)) != 0) + return result; + + if ((recv[0] != send[0]) || (recv[1] != send[1])) { + debug_msg(npe, "Message %s: unexpected message received\n", + what); + return -EIO; + } + return 0; +} + + +int npe_load_firmware(struct npe *npe, const char *name, struct device *dev) +{ + const struct firmware *fw_entry; + + struct dl_block { + u32 type; + u32 offset; + } *blk; + + struct dl_image { + u32 magic; + u32 id; + u32 size; + union { + u32 data[0]; + struct dl_block blocks[0]; + }; + } *image; + + struct dl_codeblock { + u32 npe_addr; + u32 size; + u32 data[0]; + } *cb; + + int i, j, err, data_size, instr_size, blocks, table_end; + u32 cmd; + + if ((err = request_firmware(&fw_entry, name, dev)) != 0) + return err; + + err = -EINVAL; + if (fw_entry->size < sizeof(struct dl_image)) { + print_npe(KERN_ERR, npe, "incomplete firmware file\n"); + goto err; + } + image = (struct dl_image*)fw_entry->data; + +#if DEBUG_FW + print_npe(KERN_DEBUG, npe, "firmware: %08X %08X %08X (0x%X bytes)\n", + image->magic, image->id, image->size, image->size * 4); +#endif + + if (image->magic == swab32(FW_MAGIC)) { /* swapped file */ + image->id = swab32(image->id); + image->size = swab32(image->size); + } else if (image->magic != FW_MAGIC) { + print_npe(KERN_ERR, npe, "bad firmware file magic: 0x%X\n", + image->magic); + goto err; + } + if ((image->size * 4 + sizeof(struct dl_image)) != fw_entry->size) { + print_npe(KERN_ERR, npe, + "inconsistent size of firmware file\n"); + goto err; + } + if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) { + print_npe(KERN_ERR, npe, "firmware file NPE ID mismatch\n"); + goto err; + } + if (image->magic == swab32(FW_MAGIC)) + for (i = 0; i < image->size; i++) + image->data[i] = swab32(image->data[i]); + + if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) { + print_npe(KERN_INFO, npe, "IXP46x firmware ignored on " + "IXP42x\n"); + goto err; + } + + if (npe_running(npe)) { + print_npe(KERN_INFO, npe, "unable to load firmware, NPE is " + "already running\n"); + err = -EBUSY; + goto err; + } +#if 0 + npe_stop(npe); + npe_reset(npe); +#endif + + print_npe(KERN_INFO, npe, "firmware functionality 0x%X, " + "revision 0x%X:%X\n", (image->id >> 16) & 0xFF, + (image->id >> 8) & 0xFF, image->id & 0xFF); + + if (!cpu_is_ixp46x()) { + if (!npe->id) + instr_size = NPE_A_42X_INSTR_SIZE; + else + instr_size = NPE_B_AND_C_42X_INSTR_SIZE; + data_size = NPE_42X_DATA_SIZE; + } else { + instr_size = NPE_46X_INSTR_SIZE; + data_size = NPE_46X_DATA_SIZE; + } + + for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size; + blocks++) + if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF) + break; + if (blocks * sizeof(struct dl_block) / 4 >= image->size) { + print_npe(KERN_INFO, npe, "firmware EOF block marker not " + "found\n"); + goto err; + } + +#if DEBUG_FW + print_npe(KERN_DEBUG, npe, "%i firmware blocks found\n", blocks); +#endif + + table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */; + for (i = 0, blk = image->blocks; i < blocks; i++, blk++) { + if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4 + || blk->offset < table_end) { + print_npe(KERN_INFO, npe, "invalid offset 0x%X of " + "firmware block #%i\n", blk->offset, i); + goto err; + } + + cb = (struct dl_codeblock*)&image->data[blk->offset]; + if (blk->type == FW_BLOCK_TYPE_INSTR) { + if (cb->npe_addr + cb->size > instr_size) + goto too_big; + cmd = CMD_WR_INS_MEM; + } else if (blk->type == FW_BLOCK_TYPE_DATA) { + if (cb->npe_addr + cb->size > data_size) + goto too_big; + cmd = CMD_WR_DATA_MEM; + } else { + print_npe(KERN_INFO, npe, "invalid firmware block #%i " + "type 0x%X\n", i, blk->type); + goto err; + } + if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) { + print_npe(KERN_INFO, npe, "firmware block #%i doesn't " + "fit in firmware image: type %c, start 0x%X," + " length 0x%X\n", i, + blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D', + cb->npe_addr, cb->size); + goto err; + } + + for (j = 0; j < cb->size; j++) + npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]); + } + + npe_start(npe); + if (!npe_running(npe)) + print_npe(KERN_ERR, npe, "unable to start\n"); + release_firmware(fw_entry); + return 0; + +too_big: + print_npe(KERN_INFO, npe, "firmware block #%i doesn't fit in NPE " + "memory: type %c, start 0x%X, length 0x%X\n", i, + blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D', + cb->npe_addr, cb->size); +err: + release_firmware(fw_entry); + return err; +} + + +struct npe *npe_request(int id) +{ + if (id < NPE_COUNT) + if (npe_tab[id].valid) + if (try_module_get(THIS_MODULE)) + return &npe_tab[id]; + return NULL; +} + +void npe_release(struct npe *npe) +{ + module_put(THIS_MODULE); +} + + +static int __init npe_init_module(void) +{ + + int i, found = 0; + + for (i = 0; i < NPE_COUNT; i++) { + struct npe *npe = &npe_tab[i]; + if (!(ixp4xx_read_feature_bits() & + (IXP4XX_FEATURE_RESET_NPEA << i))) + continue; /* NPE already disabled or not present */ + if (!(npe->mem_res = request_mem_region(npe->regs_phys, + REGS_SIZE, + npe_name(npe)))) { + print_npe(KERN_ERR, npe, + "failed to request memory region\n"); + continue; + } + + if (npe_reset(npe)) + continue; + npe->valid = 1; + found++; + } + + if (!found) + return -ENOSYS; + return 0; +} + +static void __exit npe_cleanup_module(void) +{ + int i; + + for (i = 0; i < NPE_COUNT; i++) + if (npe_tab[i].mem_res) { + npe_reset(&npe_tab[i]); + release_resource(npe_tab[i].mem_res); + } +} + +module_init(npe_init_module); +module_exit(npe_cleanup_module); + +MODULE_AUTHOR("Krzysztof Halasa"); +MODULE_LICENSE("GPL v2"); + +EXPORT_SYMBOL(npe_names); +EXPORT_SYMBOL(npe_running); +EXPORT_SYMBOL(npe_request); +EXPORT_SYMBOL(npe_release); +EXPORT_SYMBOL(npe_load_firmware); +EXPORT_SYMBOL(npe_send_message); +EXPORT_SYMBOL(npe_recv_message); +EXPORT_SYMBOL(npe_send_recv_message); diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c new file mode 100644 index 00000000000..e8330132530 --- /dev/null +++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c @@ -0,0 +1,274 @@ +/* + * Intel IXP4xx Queue Manager driver for Linux + * + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + */ + +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/arch/qmgr.h> + +#define DEBUG 0 + +struct qmgr_regs __iomem *qmgr_regs; +static struct resource *mem_res; +static spinlock_t qmgr_lock; +static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ +static void (*irq_handlers[HALF_QUEUES])(void *pdev); +static void *irq_pdevs[HALF_QUEUES]; + +void qmgr_set_irq(unsigned int queue, int src, + void (*handler)(void *pdev), void *pdev) +{ + u32 __iomem *reg = &qmgr_regs->irqsrc[queue / 8]; /* 8 queues / u32 */ + int bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */ + unsigned long flags; + + src &= 7; + spin_lock_irqsave(&qmgr_lock, flags); + __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg); + irq_handlers[queue] = handler; + irq_pdevs[queue] = pdev; + spin_unlock_irqrestore(&qmgr_lock, flags); +} + + +static irqreturn_t qmgr_irq1(int irq, void *pdev) +{ + int i; + u32 val = __raw_readl(&qmgr_regs->irqstat[0]); + __raw_writel(val, &qmgr_regs->irqstat[0]); /* ACK */ + + for (i = 0; i < HALF_QUEUES; i++) + if (val & (1 << i)) + irq_handlers[i](irq_pdevs[i]); + + return val ? IRQ_HANDLED : 0; +} + + +void qmgr_enable_irq(unsigned int queue) +{ + unsigned long flags; + + spin_lock_irqsave(&qmgr_lock, flags); + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | (1 << queue), + &qmgr_regs->irqen[0]); + spin_unlock_irqrestore(&qmgr_lock, flags); +} + +void qmgr_disable_irq(unsigned int queue) +{ + unsigned long flags; + + spin_lock_irqsave(&qmgr_lock, flags); + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), + &qmgr_regs->irqen[0]); + spin_unlock_irqrestore(&qmgr_lock, flags); +} + +static inline void shift_mask(u32 *mask) +{ + mask[3] = mask[3] << 1 | mask[2] >> 31; + mask[2] = mask[2] << 1 | mask[1] >> 31; + mask[1] = mask[1] << 1 | mask[0] >> 31; + mask[0] <<= 1; +} + +int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, + unsigned int nearly_empty_watermark, + unsigned int nearly_full_watermark) +{ + u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ + int err; + + if (queue >= HALF_QUEUES) + return -ERANGE; + + if ((nearly_empty_watermark | nearly_full_watermark) & ~7) + return -EINVAL; + + switch (len) { + case 16: + cfg = 0 << 24; + mask[0] = 0x1; + break; + case 32: + cfg = 1 << 24; + mask[0] = 0x3; + break; + case 64: + cfg = 2 << 24; + mask[0] = 0xF; + break; + case 128: + cfg = 3 << 24; + mask[0] = 0xFF; + break; + default: + return -EINVAL; + } + + cfg |= nearly_empty_watermark << 26; + cfg |= nearly_full_watermark << 29; + len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */ + mask[1] = mask[2] = mask[3] = 0; + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + spin_lock_irq(&qmgr_lock); + if (__raw_readl(&qmgr_regs->sram[queue])) { + err = -EBUSY; + goto err; + } + + while (1) { + if (!(used_sram_bitmap[0] & mask[0]) && + !(used_sram_bitmap[1] & mask[1]) && + !(used_sram_bitmap[2] & mask[2]) && + !(used_sram_bitmap[3] & mask[3])) + break; /* found free space */ + + addr++; + shift_mask(mask); + if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) { + printk(KERN_ERR "qmgr: no free SRAM space for" + " queue %i\n", queue); + err = -ENOMEM; + goto err; + } + } + + used_sram_bitmap[0] |= mask[0]; + used_sram_bitmap[1] |= mask[1]; + used_sram_bitmap[2] |= mask[2]; + used_sram_bitmap[3] |= mask[3]; + __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); + spin_unlock_irq(&qmgr_lock); + +#if DEBUG + printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n", + queue, addr); +#endif + return 0; + +err: + spin_unlock_irq(&qmgr_lock); + module_put(THIS_MODULE); + return err; +} + +void qmgr_release_queue(unsigned int queue) +{ + u32 cfg, addr, mask[4]; + + BUG_ON(queue >= HALF_QUEUES); /* not in valid range */ + + spin_lock_irq(&qmgr_lock); + cfg = __raw_readl(&qmgr_regs->sram[queue]); + addr = (cfg >> 14) & 0xFF; + + BUG_ON(!addr); /* not requested */ + + switch ((cfg >> 24) & 3) { + case 0: mask[0] = 0x1; break; + case 1: mask[0] = 0x3; break; + case 2: mask[0] = 0xF; break; + case 3: mask[0] = 0xFF; break; + } + + while (addr--) + shift_mask(mask); + + __raw_writel(0, &qmgr_regs->sram[queue]); + + used_sram_bitmap[0] &= ~mask[0]; + used_sram_bitmap[1] &= ~mask[1]; + used_sram_bitmap[2] &= ~mask[2]; + used_sram_bitmap[3] &= ~mask[3]; + irq_handlers[queue] = NULL; /* catch IRQ bugs */ + spin_unlock_irq(&qmgr_lock); + + module_put(THIS_MODULE); +#if DEBUG + printk(KERN_DEBUG "qmgr: released queue %i\n", queue); +#endif +} + +static int qmgr_init(void) +{ + int i, err; + mem_res = request_mem_region(IXP4XX_QMGR_BASE_PHYS, + IXP4XX_QMGR_REGION_SIZE, + "IXP4xx Queue Manager"); + if (mem_res == NULL) + return -EBUSY; + + qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); + if (qmgr_regs == NULL) { + err = -ENOMEM; + goto error_map; + } + + /* reset qmgr registers */ + for (i = 0; i < 4; i++) { + __raw_writel(0x33333333, &qmgr_regs->stat1[i]); + __raw_writel(0, &qmgr_regs->irqsrc[i]); + } + for (i = 0; i < 2; i++) { + __raw_writel(0, &qmgr_regs->stat2[i]); + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */ + __raw_writel(0, &qmgr_regs->irqen[i]); + } + + for (i = 0; i < QUEUES; i++) + __raw_writel(0, &qmgr_regs->sram[i]); + + err = request_irq(IRQ_IXP4XX_QM1, qmgr_irq1, 0, + "IXP4xx Queue Manager", NULL); + if (err) { + printk(KERN_ERR "qmgr: failed to request IRQ%i\n", + IRQ_IXP4XX_QM1); + goto error_irq; + } + + used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ + spin_lock_init(&qmgr_lock); + + printk(KERN_INFO "IXP4xx Queue Manager initialized.\n"); + return 0; + +error_irq: + iounmap(qmgr_regs); +error_map: + release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); + return err; +} + +static void qmgr_remove(void) +{ + free_irq(IRQ_IXP4XX_QM1, NULL); + synchronize_irq(IRQ_IXP4XX_QM1); + iounmap(qmgr_regs); + release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE); +} + +module_init(qmgr_init); +module_exit(qmgr_remove); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Krzysztof Halasa"); + +EXPORT_SYMBOL(qmgr_regs); +EXPORT_SYMBOL(qmgr_set_irq); +EXPORT_SYMBOL(qmgr_enable_irq); +EXPORT_SYMBOL(qmgr_disable_irq); +EXPORT_SYMBOL(qmgr_request_queue); +EXPORT_SYMBOL(qmgr_release_queue); diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c deleted file mode 100644 index 29aa98d3a7f..00000000000 --- a/arch/arm/mach-ixp4xx/nas100d-power.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * arch/arm/mach-ixp4xx/nas100d-power.c - * - * NAS 100d Power/Reset driver - * - * Copyright (C) 2005 Tower Technologies - * - * based on nas100d-io.c - * Copyright (C) 2004 Karen Spearel - * - * Author: Alessandro Zummo <a.zummo@towertech.it> - * Maintainers: http://www.nslu2-linux.org/ - * - * 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/interrupt.h> -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/reboot.h> - -#include <asm/mach-types.h> - -static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) -{ - /* Signal init to do the ctrlaltdel action, this will bypass init if - * it hasn't started and do a kernel_restart. - */ - ctrl_alt_del(); - - return IRQ_HANDLED; -} - -static int __init nas100d_power_init(void) -{ - if (!(machine_is_nas100d())) - return 0; - - set_irq_type(NAS100D_RB_IRQ, IRQT_LOW); - - if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler, - IRQF_DISABLED, "NAS100D reset button", NULL) < 0) { - - printk(KERN_DEBUG "Reset Button IRQ %d not available\n", - NAS100D_RB_IRQ); - - return -EIO; - } - - return 0; -} - -static void __exit nas100d_power_exit(void) -{ - if (!(machine_is_nas100d())) - return; - - free_irq(NAS100D_RB_IRQ, NULL); -} - -module_init(nas100d_power_init); -module_exit(nas100d_power_exit); - -MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); -MODULE_DESCRIPTION("NAS100D Power/Reset driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 54d884fb251..4cecae84837 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -3,8 +3,14 @@ * * NAS 100d board-setup * - * based ixdp425-setup.c: + * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au> + * + * based on ixdp425-setup.c: * Copyright (C) 2003-2004 MontaVista Software, Inc. + * based on nas100d-power.c: + * Copyright (C) 2005 Tower Technologies + * based on nas100d-io.c + * Copyright (C) 2004 Karen Spearel * * Author: Alessandro Zummo <a.zummo@towertech.it> * Author: Rod Whitby <rod@whitby.id.au> @@ -12,15 +18,22 @@ * */ -#include <linux/kernel.h> +#include <linux/if_ether.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/timer.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/leds.h> +#include <linux/reboot.h> +#include <linux/i2c.h> #include <linux/i2c-gpio.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <asm/io.h> +#include <asm/gpio.h> static struct flash_platform_data nas100d_flash_data = { .map_name = "cfi_probe", @@ -39,35 +52,40 @@ static struct platform_device nas100d_flash = { .resource = &nas100d_flash_resource, }; -#ifdef CONFIG_LEDS_IXP4XX -static struct resource nas100d_led_resources[] = { +static struct i2c_board_info __initdata nas100d_i2c_board_info [] = { + { + I2C_BOARD_INFO("rtc-pcf8563", 0x51), + }, +}; + +static struct gpio_led nas100d_led_pins[] = { { .name = "wlan", /* green led */ - .start = 0, - .end = 0, - .flags = IXP4XX_GPIO_LOW, + .gpio = NAS100D_LED_WLAN_GPIO, + .active_low = true, }, { - .name = "ready", /* blue power led (off is flashing!) */ - .start = 15, - .end = 15, - .flags = IXP4XX_GPIO_LOW, + .name = "power", /* blue power led (off=flashing) */ + .gpio = NAS100D_LED_PWR_GPIO, + .active_low = true, }, { .name = "disk", /* yellow led */ - .start = 3, - .end = 3, - .flags = IXP4XX_GPIO_LOW, + .gpio = NAS100D_LED_DISK_GPIO, + .active_low = true, }, }; +static struct gpio_led_platform_data nas100d_led_data = { + .num_leds = ARRAY_SIZE(nas100d_led_pins), + .leds = nas100d_led_pins, +}; + static struct platform_device nas100d_leds = { - .name = "IXP4XX-GPIO-LED", + .name = "leds-gpio", .id = -1, - .num_resources = ARRAY_SIZE(nas100d_led_resources), - .resource = nas100d_led_resources, + .dev.platform_data = &nas100d_led_data, }; -#endif static struct i2c_gpio_platform_data nas100d_i2c_gpio_data = { .sda_pin = NAS100D_SDA_PIN, @@ -125,12 +143,28 @@ static struct platform_device nas100d_uart = { .resource = nas100d_uart_resources, }; +/* Built-in 10/100 Ethernet MAC interfaces */ +static struct eth_plat_info nas100d_plat_eth[] = { + { + .phy = 0, + .rxq = 3, + .txreadyq = 20, + } +}; + +static struct platform_device nas100d_eth[] = { + { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEB, + .dev.platform_data = nas100d_plat_eth, + } +}; + static struct platform_device *nas100d_devices[] __initdata = { &nas100d_i2c_gpio, &nas100d_flash, -#ifdef CONFIG_LEDS_IXP4XX &nas100d_leds, -#endif + &nas100d_eth[0], }; static void nas100d_power_off(void) @@ -144,8 +178,63 @@ static void nas100d_power_off(void) gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH); } +/* This is used to make sure the power-button pusher is serious. The button + * must be held until the value of this counter reaches zero. + */ +static int power_button_countdown; + +/* Must hold the button down for at least this many counts to be processed */ +#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */ + +static void nas100d_power_handler(unsigned long data); +static DEFINE_TIMER(nas100d_power_timer, nas100d_power_handler, 0, 0); + +static void nas100d_power_handler(unsigned long data) +{ + /* This routine is called twice per second to check the + * state of the power button. + */ + + if (gpio_get_value(NAS100D_PB_GPIO)) { + + /* IO Pin is 1 (button pushed) */ + if (power_button_countdown > 0) + power_button_countdown--; + + } else { + + /* Done on button release, to allow for auto-power-on mods. */ + if (power_button_countdown == 0) { + /* Signal init to do the ctrlaltdel action, + * this will bypass init if it hasn't started + * and do a kernel_restart. + */ + ctrl_alt_del(); + + /* Change the state of the power LED to "blink" */ + gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW); + } else { + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + } + } + + mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); +} + +static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) +{ + /* This is the paper-clip reset, it shuts the machine down directly. */ + machine_power_off(); + + return IRQ_HANDLED; +} + static void __init nas100d_init(void) { + DECLARE_MAC_BUF(mac_buf); + uint8_t __iomem *f; + int i; + ixp4xx_sys_init(); /* gpio 14 and 15 are _not_ clocks */ @@ -155,7 +244,8 @@ static void __init nas100d_init(void) nas100d_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; - pm_power_off = nas100d_power_off; + i2c_register_board_info(0, nas100d_i2c_board_info, + ARRAY_SIZE(nas100d_i2c_board_info)); /* * This is only useful on a modified machine, but it is valuable @@ -165,6 +255,48 @@ static void __init nas100d_init(void) (void)platform_device_register(&nas100d_uart); platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices)); + + pm_power_off = nas100d_power_off; + + if (request_irq(gpio_to_irq(NAS100D_RB_GPIO), &nas100d_reset_handler, + IRQF_DISABLED | IRQF_TRIGGER_LOW, + "NAS100D reset button", NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + gpio_to_irq(NAS100D_RB_GPIO)); + } + + /* The power button on the Iomega NAS100d is on GPIO 14, but + * it cannot handle interrupts on that GPIO line. So we'll + * have to poll it with a kernel timer. + */ + + /* Make sure that the power button GPIO is set up as an input */ + gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN); + + /* Set the initial value for the power button IRQ handler */ + power_button_countdown = PBUTTON_HOLDDOWN_COUNT; + + mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500)); + + /* + * Map in a portion of the flash and read the MAC address. + * Since it is stored in BE in the flash itself, we need to + * byteswap it if we're in LE mode. + */ + f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x1000000); + if (f) { + for (i = 0; i < 6; i++) +#ifdef __ARMEB__ + nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + i); +#else + nas100d_plat_eth[0].hwaddr[i] = readb(f + 0xFC0FD8 + (i^3)); +#endif + iounmap(f); + } + printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n", + print_mac(mac_buf, nas100d_plat_eth[0].hwaddr)); + } MACHINE_START(NAS100D, "Iomega NAS 100d") diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c deleted file mode 100644 index 6f10dc20832..00000000000 --- a/arch/arm/mach-ixp4xx/nslu2-power.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * arch/arm/mach-ixp4xx/nslu2-power.c - * - * NSLU2 Power/Reset driver - * - * Copyright (C) 2005 Tower Technologies - * - * based on nslu2-io.c - * Copyright (C) 2004 Karen Spearel - * - * Author: Alessandro Zummo <a.zummo@towertech.it> - * Maintainers: http://www.nslu2-linux.org/ - * - * 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/module.h> -#include <linux/reboot.h> -#include <linux/irq.h> -#include <linux/interrupt.h> - -#include <asm/mach-types.h> - -static irqreturn_t nslu2_power_handler(int irq, void *dev_id) -{ - /* Signal init to do the ctrlaltdel action, this will bypass init if - * it hasn't started and do a kernel_restart. - */ - ctrl_alt_del(); - - return IRQ_HANDLED; -} - -static irqreturn_t nslu2_reset_handler(int irq, void *dev_id) -{ - /* This is the paper-clip reset, it shuts the machine down directly. - */ - machine_power_off(); - - return IRQ_HANDLED; -} - -static int __init nslu2_power_init(void) -{ - if (!(machine_is_nslu2())) - return 0; - - *IXP4XX_GPIO_GPISR = 0x20400000; /* read the 2 irqs to clr */ - - set_irq_type(NSLU2_RB_IRQ, IRQT_LOW); - set_irq_type(NSLU2_PB_IRQ, IRQT_HIGH); - - if (request_irq(NSLU2_RB_IRQ, &nslu2_reset_handler, - IRQF_DISABLED, "NSLU2 reset button", NULL) < 0) { - - printk(KERN_DEBUG "Reset Button IRQ %d not available\n", - NSLU2_RB_IRQ); - - return -EIO; - } - - if (request_irq(NSLU2_PB_IRQ, &nslu2_power_handler, - IRQF_DISABLED, "NSLU2 power button", NULL) < 0) { - - printk(KERN_DEBUG "Power Button IRQ %d not available\n", - NSLU2_PB_IRQ); - - return -EIO; - } - - return 0; -} - -static void __exit nslu2_power_exit(void) -{ - if (!(machine_is_nslu2())) - return; - - free_irq(NSLU2_RB_IRQ, NULL); - free_irq(NSLU2_PB_IRQ, NULL); -} - -module_init(nslu2_power_init); -module_exit(nslu2_power_exit); - -MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); -MODULE_DESCRIPTION("NSLU2 Power/Reset driver"); -MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index 77277d27fcc..acaebcbce53 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -3,27 +3,35 @@ * * NSLU2 board-setup * - * based ixdp425-setup.c: + * Copyright (C) 2008 Rod Whitby <rod@whitby.id.au> + * + * based on ixdp425-setup.c: * Copyright (C) 2003-2004 MontaVista Software, Inc. + * based on nslu2-power.c: + * Copyright (C) 2005 Tower Technologies * * Author: Mark Rakes <mrakes at mac.com> * Author: Rod Whitby <rod@whitby.id.au> + * Author: Alessandro Zummo <a.zummo@towertech.it> * Maintainers: http://www.nslu2-linux.org/ * - * Fixed missing init_time in MACHINE_START kas11 10/22/04 - * Changed to conform to new style __init ixdp425 kas11 10/22/04 */ -#include <linux/kernel.h> +#include <linux/if_ether.h> +#include <linux/irq.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/leds.h> +#include <linux/reboot.h> +#include <linux/i2c.h> #include <linux/i2c-gpio.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> #include <asm/mach/time.h> +#include <asm/io.h> +#include <asm/gpio.h> static struct flash_platform_data nslu2_flash_data = { .map_name = "cfi_probe", @@ -47,41 +55,43 @@ static struct i2c_gpio_platform_data nslu2_i2c_gpio_data = { .scl_pin = NSLU2_SCL_PIN, }; -#ifdef CONFIG_LEDS_IXP4XX -static struct resource nslu2_led_resources[] = { +static struct i2c_board_info __initdata nslu2_i2c_board_info [] = { + { + I2C_BOARD_INFO("rtc-x1205", 0x6f), + }, +}; + +static struct gpio_led nslu2_led_pins[] = { { .name = "ready", /* green led */ - .start = NSLU2_LED_GRN_GPIO, - .end = NSLU2_LED_GRN_GPIO, - .flags = IXP4XX_GPIO_HIGH, + .gpio = NSLU2_LED_GRN_GPIO, }, { .name = "status", /* red led */ - .start = NSLU2_LED_RED_GPIO, - .end = NSLU2_LED_RED_GPIO, - .flags = IXP4XX_GPIO_HIGH, + .gpio = NSLU2_LED_RED_GPIO, }, { .name = "disk-1", - .start = NSLU2_LED_DISK1_GPIO, - .end = NSLU2_LED_DISK1_GPIO, - .flags = IXP4XX_GPIO_LOW, + .gpio = NSLU2_LED_DISK1_GPIO, + .active_low = true, }, { .name = "disk-2", - .start = NSLU2_LED_DISK2_GPIO, - .end = NSLU2_LED_DISK2_GPIO, - .flags = IXP4XX_GPIO_LOW, + .gpio = NSLU2_LED_DISK2_GPIO, + .active_low = true, }, }; +static struct gpio_led_platform_data nslu2_led_data = { + .num_leds = ARRAY_SIZE(nslu2_led_pins), + .leds = nslu2_led_pins, +}; + static struct platform_device nslu2_leds = { - .name = "IXP4XX-GPIO-LED", + .name = "leds-gpio", .id = -1, - .num_resources = ARRAY_SIZE(nslu2_led_resources), - .resource = nslu2_led_resources, + .dev.platform_data = &nslu2_led_data, }; -#endif static struct platform_device nslu2_i2c_gpio = { .name = "i2c-gpio", @@ -140,13 +150,29 @@ static struct platform_device nslu2_uart = { .resource = nslu2_uart_resources, }; +/* Built-in 10/100 Ethernet MAC interfaces */ +static struct eth_plat_info nslu2_plat_eth[] = { + { + .phy = 1, + .rxq = 3, + .txreadyq = 20, + } +}; + +static struct platform_device nslu2_eth[] = { + { + .name = "ixp4xx_eth", + .id = IXP4XX_ETH_NPEB, + .dev.platform_data = nslu2_plat_eth, + } +}; + static struct platform_device *nslu2_devices[] __initdata = { &nslu2_i2c_gpio, &nslu2_flash, &nslu2_beeper, -#ifdef CONFIG_LEDS_IXP4XX &nslu2_leds, -#endif + &nslu2_eth[0], }; static void nslu2_power_off(void) @@ -160,6 +186,25 @@ static void nslu2_power_off(void) gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH); } +static irqreturn_t nslu2_power_handler(int irq, void *dev_id) +{ + /* Signal init to do the ctrlaltdel action, this will bypass init if + * it hasn't started and do a kernel_restart. + */ + ctrl_alt_del(); + + return IRQ_HANDLED; +} + +static irqreturn_t nslu2_reset_handler(int irq, void *dev_id) +{ + /* This is the paper-clip reset, it shuts the machine down directly. + */ + machine_power_off(); + + return IRQ_HANDLED; +} + static void __init nslu2_timer_init(void) { /* The xtal on this machine is non-standard. */ @@ -175,13 +220,18 @@ static struct sys_timer nslu2_timer = { static void __init nslu2_init(void) { + DECLARE_MAC_BUF(mac_buf); + uint8_t __iomem *f; + int i; + ixp4xx_sys_init(); nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); nslu2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1; - pm_power_off = nslu2_power_off; + i2c_register_board_info(0, nslu2_i2c_board_info, + ARRAY_SIZE(nslu2_i2c_board_info)); /* * This is only useful on a modified machine, but it is valuable @@ -191,6 +241,43 @@ static void __init nslu2_init(void) (void)platform_device_register(&nslu2_uart); platform_add_devices(nslu2_devices, ARRAY_SIZE(nslu2_devices)); + + pm_power_off = nslu2_power_off; + + if (request_irq(gpio_to_irq(NSLU2_RB_GPIO), &nslu2_reset_handler, + IRQF_DISABLED | IRQF_TRIGGER_LOW, + "NSLU2 reset button", NULL) < 0) { + + printk(KERN_DEBUG "Reset Button IRQ %d not available\n", + gpio_to_irq(NSLU2_RB_GPIO)); + } + + if (request_irq(gpio_to_irq(NSLU2_PB_GPIO), &nslu2_power_handler, + IRQF_DISABLED | IRQF_TRIGGER_HIGH, + "NSLU2 power button", NULL) < 0) { + + printk(KERN_DEBUG "Power Button IRQ %d not available\n", + gpio_to_irq(NSLU2_PB_GPIO)); + } + + /* + * Map in a portion of the flash and read the MAC address. + * Since it is stored in BE in the flash itself, we need to + * byteswap it if we're in LE mode. + */ + f = ioremap(IXP4XX_EXP_BUS_BASE(0), 0x40000); + if (f) { + for (i = 0; i < 6; i++) +#ifdef __ARMEB__ + nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + i); +#else + nslu2_plat_eth[0].hwaddr[i] = readb(f + 0x3FFB0 + (i^3)); +#endif + iounmap(f); + } + printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n", + print_mac(mac_buf, nslu2_plat_eth[0].hwaddr)); + } MACHINE_START(NSLU2, "Linksys NSLU2") diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index b5c916c0747..6e0c4f5b5ae 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -3,10 +3,11 @@ # # Common support (must be linked before board specific support) -obj-y += clock.o devices.o generic.o irq.o dma.o time.o +obj-y += clock.o devices.o generic.o irq.o dma.o \ + time.o gpio.o obj-$(CONFIG_PXA25x) += pxa25x.o obj-$(CONFIG_PXA27x) += pxa27x.o -obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o +obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o obj-$(CONFIG_CPU_PXA300) += pxa300.o obj-$(CONFIG_CPU_PXA320) += pxa320.o diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c index 28cfd71c032..6012177a29a 100644 --- a/arch/arm/mach-pxa/cm-x270.c +++ b/arch/arm/mach-pxa/cm-x270.c @@ -29,6 +29,7 @@ #include <asm/mach/map.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/pxafb.h> #include <asm/arch/ohci.h> #include <asm/arch/mmc.h> diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index 50ff453ad37..bfccb80ac8e 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -10,6 +10,7 @@ #include <asm/arch/mmc.h> #include <asm/arch/irda.h> #include <asm/arch/i2c.h> +#include <asm/arch/ohci.h> #include "devices.h" diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 698aeec5296..80721c610d4 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -23,6 +23,7 @@ #include <linux/ioport.h> #include <linux/pm.h> #include <linux/string.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/irq.h> @@ -31,7 +32,6 @@ #include <asm/mach/map.h> #include <asm/arch/pxa-regs.h> -#include <asm/arch/gpio.h> #include "generic.h" @@ -66,97 +66,6 @@ unsigned int get_memclk_frequency_10khz(void) EXPORT_SYMBOL(get_memclk_frequency_10khz); /* - * Handy function to set GPIO alternate functions - */ -int pxa_last_gpio; - -int pxa_gpio_mode(int gpio_mode) -{ - unsigned long flags; - int gpio = gpio_mode & GPIO_MD_MASK_NR; - int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; - int gafr; - - if (gpio > pxa_last_gpio) - return -EINVAL; - - local_irq_save(flags); - if (gpio_mode & GPIO_DFLT_LOW) - GPCR(gpio) = GPIO_bit(gpio); - else if (gpio_mode & GPIO_DFLT_HIGH) - GPSR(gpio) = GPIO_bit(gpio); - if (gpio_mode & GPIO_MD_MASK_DIR) - GPDR(gpio) |= GPIO_bit(gpio); - else - GPDR(gpio) &= ~GPIO_bit(gpio); - gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); - GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); - local_irq_restore(flags); - - return 0; -} - -EXPORT_SYMBOL(pxa_gpio_mode); - -int gpio_direction_input(unsigned gpio) -{ - unsigned long flags; - u32 mask; - - if (gpio > pxa_last_gpio) - return -EINVAL; - - mask = GPIO_bit(gpio); - local_irq_save(flags); - GPDR(gpio) &= ~mask; - local_irq_restore(flags); - - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned gpio, int value) -{ - unsigned long flags; - u32 mask; - - if (gpio > pxa_last_gpio) - return -EINVAL; - - mask = GPIO_bit(gpio); - local_irq_save(flags); - if (value) - GPSR(gpio) = mask; - else - GPCR(gpio) = mask; - GPDR(gpio) |= mask; - local_irq_restore(flags); - - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); - -/* - * Return GPIO level - */ -int pxa_gpio_get_value(unsigned gpio) -{ - return __gpio_get_value(gpio); -} - -EXPORT_SYMBOL(pxa_gpio_get_value); - -/* - * Set output GPIO level - */ -void pxa_gpio_set_value(unsigned gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -EXPORT_SYMBOL(pxa_gpio_set_value); - -/* * Routine to safely enable or disable a clock in the CKEN */ void __pxa_set_cken(int clock, int enable) @@ -171,7 +80,6 @@ void __pxa_set_cken(int clock, int enable) local_irq_restore(flags); } - EXPORT_SYMBOL(__pxa_set_cken); /* @@ -226,3 +134,59 @@ void __init pxa_map_io(void) iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc)); get_clk_frequency_khz(1); } + +#ifdef CONFIG_PM + +static unsigned long saved_gplr[4]; +static unsigned long saved_gpdr[4]; +static unsigned long saved_grer[4]; +static unsigned long saved_gfer[4]; + +static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state) +{ + int i, gpio; + + for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) { + saved_gplr[i] = GPLR(gpio); + saved_gpdr[i] = GPDR(gpio); + saved_grer[i] = GRER(gpio); + saved_gfer[i] = GFER(gpio); + + /* Clear GPIO transition detect bits */ + GEDR(gpio) = GEDR(gpio); + } + return 0; +} + +static int pxa_gpio_resume(struct sys_device *dev) +{ + int i, gpio; + + for (gpio = 0, i = 0; gpio < pxa_last_gpio; gpio += 32, i++) { + /* restore level with set/clear */ + GPSR(gpio) = saved_gplr[i]; + GPCR(gpio) = ~saved_gplr[i]; + + GRER(gpio) = saved_grer[i]; + GFER(gpio) = saved_gfer[i]; + GPDR(gpio) = saved_gpdr[i]; + } + return 0; +} +#else +#define pxa_gpio_suspend NULL +#define pxa_gpio_resume NULL +#endif + +struct sysdev_class pxa_gpio_sysclass = { + .name = "gpio", + .suspend = pxa_gpio_suspend, + .resume = pxa_gpio_resume, +}; + +static int __init pxa_gpio_init(void) +{ + return sysdev_class_register(&pxa_gpio_sysclass); +} + +core_initcall(pxa_gpio_init); diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index b30f240a16c..b3d10b0e52a 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -16,6 +16,7 @@ extern void __init pxa_init_irq_low(void); extern void __init pxa_init_irq_high(void); extern void __init pxa_init_irq_gpio(int gpio_nr); extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)); +extern void __init pxa_init_gpio(int gpio_nr); extern void __init pxa25x_init_irq(void); extern void __init pxa27x_init_irq(void); extern void __init pxa3xx_init_irq(void); @@ -52,3 +53,6 @@ extern unsigned pxa3xx_get_memclk_frequency_10khz(void); #define pxa3xx_get_clk_frequency_khz(x) (0) #define pxa3xx_get_memclk_frequency_10khz() (0) #endif + +extern struct sysdev_class pxa_irq_sysclass; +extern struct sysdev_class pxa_gpio_sysclass; diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c new file mode 100644 index 00000000000..8638dd7dd07 --- /dev/null +++ b/arch/arm/mach-pxa/gpio.c @@ -0,0 +1,197 @@ +/* + * linux/arch/arm/mach-pxa/gpio.c + * + * Generic PXA GPIO handling + * + * Author: Nicolas Pitre + * Created: Jun 15, 2001 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> + +#include <asm/gpio.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/pxa-regs.h> + +#include "generic.h" + + +struct pxa_gpio_chip { + struct gpio_chip chip; + void __iomem *regbase; +}; + +int pxa_last_gpio; + +/* + * Configure pins for GPIO or other functions + */ +int pxa_gpio_mode(int gpio_mode) +{ + unsigned long flags; + int gpio = gpio_mode & GPIO_MD_MASK_NR; + int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; + int gafr; + + if (gpio > pxa_last_gpio) + return -EINVAL; + + local_irq_save(flags); + if (gpio_mode & GPIO_DFLT_LOW) + GPCR(gpio) = GPIO_bit(gpio); + else if (gpio_mode & GPIO_DFLT_HIGH) + GPSR(gpio) = GPIO_bit(gpio); + if (gpio_mode & GPIO_MD_MASK_DIR) + GPDR(gpio) |= GPIO_bit(gpio); + else + GPDR(gpio) &= ~GPIO_bit(gpio); + gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); + GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(pxa_gpio_mode); + +static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + unsigned long flags; + u32 mask = 1 << offset; + u32 value; + struct pxa_gpio_chip *pxa; + void __iomem *gpdr; + + pxa = container_of(chip, struct pxa_gpio_chip, chip); + gpdr = pxa->regbase + GPDR_OFFSET; + local_irq_save(flags); + value = __raw_readl(gpdr); + value &= ~mask; + __raw_writel(value, gpdr); + local_irq_restore(flags); + + return 0; +} + +static int pxa_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + unsigned long flags; + u32 mask = 1 << offset; + u32 tmp; + struct pxa_gpio_chip *pxa; + void __iomem *gpdr; + + pxa = container_of(chip, struct pxa_gpio_chip, chip); + __raw_writel(mask, + pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET)); + gpdr = pxa->regbase + GPDR_OFFSET; + local_irq_save(flags); + tmp = __raw_readl(gpdr); + tmp |= mask; + __raw_writel(tmp, gpdr); + local_irq_restore(flags); + + return 0; +} + +/* + * Return GPIO level + */ +static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + u32 mask = 1 << offset; + struct pxa_gpio_chip *pxa; + + pxa = container_of(chip, struct pxa_gpio_chip, chip); + return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask; +} + +/* + * Set output GPIO level + */ +static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + u32 mask = 1 << offset; + struct pxa_gpio_chip *pxa; + + pxa = container_of(chip, struct pxa_gpio_chip, chip); + + if (value) + __raw_writel(mask, pxa->regbase + GPSR_OFFSET); + else + __raw_writel(mask, pxa->regbase + GPCR_OFFSET); +} + +static struct pxa_gpio_chip pxa_gpio_chip[] = { + [0] = { + .regbase = GPIO0_BASE, + .chip = { + .label = "gpio-0", + .direction_input = pxa_gpio_direction_input, + .direction_output = pxa_gpio_direction_output, + .get = pxa_gpio_get, + .set = pxa_gpio_set, + .base = 0, + .ngpio = 32, + }, + }, + [1] = { + .regbase = GPIO1_BASE, + .chip = { + .label = "gpio-1", + .direction_input = pxa_gpio_direction_input, + .direction_output = pxa_gpio_direction_output, + .get = pxa_gpio_get, + .set = pxa_gpio_set, + .base = 32, + .ngpio = 32, + }, + }, + [2] = { + .regbase = GPIO2_BASE, + .chip = { + .label = "gpio-2", + .direction_input = pxa_gpio_direction_input, + .direction_output = pxa_gpio_direction_output, + .get = pxa_gpio_get, + .set = pxa_gpio_set, + .base = 64, + .ngpio = 32, /* 21 for PXA25x */ + }, + }, +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + [3] = { + .regbase = GPIO3_BASE, + .chip = { + .label = "gpio-3", + .direction_input = pxa_gpio_direction_input, + .direction_output = pxa_gpio_direction_output, + .get = pxa_gpio_get, + .set = pxa_gpio_set, + .base = 96, + .ngpio = 32, + }, + }, +#endif +}; + +void __init pxa_init_gpio(int gpio_nr) +{ + int i; + + /* add a GPIO chip for each register bank. + * the last PXA25x register only contains 21 GPIOs + */ + for (i = 0; i < gpio_nr; i += 32) { + if (i+32 > gpio_nr) + pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i; + gpiochip_add(&pxa_gpio_chip[i/32].chip); + } +} diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 07acb45b16e..36c6a68beca 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/irq.h> @@ -310,6 +311,8 @@ void __init pxa_init_irq_gpio(int gpio_nr) /* Install handler for GPIO>=2 edge detect interrupts */ set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); + + pxa_init_gpio(gpio_nr); } void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) @@ -321,3 +324,64 @@ void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) pxa_low_gpio_chip.set_wake = set_wake; pxa_muxed_gpio_chip.set_wake = set_wake; } + +#ifdef CONFIG_PM +static unsigned long saved_icmr[2]; + +static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) +{ + switch (dev->id) { + case 0: + saved_icmr[0] = ICMR; + ICMR = 0; + break; +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + case 1: + saved_icmr[1] = ICMR2; + ICMR2 = 0; + break; +#endif + default: + return -EINVAL; + } + + return 0; +} + +static int pxa_irq_resume(struct sys_device *dev) +{ + switch (dev->id) { + case 0: + ICMR = saved_icmr[0]; + ICLR = 0; + ICCR = 1; + break; +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) + case 1: + ICMR2 = saved_icmr[1]; + ICLR2 = 0; + break; +#endif + default: + return -EINVAL; + } + + return 0; +} +#else +#define pxa_irq_suspend NULL +#define pxa_irq_resume NULL +#endif + +struct sysdev_class pxa_irq_sysclass = { + .name = "irq", + .suspend = pxa_irq_suspend, + .resume = pxa_irq_resume, +}; + +static int __init pxa_irq_init(void) +{ + return sysdev_class_register(&pxa_irq_sysclass); +} + +core_initcall(pxa_irq_init); diff --git a/arch/arm/mach-pxa/mfp.c b/arch/arm/mach-pxa/mfp.c index ec1b2d8f61c..f5809adce29 100644 --- a/arch/arm/mach-pxa/mfp.c +++ b/arch/arm/mach-pxa/mfp.c @@ -22,6 +22,7 @@ #include <asm/hardware.h> #include <asm/arch/mfp.h> #include <asm/arch/mfp-pxa3xx.h> +#include <asm/arch/pxa3xx-regs.h> /* mfp_spin_lock is used to ensure that MFP register configuration * (most likely a read-modify-write operation) is atomic, and that @@ -223,11 +224,19 @@ static int pxa3xx_mfp_resume(struct sys_device *d) struct pxa3xx_mfp_pin *p = &mfp_table[pin]; __mfp_config_run(p); } + + /* clear RDH bit when MFP settings are restored + * + * NOTE: the last 3 bits DxS are write-1-to-clear so carefully + * preserve them here in case they will be referenced later + */ + ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); + return 0; } static struct sysdev_class mfp_sysclass = { - set_kset_name("mfp"), + .name = "mfp", .suspend = pxa3xx_mfp_suspend, .resume = pxa3xx_mfp_resume, }; diff --git a/arch/arm/mach-pxa/pcm027.c b/arch/arm/mach-pxa/pcm027.c index 540c3bba5f9..c14696b9979 100644 --- a/arch/arm/mach-pxa/pcm027.c +++ b/arch/arm/mach-pxa/pcm027.c @@ -29,6 +29,7 @@ #include <asm/mach/arch.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/pxa2xx_spi.h> #include <asm/arch/pcm027.h> #include "generic.h" diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index dd54496083c..209eabf0ed3 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -164,7 +164,7 @@ static struct resource poodlets_resources[] = { }, }; -static unsigned long poodle_get_hsync_len(void) +static unsigned long poodle_get_hsync_invperiod(void) { return 0; } @@ -174,9 +174,9 @@ static void poodle_null_hsync(void) } static struct corgits_machinfo poodle_ts_machinfo = { - .get_hsync_len = poodle_get_hsync_len, - .put_hsync = poodle_null_hsync, - .wait_hsync = poodle_null_hsync, + .get_hsync_invperiod = poodle_get_hsync_invperiod, + .put_hsync = poodle_null_hsync, + .wait_hsync = poodle_null_hsync, }; static struct platform_device poodle_ts_device = { diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index ddd05bf78e0..599e53fcc2c 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/suspend.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/arch/irqs.h> @@ -141,11 +142,6 @@ static struct clk pxa25x_clks[] = { #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] -#define RESTORE_GPLEVEL(n) do { \ - GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ - GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ -} while (0) - /* * List of global PXA peripheral registers to preserve. * More ones like CP and general purpose register values are preserved @@ -153,10 +149,6 @@ static struct clk pxa25x_clks[] = { */ enum { SLEEP_SAVE_START = 0, - SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, - SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, - SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, - SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, @@ -165,7 +157,6 @@ enum { SLEEP_SAVE_START = 0, SLEEP_SAVE_PSTR, - SLEEP_SAVE_ICMR, SLEEP_SAVE_CKEN, SLEEP_SAVE_SIZE @@ -174,17 +165,12 @@ enum { SLEEP_SAVE_START = 0, static void pxa25x_cpu_pm_save(unsigned long *sleep_save) { - SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); - SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); - SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); - SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(GAFR0_L); SAVE(GAFR0_U); SAVE(GAFR1_L); SAVE(GAFR1_U); SAVE(GAFR2_L); SAVE(GAFR2_U); - SAVE(ICMR); ICMR = 0; SAVE(CKEN); SAVE(PSTR); @@ -198,22 +184,14 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save) PSPR = 0; /* restore registers */ - RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2); - RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GAFR0_L); RESTORE(GAFR0_U); RESTORE(GAFR1_L); RESTORE(GAFR1_U); RESTORE(GAFR2_L); RESTORE(GAFR2_U); - RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); - RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); PSSR = PSSR_RDH | PSSR_PH; RESTORE(CKEN); - - ICLR = 0; - ICCR = 1; - RESTORE(ICMR); RESTORE(PSTR); } @@ -304,9 +282,17 @@ static struct platform_device *pxa25x_devices[] __initdata = { &pxa25x_device_assp, }; +static struct sys_device pxa25x_sysdev[] = { + { + .cls = &pxa_irq_sysclass, + }, { + .cls = &pxa_gpio_sysclass, + }, +}; + static int __init pxa25x_init(void) { - int ret = 0; + int i, ret = 0; /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ if (cpu_is_pxa25x()) @@ -320,9 +306,18 @@ static int __init pxa25x_init(void) pxa25x_init_pm(); + for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) { + ret = sysdev_register(&pxa25x_sysdev[i]); + if (ret) + pr_err("failed to register sysdev[%d]\n", i); + } + ret = platform_add_devices(pxa25x_devices, ARRAY_SIZE(pxa25x_devices)); + if (ret) + return ret; } + /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */ if (cpu_is_pxa25x()) ret = platform_device_register(&pxa_device_hwuart); diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 96cf274ec7c..46a951c3e5a 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/suspend.h> #include <linux/platform_device.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/irq.h> @@ -171,11 +172,6 @@ static struct clk pxa27x_clks[] = { #define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x #define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] -#define RESTORE_GPLEVEL(n) do { \ - GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \ - GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \ -} while (0) - /* * List of global PXA peripheral registers to preserve. * More ones like CP and general purpose register values are preserved @@ -183,10 +179,6 @@ static struct clk pxa27x_clks[] = { */ enum { SLEEP_SAVE_START = 0, - SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3, - SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3, - SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3, - SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3, SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3, SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U, @@ -196,7 +188,6 @@ enum { SLEEP_SAVE_START = 0, SLEEP_SAVE_PSTR, - SLEEP_SAVE_ICMR, SLEEP_SAVE_CKEN, SLEEP_SAVE_MDREFR, @@ -208,10 +199,6 @@ enum { SLEEP_SAVE_START = 0, void pxa27x_cpu_pm_save(unsigned long *sleep_save) { - SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3); - SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3); - SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3); - SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3); SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3); SAVE(GAFR0_L); SAVE(GAFR0_U); @@ -223,12 +210,8 @@ void pxa27x_cpu_pm_save(unsigned long *sleep_save) SAVE(PWER); SAVE(PCFR); SAVE(PRER); SAVE(PFER); SAVE(PKWR); - SAVE(ICMR); ICMR = 0; SAVE(CKEN); SAVE(PSTR); - - /* Clear GPIO transition detect bits */ - GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3; } void pxa27x_cpu_pm_restore(unsigned long *sleep_save) @@ -237,15 +220,10 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save) PSPR = 0; /* restore registers */ - RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); - RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3); - RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3); RESTORE(GAFR0_L); RESTORE(GAFR0_U); RESTORE(GAFR1_L); RESTORE(GAFR1_U); RESTORE(GAFR2_L); RESTORE(GAFR2_U); RESTORE(GAFR3_L); RESTORE(GAFR3_U); - RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3); - RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3); RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3); RESTORE(MDREFR); @@ -256,9 +234,6 @@ void pxa27x_cpu_pm_restore(unsigned long *sleep_save) RESTORE(CKEN); - ICLR = 0; - ICCR = 1; - RESTORE(ICMR); RESTORE(PSTR); } @@ -409,9 +384,22 @@ static struct platform_device *devices[] __initdata = { &pxa27x_device_ssp3, }; +static struct sys_device pxa27x_sysdev[] = { + { + .id = 0, + .cls = &pxa_irq_sysclass, + }, { + .id = 1, + .cls = &pxa_irq_sysclass, + }, { + .cls = &pxa_gpio_sysclass, + }, +}; + static int __init pxa27x_init(void) { - int ret = 0; + int i, ret = 0; + if (cpu_is_pxa27x()) { clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks)); @@ -420,8 +408,15 @@ static int __init pxa27x_init(void) pxa27x_init_pm(); + for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) { + ret = sysdev_register(&pxa27x_sysdev[i]); + if (ret) + pr_err("failed to register sysdev[%d]\n", i); + } + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } + return ret; } diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 5cbf057a1b3..e47e67c11af 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -20,6 +20,7 @@ #include <linux/platform_device.h> #include <linux/irq.h> #include <linux/io.h> +#include <linux/sysdev.h> #include <asm/hardware.h> #include <asm/arch/pxa3xx-regs.h> @@ -39,6 +40,7 @@ #define RO_CLK 60000000 #define ACCR_D0CS (1 << 26) +#define ACCR_PCCE (1 << 11) /* crystal frequency to static memory controller multiplier (SMCFS) */ static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, }; @@ -203,7 +205,6 @@ static struct clk pxa3xx_clks[] = { }; #ifdef CONFIG_PM -#define SLEEP_SAVE_SIZE 4 #define ISRAM_START 0x5c000000 #define ISRAM_SIZE SZ_256K @@ -211,25 +212,29 @@ static struct clk pxa3xx_clks[] = { static void __iomem *sram; static unsigned long wakeup_src; -static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) -{ - pr_debug("PM: CKENA=%08x CKENB=%08x\n", CKENA, CKENB); +#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] - if (CKENA & (1 << CKEN_USBH)) { - printk(KERN_ERR "PM: USB host clock not stopped?\n"); - CKENA &= ~(1 << CKEN_USBH); - } -// CKENA |= 1 << (CKEN_ISC & 31); +enum { SLEEP_SAVE_START = 0, + SLEEP_SAVE_CKENA, + SLEEP_SAVE_CKENB, + SLEEP_SAVE_ACCR, - /* - * Low power modes require the HSIO2 clock to be enabled. - */ - CKENB |= 1 << (CKEN_HSIO2 & 31); + SLEEP_SAVE_SIZE, +}; + +static void pxa3xx_cpu_pm_save(unsigned long *sleep_save) +{ + SAVE(CKENA); + SAVE(CKENB); + SAVE(ACCR); } static void pxa3xx_cpu_pm_restore(unsigned long *sleep_save) { - CKENB &= ~(1 << (CKEN_HSIO2 & 31)); + RESTORE(ACCR); + RESTORE(CKENA); + RESTORE(CKENB); } /* @@ -265,6 +270,46 @@ static void pxa3xx_cpu_standby(unsigned int pwrmode) printk("PM: AD2D0SR=%08x ASCR=%08x\n", AD2D0SR, ASCR); } +/* + * NOTE: currently, the OBM (OEM Boot Module) binary comes along with + * PXA3xx development kits assumes that the resuming process continues + * with the address stored within the first 4 bytes of SDRAM. The PSPR + * register is used privately by BootROM and OBM, and _must_ be set to + * 0x5c014000 for the moment. + */ +static void pxa3xx_cpu_pm_suspend(void) +{ + volatile unsigned long *p = (volatile void *)0xc0000000; + unsigned long saved_data = *p; + + extern void pxa3xx_cpu_suspend(void); + extern void pxa3xx_cpu_resume(void); + + /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */ + CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM); + CKENB |= 1 << (CKEN_HSIO2 & 0x1f); + + /* clear and setup wakeup source */ + AD3SR = ~0; + AD3ER = wakeup_src; + ASCR = ASCR; + ARSR = ARSR; + + PCFR |= (1u << 13); /* L1_DIS */ + PCFR &= ~((1u << 12) | (1u << 1)); /* L0_EN | SL_ROD */ + + PSPR = 0x5c014000; + + /* overwrite with the resume address */ + *p = virt_to_phys(pxa3xx_cpu_resume); + + pxa3xx_cpu_suspend(); + + *p = saved_data; + + AD3ER = 0; +} + static void pxa3xx_cpu_pm_enter(suspend_state_t state) { /* @@ -279,6 +324,7 @@ static void pxa3xx_cpu_pm_enter(suspend_state_t state) break; case PM_SUSPEND_MEM: + pxa3xx_cpu_pm_suspend(); break; } } @@ -452,9 +498,21 @@ static struct platform_device *devices[] __initdata = { &pxa3xx_device_ssp4, }; +static struct sys_device pxa3xx_sysdev[] = { + { + .id = 0, + .cls = &pxa_irq_sysclass, + }, { + .id = 1, + .cls = &pxa_irq_sysclass, + }, { + .cls = &pxa_gpio_sysclass, + }, +}; + static int __init pxa3xx_init(void) { - int ret = 0; + int i, ret = 0; if (cpu_is_pxa3xx()) { clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks)); @@ -464,9 +522,16 @@ static int __init pxa3xx_init(void) pxa3xx_init_pm(); - return platform_add_devices(devices, ARRAY_SIZE(devices)); + for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) { + ret = sysdev_register(&pxa3xx_sysdev[i]); + if (ret) + pr_err("failed to register sysdev[%d]\n", i); + } + + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } - return 0; + + return ret; } subsys_initcall(pxa3xx_init); diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S index 14bb4a93ea5..784716eb7fc 100644 --- a/arch/arm/mach-pxa/sleep.S +++ b/arch/arm/mach-pxa/sleep.S @@ -50,6 +50,108 @@ pxa_cpu_save_sp: str r0, [r1] ldr pc, [sp], #4 +#ifdef CONFIG_PXA3xx +/* + * pxa3xx_cpu_suspend() - forces CPU into sleep state (S2D3C4) + * + * NOTE: unfortunately, pxa_cpu_save_cp can not be reused here since + * the auxiliary control register address is different between pxa3xx + * and pxa{25x,27x} + */ + +ENTRY(pxa3xx_cpu_suspend) + +#ifndef CONFIG_IWMMXT + mra r2, r3, acc0 +#endif + stmfd sp!, {r2 - r12, lr} @ save registers on stack + + mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode + mrc p15, 0, r4, c15, c1, 0 @ CP access reg + mrc p15, 0, r5, c13, c0, 0 @ PID + mrc p15, 0, r6, c3, c0, 0 @ domain ID + mrc p15, 0, r7, c2, c0, 0 @ translation table base addr + mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg + mrc p15, 0, r9, c1, c0, 0 @ control reg + + bic r3, r3, #2 @ clear frequency change bit + + @ store them plus current virtual stack ptr on stack + mov r10, sp + stmfd sp!, {r3 - r10} + + @ store physical address of stack pointer + mov r0, sp + bl sleep_phys_sp + ldr r1, =sleep_save_sp + str r0, [r1] + + @ clean data cache + bl xsc3_flush_kern_cache_all + + mov r0, #0x06 @ S2D3C4 mode + mcr p14, 0, r0, c7, c0, 0 @ enter sleep + +20: b 20b @ waiting for sleep + + .data + .align 5 +/* + * pxa3xx_cpu_resume + */ + +ENTRY(pxa3xx_cpu_resume) + + mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off + msr cpsr_c, r0 + + ldr r0, sleep_save_sp @ stack phys addr + ldmfd r0, {r3 - r9, sp} @ CP regs + virt stack ptr + + mov r1, #0 + mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB + mcr p15, 0, r1, c7, c10, 4 @ drain write (&fill) buffer + mcr p15, 0, r1, c7, c5, 4 @ flush prefetch buffer + mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs + + mcr p14, 0, r3, c6, c0, 0 @ clock configuration, turbo mode. + mcr p15, 0, r4, c15, c1, 0 @ CP access reg + mcr p15, 0, r5, c13, c0, 0 @ PID + mcr p15, 0, r6, c3, c0, 0 @ domain ID + mcr p15, 0, r7, c2, c0, 0 @ translation table base addr + mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg + + @ temporarily map resume_turn_on_mmu into the page table, + @ otherwise prefetch abort occurs after MMU is turned on + mov r1, r7 + bic r1, r1, #0x00ff + bic r1, r1, #0x3f00 + ldr r2, =0x542e + + adr r3, resume_turn_on_mmu + mov r3, r3, lsr #20 + orr r4, r2, r3, lsl #20 + ldr r5, [r1, r3, lsl #2] + str r4, [r1, r3, lsl #2] + + @ Mapping page table address in the page table + mov r6, r1, lsr #20 + orr r7, r2, r6, lsl #20 + ldr r8, [r1, r6, lsl #2] + str r7, [r1, r6, lsl #2] + + ldr r2, =pxa3xx_resume_after_mmu @ absolute virtual address + b resume_turn_on_mmu @ cache align execution + + .text +pxa3xx_resume_after_mmu: + /* restore the temporary mapping */ + str r5, [r1, r3, lsl #2] + str r8, [r1, r6, lsl #2] + b resume_after_mmu + +#endif /* CONFIG_PXA3xx */ + #ifdef CONFIG_PXA27x /* * pxa27x_cpu_suspend() diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c new file mode 100644 index 00000000000..ad346addc02 --- /dev/null +++ b/arch/arm/mach-pxa/smemc.c @@ -0,0 +1,88 @@ +/* + * Static Memory Controller + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/sysdev.h> + +#define SMEMC_PHYS_BASE (0x4A000000) +#define SMEMC_PHYS_SIZE (0x90) + +#define MSC0 (0x08) /* Static Memory Controller Register 0 */ +#define MSC1 (0x0C) /* Static Memory Controller Register 1 */ +#define SXCNFG (0x1C) /* Synchronous Static Memory Control Register */ +#define MEMCLKCFG (0x68) /* Clock Configuration */ +#define CSADRCFG0 (0x80) /* Address Configuration Register for CS0 */ +#define CSADRCFG1 (0x84) /* Address Configuration Register for CS1 */ +#define CSADRCFG2 (0x88) /* Address Configuration Register for CS2 */ +#define CSADRCFG3 (0x8C) /* Address Configuration Register for CS3 */ + +#ifdef CONFIG_PM +static void __iomem *smemc_mmio_base; + +static unsigned long msc[2]; +static unsigned long sxcnfg, memclkcfg; +static unsigned long csadrcfg[4]; + +static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state) +{ + msc[0] = __raw_readl(smemc_mmio_base + MSC0); + msc[1] = __raw_readl(smemc_mmio_base + MSC1); + sxcnfg = __raw_readl(smemc_mmio_base + SXCNFG); + memclkcfg = __raw_readl(smemc_mmio_base + MEMCLKCFG); + csadrcfg[0] = __raw_readl(smemc_mmio_base + CSADRCFG0); + csadrcfg[1] = __raw_readl(smemc_mmio_base + CSADRCFG1); + csadrcfg[2] = __raw_readl(smemc_mmio_base + CSADRCFG2); + csadrcfg[3] = __raw_readl(smemc_mmio_base + CSADRCFG3); + + return 0; +} + +static int pxa3xx_smemc_resume(struct sys_device *dev) +{ + __raw_writel(msc[0], smemc_mmio_base + MSC0); + __raw_writel(msc[1], smemc_mmio_base + MSC1); + __raw_writel(sxcnfg, smemc_mmio_base + SXCNFG); + __raw_writel(memclkcfg, smemc_mmio_base + MEMCLKCFG); + __raw_writel(csadrcfg[0], smemc_mmio_base + CSADRCFG0); + __raw_writel(csadrcfg[1], smemc_mmio_base + CSADRCFG1); + __raw_writel(csadrcfg[2], smemc_mmio_base + CSADRCFG2); + __raw_writel(csadrcfg[3], smemc_mmio_base + CSADRCFG3); + + return 0; +} + +static struct sysdev_class smemc_sysclass = { + .name = "smemc", + .suspend = pxa3xx_smemc_suspend, + .resume = pxa3xx_smemc_resume, +}; + +static struct sys_device smemc_sysdev = { + .id = 0, + .cls = &smemc_sysclass, +}; + +static int __init smemc_init(void) +{ + int ret = 0; + + if (cpu_is_pxa3xx()) { + smemc_mmio_base = ioremap(SMEMC_PHYS_BASE, SMEMC_PHYS_SIZE); + if (smemc_mmio_base == NULL) + return -ENODEV; + + ret = sysdev_class_register(&smemc_sysclass); + if (ret) + return ret; + + ret = sysdev_register(&smemc_sysdev); + } + + return ret; +} +subsys_initcall(smemc_init); +#endif diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 5078edeadf9..9e7773fca01 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -36,6 +36,7 @@ #include <asm/mach/irq.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/irda.h> #include <asm/arch/mmc.h> #include <asm/arch/ohci.h> diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 1a9c844ac7e..9b26fa5edad 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -29,6 +29,7 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <asm/arch/irda.h> #include <asm/arch/mmc.h> #include <asm/arch/udc.h> diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index 35156ca39df..39b3bb7f102 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -7,24 +7,21 @@ config MACH_REALVIEW_EB help Include support for the ARM(R) RealView Emulation Baseboard platform. -config REALVIEW_MPCORE - bool "Support MPcore tile" +config REALVIEW_EB_ARM11MP + bool "Support ARM11MPCore tile" depends on MACH_REALVIEW_EB select CACHE_L2X0 help - Enable support for the MPCore tile on the Realview platform. - Since there are device address and interrupt differences, a - kernel built with this option enabled is not compatible with - other tiles. + Enable support for the ARM11MPCore tile on the Realview platform. -config REALVIEW_MPCORE_REVB - bool "Support MPcore RevB tile" - depends on REALVIEW_MPCORE +config REALVIEW_EB_ARM11MP_REVB + bool "Support ARM11MPCore RevB tile" + depends on REALVIEW_EB_ARM11MP default n help - Enable support for the MPCore RevB tile on the Realview platform. - Since there are device address differences, a + Enable support for the ARM11MPCore RevB tile on the Realview + platform. Since there are device address differences, a kernel built with this option enabled is not compatible with - other tiles. + other revisions of the ARM11MPCore tile. endmenu diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index 36e76ba937f..ca1e390c3c2 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -4,6 +4,5 @@ obj-y := core.o clock.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o -obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 61d70218f1e..98aefc9f4df 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -25,6 +25,8 @@ #include <linux/interrupt.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/system.h> #include <asm/hardware.h> @@ -37,7 +39,6 @@ #include <asm/mach/arch.h> #include <asm/mach/flash.h> #include <asm/mach/irq.h> -#include <asm/mach/time.h> #include <asm/mach/map.h> #include <asm/mach/mmc.h> @@ -48,6 +49,9 @@ #define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) +/* used by entry-macro.S */ +void __iomem *gic_cpu_base_addr; + /* * This is the RealView sched_clock implementation. This has * a resolution of 41.7ns, and a maximum value of about 179s. @@ -121,26 +125,6 @@ struct platform_device realview_flash_device = { .resource = &realview_flash_resource, }; -static struct resource realview_smc91x_resources[] = { - [0] = { - .start = REALVIEW_ETH_BASE, - .end = REALVIEW_ETH_BASE + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_ETH, - .end = IRQ_ETH, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device realview_smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(realview_smc91x_resources), - .resource = realview_smc91x_resources, -}; - static struct resource realview_i2c_resource = { .start = REALVIEW_I2C_BASE, .end = REALVIEW_I2C_BASE + SZ_4K - 1, @@ -484,45 +468,64 @@ void realview_leds_event(led_event_t ledevt) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #endif -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -static unsigned long realview_gettimeoffset(void) +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) { - unsigned long ticks1, ticks2, status; + unsigned long ctrl; - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) - + ((IRQ_TIMERINT0_1 >> 5) << 2)); - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - /* - * Number of ticks since last interrupt. - */ - ticks1 = TIMER_RELOAD - ticks2; + ctrl = TIMER_CTRL_PERIODIC; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TIMER_CTRL_ONESHOT; + ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } - /* - * Interrupt pending? If so, we've reloaded once already. - * - * FIXME: Need to check this is effectively timer 0 that expires - */ - if (status & IRQMASK_TIMERINT0_1) - ticks1 += TIMER_RELOAD; + writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); +} - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); +static int timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL); + + writel(evt, TIMER0_VA_BASE + TIMER_LOAD); + writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL); + + return 0; +} + +static struct clock_event_device timer0_clockevent = { + .name = "timer0", + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_mode = timer_set_mode, + .set_next_event = timer_set_next_event, + .rating = 300, + .cpumask = CPU_MASK_ALL, +}; + +static void __init realview_clockevents_init(unsigned int timer_irq) +{ + timer0_clockevent.irq = timer_irq; + timer0_clockevent.mult = + div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); + timer0_clockevent.max_delta_ns = + clockevent_delta2ns(0xffffffff, &timer0_clockevent); + timer0_clockevent.min_delta_ns = + clockevent_delta2ns(0xf, &timer0_clockevent); + + clockevents_register_device(&timer0_clockevent); } /* @@ -530,15 +533,12 @@ static unsigned long realview_gettimeoffset(void) */ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) { - // ...clear the interrupt + struct clock_event_device *evt = &timer0_clockevent; + + /* clear the interrupt */ writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - timer_tick(); - -#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) - smp_send_timer(); - update_process_times(user_mode(get_irq_regs())); -#endif + evt->event_handler(evt); return IRQ_HANDLED; } @@ -549,13 +549,49 @@ static struct irqaction realview_timer_irq = { .handler = realview_timer_interrupt, }; +static cycle_t realview_get_cycles(void) +{ + return ~readl(TIMER3_VA_BASE + TIMER_VALUE); +} + +static struct clocksource clocksource_realview = { + .name = "timer3", + .rating = 200, + .read = realview_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init realview_clocksource_init(void) +{ + /* setup timer 0 as free-running clocksource */ + writel(0, TIMER3_VA_BASE + TIMER_CTRL); + writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD); + writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE); + writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, + TIMER3_VA_BASE + TIMER_CTRL); + + clocksource_realview.mult = + clocksource_khz2mult(1000, clocksource_realview.shift); + clocksource_register(&clocksource_realview); +} + /* - * Set up timer interrupt, and return the current time in seconds. + * Set up the clock source and clock events devices */ -static void __init realview_timer_init(void) +void __init realview_timer_init(unsigned int timer_irq) { u32 val; +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + /* + * The dummy clock device has to be registered before the main device + * so that the latter will broadcast the clock events + */ + local_timer_setup(smp_processor_id()); +#endif + /* * set clock frequency: * REALVIEW_REFCLK is 32KHz @@ -576,18 +612,11 @@ static void __init realview_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); writel(0, TIMER3_VA_BASE + TIMER_CTRL); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); - writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | - TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); - /* * Make irqs happen for the system timer */ - setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); -} + setup_irq(timer_irq, &realview_timer_irq); -struct sys_timer realview_timer = { - .init = realview_timer_init, - .offset = realview_gettimeoffset, -}; + realview_clocksource_init(); + realview_clockevents_init(timer_irq); +} diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index 2b53420f9c1..492a14c0d60 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -27,8 +27,6 @@ #include <asm/leds.h> #include <asm/io.h> -extern struct sys_timer realview_timer; - #define AMBA_DEVICE(name,busid,base,plat) \ static struct amba_device name##_device = { \ .dev = { \ @@ -38,7 +36,7 @@ static struct amba_device name##_device = { \ }, \ .res = { \ .start = REALVIEW_##base##_BASE, \ - .end = (REALVIEW_##base##_BASE) + SZ_4K - 1,\ + .end = (REALVIEW_##base##_BASE) + SZ_4K - 1, \ .flags = IORESOURCE_MEM, \ }, \ .dma_mask = ~0, \ @@ -46,74 +44,19 @@ static struct amba_device name##_device = { \ /* .dma = base##_DMA,*/ \ } -/* - * These devices are connected via the core APB bridge - */ -#define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } -#define GPIO2_DMA { 0, 0 } -#define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } -#define GPIO3_DMA { 0, 0 } - -#define AACI_IRQ { IRQ_AACI, NO_IRQ } -#define AACI_DMA { 0x80, 0x81 } -#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_MMCI0B } -#define MMCI0_DMA { 0x84, 0 } -#define KMI0_IRQ { IRQ_KMI0, NO_IRQ } -#define KMI0_DMA { 0, 0 } -#define KMI1_IRQ { IRQ_KMI1, NO_IRQ } -#define KMI1_DMA { 0, 0 } - -/* - * These devices are connected directly to the multi-layer AHB switch - */ -#define SMC_IRQ { NO_IRQ, NO_IRQ } -#define SMC_DMA { 0, 0 } -#define MPMC_IRQ { NO_IRQ, NO_IRQ } -#define MPMC_DMA { 0, 0 } -#define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } -#define CLCD_DMA { 0, 0 } -#define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } -#define DMAC_DMA { 0, 0 } - -/* - * These devices are connected via the core APB bridge - */ -#define SCTL_IRQ { NO_IRQ, NO_IRQ } -#define SCTL_DMA { 0, 0 } -#define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } -#define WATCHDOG_DMA { 0, 0 } -#define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } -#define GPIO0_DMA { 0, 0 } -#define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } -#define GPIO1_DMA { 0, 0 } -#define RTC_IRQ { IRQ_RTCINT, NO_IRQ } -#define RTC_DMA { 0, 0 } - -/* - * These devices are connected via the DMA APB bridge - */ -#define SCI_IRQ { IRQ_SCIINT, NO_IRQ } -#define SCI_DMA { 7, 6 } -#define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } -#define UART0_DMA { 15, 14 } -#define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } -#define UART1_DMA { 13, 12 } -#define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } -#define UART2_DMA { 11, 10 } -#define UART3_IRQ { IRQ_UART3, NO_IRQ } -#define UART3_DMA { 0x86, 0x87 } -#define SSP_IRQ { IRQ_SSPINT, NO_IRQ } -#define SSP_DMA { 9, 8 } - - extern struct platform_device realview_flash_device; -extern struct platform_device realview_smc91x_device; extern struct platform_device realview_i2c_device; extern struct mmc_platform_data realview_mmc0_plat_data; extern struct mmc_platform_data realview_mmc1_plat_data; extern struct clk realview_clcd_clk; extern struct clcd_board clcd_plat_data; +extern void __iomem *gic_cpu_base_addr; +#ifdef CONFIG_LOCAL_TIMERS +extern void __iomem *twd_base_addr; +extern unsigned int twd_size; +#endif extern void realview_leds_event(led_event_t ledevt); +extern void realview_timer_init(unsigned int timer_irq); #endif diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c index c7bdf04ab09..50604360479 100644 --- a/arch/arm/mach-realview/localtimer.c +++ b/arch/arm/mach-realview/localtimer.c @@ -14,19 +14,75 @@ #include <linux/device.h> #include <linux/smp.h> #include <linux/jiffies.h> +#include <linux/percpu.h> +#include <linux/clockchips.h> +#include <linux/irq.h> -#include <asm/mach/time.h> #include <asm/hardware/arm_twd.h> #include <asm/hardware/gic.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> -#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ - ((cpu) * REALVIEW_TWD_SIZE)) +static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); + +/* + * Used on SMP for either the local timer or IPI_TIMER + */ +void local_timer_interrupt(void) +{ + struct clock_event_device *clk = &__get_cpu_var(local_clockevent); + + clk->event_handler(clk); +} + +#ifdef CONFIG_LOCAL_TIMERS + +#define TWD_BASE(cpu) (twd_base_addr + (cpu) * twd_size) + +/* set up by the platform code */ +void __iomem *twd_base_addr; +unsigned int twd_size; static unsigned long mpcore_timer_rate; +static void local_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + void __iomem *base = TWD_BASE(smp_processor_id()); + unsigned long ctrl; + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* timer load already set up */ + ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE + | TWD_TIMER_CONTROL_PERIODIC; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } + + __raw_writel(ctrl, base + TWD_TIMER_CONTROL); +} + +static int local_timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + void __iomem *base = TWD_BASE(smp_processor_id()); + unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL); + + __raw_writel(evt, base + TWD_TIMER_COUNTER); + __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL); + + return 0; +} + /* * local_timer_ack: checks for a local timer interrupt. * @@ -45,12 +101,11 @@ int local_timer_ack(void) return 0; } -void __cpuinit local_timer_setup(unsigned int cpu) +static void __cpuinit twd_calibrate_rate(unsigned int cpu) { void __iomem *base = TWD_BASE(cpu); - unsigned int load, offset; + unsigned long load, count; u64 waitjiffies; - unsigned int count; /* * If this is the first time round, we need to work out how fast @@ -88,36 +143,36 @@ void __cpuinit local_timer_setup(unsigned int cpu) load = mpcore_timer_rate / HZ; __raw_writel(load, base + TWD_TIMER_LOAD); - __raw_writel(0x7, base + TWD_TIMER_CONTROL); - - /* - * Now maneuver our local tick into the right part of the jiffy. - * Start by working out where within the tick our local timer - * interrupt should go. - */ - offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1); - - /* - * gettimeoffset() will return a number of us since the last tick. - * Convert this number of us to a local timer tick count. - * Be careful of integer overflow whilst keeping maximum precision. - * - * with HZ=100 and 1MHz (fpga) ~ 1GHz processor: - * load = 1 ~ 10,000 - * mpcore_timer_rate/10000 = 100 ~ 100,000 - * - * so the multiply value will be less than 10^9 always. - */ - load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100; - - /* Add on our offset to get the load value */ - load = (load + offset) % (mpcore_timer_rate / HZ); +} - __raw_writel(load, base + TWD_TIMER_COUNTER); +/* + * Setup the local clock events for a CPU. + */ +void __cpuinit local_timer_setup(unsigned int cpu) +{ + struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); + unsigned long flags; + + twd_calibrate_rate(cpu); + + clk->name = "local_timer"; + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + clk->rating = 350; + clk->set_mode = local_timer_set_mode; + clk->set_next_event = local_timer_set_next_event; + clk->irq = IRQ_LOCALTIMER; + clk->cpumask = cpumask_of_cpu(cpu); + clk->shift = 20; + clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); + clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); + clk->min_delta_ns = clockevent_delta2ns(0xf, clk); /* Make sure our local interrupt controller has this enabled */ - __raw_writel(1 << IRQ_LOCALTIMER, - __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET); + local_irq_save(flags); + get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); + local_irq_restore(flags); + + clockevents_register_device(clk); } /* @@ -127,3 +182,26 @@ void __cpuexit local_timer_stop(unsigned int cpu) { __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); } + +#else /* CONFIG_LOCAL_TIMERS */ + +static void dummy_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ +} + +void __cpuinit local_timer_setup(unsigned int cpu) +{ + struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); + + clk->name = "dummy_timer"; + clk->features = CLOCK_EVT_FEAT_DUMMY; + clk->rating = 200; + clk->set_mode = dummy_timer_set_mode; + clk->broadcast = smp_timer_broadcast; + clk->cpumask = cpumask_of_cpu(cpu); + + clockevents_register_device(clk); +} + +#endif /* !CONFIG_LOCAL_TIMERS */ diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index fce3596f995..de2b7159557 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -18,6 +18,7 @@ #include <asm/hardware/arm_scu.h> #include <asm/hardware.h> #include <asm/io.h> +#include <asm/mach-types.h> extern void realview_secondary_startup(void); @@ -31,9 +32,13 @@ static unsigned int __init get_core_count(void) { unsigned int ncores; - ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG); + if (machine_is_realview_eb() && core_tile_eb11mp()) { + ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG); + ncores = (ncores & 0x03) + 1; + } else + ncores = 1; - return (ncores & 0x03) + 1; + return ncores; } static DEFINE_SPINLOCK(boot_lock); @@ -52,7 +57,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); + gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE)); /* * let the primary processor know we're out of the @@ -187,10 +192,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus > ncores) max_cpus = ncores; +#ifdef CONFIG_LOCAL_TIMERS /* - * Enable the local timer for primary CPU + * Enable the local timer for primary CPU. If the device is + * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in + * realview_timer_init */ - local_timer_setup(cpu); + if (machine_is_realview_eb() && core_tile_eb11mp()) + local_timer_setup(cpu); +#endif /* * Initialise the present map, which describes the set of CPUs diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index ecec2f85c4c..60d9eb81024 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -36,7 +36,9 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/mmc.h> +#include <asm/mach/time.h> +#include <asm/arch/board-eb.h> #include <asm/arch/irqs.h> #include "core.h" @@ -58,26 +60,7 @@ static struct map_desc realview_eb_io_desc[] __initdata = { .pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE), .length = SZ_4K, .type = MT_DEVICE, - }, -#ifdef CONFIG_REALVIEW_MPCORE - { - .virtual = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE), - .pfn = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE), - .length = SZ_4K, - .type = MT_DEVICE, }, { - .virtual = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE), - .pfn = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE), - .pfn = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE), - .length = SZ_8K, - .type = MT_DEVICE, - }, -#endif - { .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE), .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE), .length = SZ_4K, @@ -103,11 +86,95 @@ static struct map_desc realview_eb_io_desc[] __initdata = { #endif }; +static struct map_desc realview_eb11mp_io_desc[] __initdata = { + { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_CPU_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_CPU_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_DIST_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_DIST_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_L220_BASE), + .length = SZ_8K, + .type = MT_DEVICE, + } +}; + static void __init realview_eb_map_io(void) { iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc)); + if (core_tile_eb11mp()) + iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc)); } +/* + * RealView EB AMBA devices + */ + +/* + * These devices are connected via the core APB bridge + */ +#define GPIO2_IRQ { IRQ_EB_GPIO2, NO_IRQ } +#define GPIO2_DMA { 0, 0 } +#define GPIO3_IRQ { IRQ_EB_GPIO3, NO_IRQ } +#define GPIO3_DMA { 0, 0 } + +#define AACI_IRQ { IRQ_EB_AACI, NO_IRQ } +#define AACI_DMA { 0x80, 0x81 } +#define MMCI0_IRQ { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B } +#define MMCI0_DMA { 0x84, 0 } +#define KMI0_IRQ { IRQ_EB_KMI0, NO_IRQ } +#define KMI0_DMA { 0, 0 } +#define KMI1_IRQ { IRQ_EB_KMI1, NO_IRQ } +#define KMI1_DMA { 0, 0 } + +/* + * These devices are connected directly to the multi-layer AHB switch + */ +#define SMC_IRQ { NO_IRQ, NO_IRQ } +#define SMC_DMA { 0, 0 } +#define MPMC_IRQ { NO_IRQ, NO_IRQ } +#define MPMC_DMA { 0, 0 } +#define CLCD_IRQ { IRQ_EB_CLCD, NO_IRQ } +#define CLCD_DMA { 0, 0 } +#define DMAC_IRQ { IRQ_EB_DMA, NO_IRQ } +#define DMAC_DMA { 0, 0 } + +/* + * These devices are connected via the core APB bridge + */ +#define SCTL_IRQ { NO_IRQ, NO_IRQ } +#define SCTL_DMA { 0, 0 } +#define WATCHDOG_IRQ { IRQ_EB_WDOG, NO_IRQ } +#define WATCHDOG_DMA { 0, 0 } +#define GPIO0_IRQ { IRQ_EB_GPIO0, NO_IRQ } +#define GPIO0_DMA { 0, 0 } +#define GPIO1_IRQ { IRQ_EB_GPIO1, NO_IRQ } +#define GPIO1_DMA { 0, 0 } +#define RTC_IRQ { IRQ_EB_RTC, NO_IRQ } +#define RTC_DMA { 0, 0 } + +/* + * These devices are connected via the DMA APB bridge + */ +#define SCI_IRQ { IRQ_EB_SCI, NO_IRQ } +#define SCI_DMA { 7, 6 } +#define UART0_IRQ { IRQ_EB_UART0, NO_IRQ } +#define UART0_DMA { 15, 14 } +#define UART1_IRQ { IRQ_EB_UART1, NO_IRQ } +#define UART1_DMA { 13, 12 } +#define UART2_IRQ { IRQ_EB_UART2, NO_IRQ } +#define UART2_DMA { 11, 10 } +#define UART3_IRQ { IRQ_EB_UART3, NO_IRQ } +#define UART3_DMA { 0x86, 0x87 } +#define SSP_IRQ { IRQ_EB_SSP, NO_IRQ } +#define SSP_DMA { 9, 8 } + /* FPGA Primecells */ AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &realview_mmc0_plat_data); @@ -153,38 +220,127 @@ static struct amba_device *amba_devs[] __initdata = { &kmi1_device, }; +/* + * RealView EB platform devices + */ + +static struct resource realview_eb_smc91x_resources[] = { + [0] = { + .start = REALVIEW_ETH_BASE, + .end = REALVIEW_ETH_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_EB_ETH, + .end = IRQ_EB_ETH, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device realview_eb_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(realview_eb_smc91x_resources), + .resource = realview_eb_smc91x_resources, +}; + static void __init gic_init_irq(void) { -#ifdef CONFIG_REALVIEW_MPCORE - unsigned int pldctrl; - writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); - pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); - pldctrl |= 0x00800000; /* New irq mode */ - writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); - writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); + if (core_tile_eb11mp()) { + unsigned int pldctrl; + + /* new irq mode */ + writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); + pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1); + pldctrl |= 0x00800000; + writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1); + writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); + + /* core tile GIC, primary */ + gic_cpu_base_addr = __io_address(REALVIEW_EB11MP_GIC_CPU_BASE); + gic_dist_init(0, __io_address(REALVIEW_EB11MP_GIC_DIST_BASE), 29); + gic_cpu_init(0, gic_cpu_base_addr); + +#ifndef CONFIG_REALVIEW_EB_ARM11MP_REVB + /* board GIC, secondary */ + gic_dist_init(1, __io_address(REALVIEW_GIC_DIST_BASE), 64); + gic_cpu_init(1, __io_address(REALVIEW_GIC_CPU_BASE)); + gic_cascade_irq(1, IRQ_EB11MP_EB_IRQ1); #endif - gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29); - gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); -#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB) - gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64); - gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE)); - gic_cascade_irq(1, IRQ_EB_IRQ1); + } else { + /* board GIC, primary */ + gic_cpu_base_addr = __io_address(REALVIEW_GIC_CPU_BASE); + gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29); + gic_cpu_init(0, gic_cpu_base_addr); + } +} + +/* + * Fix up the IRQ numbers for the RealView EB/ARM11MPCore tile + */ +static void realview_eb11mp_fixup(void) +{ + /* AMBA devices */ + dmac_device.irq[0] = IRQ_EB11MP_DMA; + uart0_device.irq[0] = IRQ_EB11MP_UART0; + uart1_device.irq[0] = IRQ_EB11MP_UART1; + uart2_device.irq[0] = IRQ_EB11MP_UART2; + uart3_device.irq[0] = IRQ_EB11MP_UART3; + clcd_device.irq[0] = IRQ_EB11MP_CLCD; + wdog_device.irq[0] = IRQ_EB11MP_WDOG; + gpio0_device.irq[0] = IRQ_EB11MP_GPIO0; + gpio1_device.irq[0] = IRQ_EB11MP_GPIO1; + gpio2_device.irq[0] = IRQ_EB11MP_GPIO2; + rtc_device.irq[0] = IRQ_EB11MP_RTC; + sci0_device.irq[0] = IRQ_EB11MP_SCI; + ssp0_device.irq[0] = IRQ_EB11MP_SSP; + aaci_device.irq[0] = IRQ_EB11MP_AACI; + mmc0_device.irq[0] = IRQ_EB11MP_MMCI0A; + mmc0_device.irq[1] = IRQ_EB11MP_MMCI0B; + kmi0_device.irq[0] = IRQ_EB11MP_KMI0; + kmi1_device.irq[0] = IRQ_EB11MP_KMI1; + + /* platform devices */ + realview_eb_smc91x_resources[1].start = IRQ_EB11MP_ETH; + realview_eb_smc91x_resources[1].end = IRQ_EB11MP_ETH; +} + +static void __init realview_eb_timer_init(void) +{ + unsigned int timer_irq; + + if (core_tile_eb11mp()) { +#ifdef CONFIG_LOCAL_TIMERS + twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE); + twd_size = REALVIEW_EB11MP_TWD_SIZE; #endif + timer_irq = IRQ_EB11MP_TIMER0_1; + } else + timer_irq = IRQ_EB_TIMER0_1; + + realview_timer_init(timer_irq); } +static struct sys_timer realview_eb_timer = { + .init = realview_eb_timer_init, +}; + static void __init realview_eb_init(void) { int i; -#ifdef CONFIG_REALVIEW_MPCORE - /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled - * Bits: .... ...0 0111 1001 0000 .... .... .... */ - l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff); -#endif + if (core_tile_eb11mp()) { + realview_eb11mp_fixup(); + + /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled + * Bits: .... ...0 0111 1001 0000 .... .... .... */ + l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff); + } + clk_register(&realview_clcd_clk); platform_device_register(&realview_flash_device); - platform_device_register(&realview_smc91x_device); + platform_device_register(&realview_eb_smc91x_device); platform_device_register(&realview_i2c_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { @@ -204,6 +360,6 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB") .boot_params = 0x00000100, .map_io = realview_eb_map_io, .init_irq = gic_init_irq, - .timer = &realview_timer, + .timer = &realview_eb_timer, .init_machine = realview_eb_init, MACHINE_END diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 9e13c8358ea..5c84c604ed8 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -470,7 +470,7 @@ void __init sa1110_mb_disable(void) * If the system is going to use the SA-1111 DMA engines, set up * the memory bus request/grant pins. */ -void __init sa1110_mb_enable(void) +void __devinit sa1110_mb_enable(void) { unsigned long flags; diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 75952779ce1..303a7ff6bfd 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -162,7 +162,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size) * Free the page table, if there was one. */ if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE) - pte_free_kernel(pmd_page_vaddr(pmd)); + pte_free_kernel(&init_mm, pmd_page_vaddr(pmd)); } addr += PGDIR_SIZE; diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c index 50b9aed6000..500c9610ab3 100644 --- a/arch/arm/mm/pgd.c +++ b/arch/arm/mm/pgd.c @@ -65,14 +65,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) return new_pgd; no_pte: - pmd_free(new_pmd); + pmd_free(mm, new_pmd); no_pmd: free_pages((unsigned long)new_pgd, 2); no_pgd: return NULL; } -void free_pgd_slow(pgd_t *pgd) +void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd) { pmd_t *pmd; struct page *pte; @@ -94,8 +94,8 @@ void free_pgd_slow(pgd_t *pgd) pmd_clear(pmd); dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE); pte_lock_deinit(pte); - pte_free(pte); - pmd_free(pmd); + pte_free(mm, pte); + pmd_free(mm, pmd); free: free_pages((unsigned long) pgd, 2); } diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index ba3d21d8fba..6fe481ff4fd 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -57,8 +57,6 @@ unsigned long iop_gettimeoffset(void) static irqreturn_t iop_timer_interrupt(int irq, void *dev_id) { - write_seqlock(&xtime_lock); - write_tisr(1); while ((signed long)(next_jiffy_time - read_tcr1()) @@ -67,8 +65,6 @@ iop_timer_interrupt(int irq, void *dev_id) next_jiffy_time -= ticks_per_jiffy; } - write_sequnlock(&xtime_lock); - return IRQ_HANDLED; } diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c index 2ec1daaa0e5..766473b3f98 100644 --- a/arch/arm/plat-s3c24xx/time.c +++ b/arch/arm/plat-s3c24xx/time.c @@ -130,9 +130,7 @@ static unsigned long s3c2410_gettimeoffset (void) static irqreturn_t s3c2410_timer_interrupt(int irq, void *dev_id) { - write_seqlock(&xtime_lock); timer_tick(); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index c816f29154c..28e0caf4156 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -82,6 +82,7 @@ config PLATFORM_AT32AP select SUBARCH_AVR32B select MMU select PERFORMANCE_COUNTERS + select HAVE_GPIO_LIB # # CPU types diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index d61a02da898..38a8fa31c0b 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -24,11 +24,11 @@ #define MAX_NR_PIO_DEVICES 8 struct pio_device { + struct gpio_chip chip; void __iomem *regs; const struct platform_device *pdev; struct clk *clk; u32 pinmux_mask; - u32 gpio_mask; char name[8]; }; @@ -64,7 +64,8 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, goto fail; } - if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) { + if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask) + || gpiochip_is_requested(&pio->chip, pin_index))) { printk("%s: pin %u is busy\n", pio->name, pin_index); goto fail; } @@ -79,9 +80,6 @@ void __init at32_select_periph(unsigned int pin, unsigned int periph, if (!(flags & AT32_GPIOF_PULLUP)) pio_writel(pio, PUDR, mask); - /* gpio_request NOT allowed */ - set_bit(pin_index, &pio->gpio_mask); - return; fail: @@ -130,9 +128,6 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags) pio_writel(pio, PER, mask); - /* gpio_request now allowed */ - clear_bit(pin_index, &pio->gpio_mask); - return; fail: @@ -166,96 +161,50 @@ fail: /* GPIO API */ -int gpio_request(unsigned int gpio, const char *label) +static int direction_input(struct gpio_chip *chip, unsigned offset) { - struct pio_device *pio; - unsigned int pin; - - pio = gpio_to_pio(gpio); - if (!pio) - return -ENODEV; + struct pio_device *pio = container_of(chip, struct pio_device, chip); + u32 mask = 1 << offset; - pin = gpio & 0x1f; - if (test_and_set_bit(pin, &pio->gpio_mask)) - return -EBUSY; + if (!(pio_readl(pio, PSR) & mask)) + return -EINVAL; + pio_writel(pio, ODR, mask); return 0; } -EXPORT_SYMBOL(gpio_request); -void gpio_free(unsigned int gpio) +static int gpio_get(struct gpio_chip *chip, unsigned offset) { - struct pio_device *pio; - unsigned int pin; + struct pio_device *pio = container_of(chip, struct pio_device, chip); - pio = gpio_to_pio(gpio); - if (!pio) { - printk(KERN_ERR - "gpio: attempted to free invalid pin %u\n", gpio); - return; - } - - pin = gpio & 0x1f; - if (!test_and_clear_bit(pin, &pio->gpio_mask)) - printk(KERN_ERR "gpio: freeing free or non-gpio pin %s-%u\n", - pio->name, pin); + return (pio_readl(pio, PDSR) >> offset) & 1; } -EXPORT_SYMBOL(gpio_free); -int gpio_direction_input(unsigned int gpio) -{ - struct pio_device *pio; - unsigned int pin; - - pio = gpio_to_pio(gpio); - if (!pio) - return -ENODEV; - - pin = gpio & 0x1f; - pio_writel(pio, ODR, 1 << pin); - - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); +static void gpio_set(struct gpio_chip *chip, unsigned offset, int value); -int gpio_direction_output(unsigned int gpio, int value) +static int direction_output(struct gpio_chip *chip, unsigned offset, int value) { - struct pio_device *pio; - unsigned int pin; - - pio = gpio_to_pio(gpio); - if (!pio) - return -ENODEV; + struct pio_device *pio = container_of(chip, struct pio_device, chip); + u32 mask = 1 << offset; - gpio_set_value(gpio, value); - - pin = gpio & 0x1f; - pio_writel(pio, OER, 1 << pin); + if (!(pio_readl(pio, PSR) & mask)) + return -EINVAL; + gpio_set(chip, offset, value); + pio_writel(pio, OER, mask); return 0; } -EXPORT_SYMBOL(gpio_direction_output); -int gpio_get_value(unsigned int gpio) +static void gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct pio_device *pio = &pio_dev[gpio >> 5]; + struct pio_device *pio = container_of(chip, struct pio_device, chip); + u32 mask = 1 << offset; - return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1; -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned int gpio, int value) -{ - struct pio_device *pio = &pio_dev[gpio >> 5]; - u32 mask; - - mask = 1 << (gpio & 0x1f); if (value) pio_writel(pio, SODR, mask); else pio_writel(pio, CODR, mask); } -EXPORT_SYMBOL(gpio_set_value); /*--------------------------------------------------------------------------*/ @@ -339,6 +288,63 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) /*--------------------------------------------------------------------------*/ +#ifdef CONFIG_DEBUG_FS + +#include <linux/seq_file.h> + +/* + * This shows more info than the generic gpio dump code: + * pullups, deglitching, open drain drive. + */ +static void pio_bank_show(struct seq_file *s, struct gpio_chip *chip) +{ + struct pio_device *pio = container_of(chip, struct pio_device, chip); + u32 psr, osr, imr, pdsr, pusr, ifsr, mdsr; + unsigned i; + u32 mask; + char bank; + + psr = pio_readl(pio, PSR); + osr = pio_readl(pio, OSR); + imr = pio_readl(pio, IMR); + pdsr = pio_readl(pio, PDSR); + pusr = pio_readl(pio, PUSR); + ifsr = pio_readl(pio, IFSR); + mdsr = pio_readl(pio, MDSR); + + bank = 'A' + pio->pdev->id; + + for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { + const char *label; + + label = gpiochip_is_requested(chip, i); + if (!label) + continue; + + seq_printf(s, " gpio-%-3d P%c%-2d (%-12s) %s %s %s", + chip->base + i, bank, i, + label, + (osr & mask) ? "out" : "in ", + (mask & pdsr) ? "hi" : "lo", + (mask & pusr) ? " " : "up"); + if (ifsr & mask) + seq_printf(s, " deglitch"); + if ((osr & mdsr) & mask) + seq_printf(s, " open-drain"); + if (imr & mask) + seq_printf(s, " irq-%d edge-both", + gpio_to_irq(chip->base + i)); + seq_printf(s, "\n"); + } +} + +#else +#define pio_bank_show NULL +#endif + + +/*--------------------------------------------------------------------------*/ + static int __init pio_probe(struct platform_device *pdev) { struct pio_device *pio = NULL; @@ -349,6 +355,18 @@ static int __init pio_probe(struct platform_device *pdev) pio = &pio_dev[pdev->id]; BUG_ON(!pio->regs); + pio->chip.label = pio->name; + pio->chip.base = pdev->id * 32; + pio->chip.ngpio = 32; + + pio->chip.direction_input = direction_input; + pio->chip.get = gpio_get; + pio->chip.direction_output = direction_output; + pio->chip.set = gpio_set; + pio->chip.dbg_show = pio_bank_show; + + gpiochip_add(&pio->chip); + gpio_irq_setup(pio, irq, gpio_irq_base); platform_set_drvdata(pdev, pio); @@ -406,12 +424,6 @@ void __init at32_init_pio(struct platform_device *pdev) pio->pdev = pdev; pio->regs = ioremap(regs->start, regs->end - regs->start + 1); - /* - * request_gpio() is only valid for pins that have been - * explicitly configured as GPIO and not previously requested - */ - pio->gpio_mask = ~0UL; - /* start with irqs disabled and acked */ pio_writel(pio, IDR, ~0UL); (void) pio_readl(pio, ISR); diff --git a/arch/avr32/mach-at32ap/pio.h b/arch/avr32/mach-at32ap/pio.h index 50fa3aca32c..7795116a483 100644 --- a/arch/avr32/mach-at32ap/pio.h +++ b/arch/avr32/mach-at32ap/pio.h @@ -19,7 +19,7 @@ #define PIO_OSR 0x0018 #define PIO_IFER 0x0020 #define PIO_IFDR 0x0024 -#define PIO_ISFR 0x0028 +#define PIO_IFSR 0x0028 #define PIO_SODR 0x0030 #define PIO_CODR 0x0034 #define PIO_ODSR 0x0038 diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 56ff51bc8c2..fdd9bf43361 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1373,7 +1373,7 @@ ENTRY(_sys_call_table) .long _sys_epoll_pwait .long _sys_utimensat .long _sys_signalfd - .long _sys_timerfd + .long _sys_ni_syscall .long _sys_eventfd /* 350 */ .long _sys_pread64 .long _sys_pwrite64 diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 7f0be4cd5e9..27b082ac7f1 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -150,6 +150,7 @@ config ETRAX_FLASH_BUSWIDTH Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. source arch/cris/arch-v10/Kconfig +source arch/cris/arch-v32/Kconfig endmenu @@ -157,8 +158,8 @@ source "net/Kconfig" # bring in ETRAX built-in drivers menu "Drivers for built-in interfaces" -# arch/cris/arch is a symlink to correct arch (arch-v10 or arch-v32) -source arch/cris/arch/drivers/Kconfig +source arch/cris/arch-v10/drivers/Kconfig +source arch/cris/arch-v32/drivers/Kconfig endmenu diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig index f1ce6f64401..1d61faec77c 100644 --- a/arch/cris/arch-v10/Kconfig +++ b/arch/cris/arch-v10/Kconfig @@ -1,3 +1,5 @@ +if ETRAX_ARCH_V10 + # ETRAX 100LX v1 has a MMU "feature" requiring a low mapping config CRIS_LOW_MAP bool @@ -451,3 +453,5 @@ config ETRAX_POWERBUTTON_BIT default "25" help Configure where power button is connected. + +endif diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig index e3c0f292814..96740ef497d 100644 --- a/arch/cris/arch-v10/drivers/Kconfig +++ b/arch/cris/arch-v10/drivers/Kconfig @@ -1,3 +1,5 @@ +if ETRAX_ARCH_V10 + config ETRAX_ETHERNET bool "Ethernet support" depends on ETRAX_ARCH_V10 @@ -806,3 +808,5 @@ config ETRAX_DS1302_TRICKLE_CHARGE 1 = 2kohm, 2 = 4kohm, 3 = 4kohm 4 = 1 diode, 8 = 2 diodes Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5 + +endif diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index ec62c951fa3..d1361dc119e 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -1167,7 +1167,7 @@ sys_call_table: .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig index 4f79d8ed3e1..d8acaa920e1 100644 --- a/arch/cris/arch-v32/Kconfig +++ b/arch/cris/arch-v32/Kconfig @@ -1,3 +1,5 @@ +if ETRAX_ARCH_V32 + config ETRAX_DRAM_VIRTUAL_BASE hex depends on ETRAX_ARCH_V32 @@ -294,3 +296,5 @@ config ETRAX_DEF_GIO_PE_OUT help Configures the initial data for the general port E bits. Most products should use 00000 here. + +endif diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 9bccb5e2a96..c329cce2a0c 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -1,3 +1,5 @@ +if ETRAX_ARCH_V32 + config ETRAX_ETHERNET bool "Ethernet support" depends on ETRAX_ARCH_V32 @@ -610,3 +612,5 @@ config ETRAX_STREAMCOPROC help This option enables a driver for the stream co-processor for cryptographic operations. + +endif diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c index 66f9500fbc0..e0364654fc4 100644 --- a/arch/cris/arch-v32/drivers/pci/dma.c +++ b/arch/cris/arch-v32/drivers/pci/dma.c @@ -93,7 +93,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); if (!dev->dma_mem) - goto out; + goto iounmap_out; dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); if (!dev->dma_mem->bitmap) goto free1_out; @@ -110,6 +110,8 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, free1_out: kfree(dev->dma_mem); + iounmap_out: + iounmap(mem_base); out: return 0; } diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index bf0468cbe71..96f7d70f447 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -138,6 +138,15 @@ config UCPAGE_OFFSET_C0000000 endchoice +config PAGE_OFFSET + hex + default 0x20000000 if UCPAGE_OFFSET_20000000 + default 0x40000000 if UCPAGE_OFFSET_40000000 + default 0x60000000 if UCPAGE_OFFSET_60000000 + default 0x80000000 if UCPAGE_OFFSET_80000000 + default 0xA0000000 if UCPAGE_OFFSET_A0000000 + default 0xC0000000 + config PROTECT_KERNEL bool "Protect core kernel against userspace" depends on !MMU diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index f42b328b1dd..ef7527b8b0c 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -13,7 +13,7 @@ ENTRY(_start) jiffies = jiffies_64 + 4; -__page_offset = 0xc0000000; /* start of area covered by struct pages */ +__page_offset = CONFIG_PAGE_OFFSET; /* start of area covered by struct pages */ __kernel_image_start = __page_offset; /* address at which kernel image resides */ SECTIONS diff --git a/arch/frv/mm/mmu-context.c b/arch/frv/mm/mmu-context.c index 1530a4111e6..81757d55a5b 100644 --- a/arch/frv/mm/mmu-context.c +++ b/arch/frv/mm/mmu-context.c @@ -181,7 +181,7 @@ int cxn_pin_by_pid(pid_t pid) /* get a handle on the mm_struct */ read_lock(&tasklist_lock); - tsk = find_task_by_pid(pid); + tsk = find_task_by_vpid(pid); if (tsk) { ret = -EINVAL; diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c index 7787c3cc52c..1a2e5c8d03a 100644 --- a/arch/frv/mm/pgalloc.c +++ b/arch/frv/mm/pgalloc.c @@ -140,7 +140,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) return pgd; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { /* in the non-PAE case, clear_page_tables() clears user pgd entries */ quicklist_free(0, pgd_dtor, pgd); diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 8c0ae4f20f7..a94445422cc 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1265,7 +1265,7 @@ sba_fill_pdir( * the sglist do both. */ static SBA_INLINE int -sba_coalesce_chunks( struct ioc *ioc, +sba_coalesce_chunks(struct ioc *ioc, struct device *dev, struct scatterlist *startsg, int nents) { @@ -1275,6 +1275,7 @@ sba_coalesce_chunks( struct ioc *ioc, struct scatterlist *dma_sg; /* next DMA stream head */ unsigned long dma_offset, dma_len; /* start/len of DMA stream */ int n_mappings = 0; + unsigned int max_seg_size = dma_get_max_seg_size(dev); while (nents > 0) { unsigned long vaddr = (unsigned long) sba_sg_address(startsg); @@ -1314,6 +1315,9 @@ sba_coalesce_chunks( struct ioc *ioc, > DMA_CHUNK_SIZE) break; + if (dma_len + startsg->length > max_seg_size) + break; + /* ** Then look for virtually contiguous blocks. ** @@ -1441,7 +1445,7 @@ int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int di ** w/o this association, we wouldn't have coherent DMA! ** Access to the virtual address is what forces a two pass algorithm. */ - coalesced = sba_coalesce_chunks(ioc, sglist, nents); + coalesced = sba_coalesce_chunks(ioc, dev, sglist, nents); /* ** Program the I/O Pdir diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index c36f43c9460..f5d3efbfbed 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1586,7 +1586,7 @@ sys_call_table: data8 sys_epoll_pwait // 1305 data8 sys_utimensat data8 sys_signalfd - data8 sys_timerfd + data8 sys_ni_syscall data8 sys_eventfd .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/m32r/boot/compressed/m32r_sio.c b/arch/m32r/boot/compressed/m32r_sio.c index ee3c8be12fa..01d877c6868 100644 --- a/arch/m32r/boot/compressed/m32r_sio.c +++ b/arch/m32r/boot/compressed/m32r_sio.c @@ -17,7 +17,7 @@ static int puts(const char *s) return 0; } -#if defined(CONFIG_PLAT_M32700UT_Alpha) || defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) +#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) #include <asm/m32r.h> #include <asm/io.h> @@ -52,7 +52,7 @@ static void putc(char c) } *BOOT_SIO0TXB = c; } -#else /* !(CONFIG_PLAT_M32700UT_Alpha) && !(CONFIG_PLAT_M32700UT) */ +#else /* !(CONFIG_PLAT_M32700UT) */ #if defined(CONFIG_PLAT_MAPPI2) #define SIO0STS (volatile unsigned short *)(0xa0efd000 + 14) #define SIO0TXB (volatile unsigned short *)(0xa0efd000 + 30) diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 8236e42ef71..ffabd01c45e 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -577,20 +577,6 @@ config MAC_HID depends on INPUT_ADBHID default y -config MAC_ADBKEYCODES - bool "Support for ADB raw keycodes" - depends on INPUT_ADBHID - help - This provides support for sending raw ADB keycodes to console - devices. This is the default up to 2.4.0, but in future this may be - phased out in favor of generic Linux keycodes. If you say Y here, - you can dynamically switch via the - /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes - sysctl and with the "keyboard_sends_linux_keycodes=" kernel - argument. - - If unsure, say Y here. - config ADB_KEYBOARD bool "Support for ADB keyboard (old driver)" depends on MAC && !INPUT_ADBHID diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 4a1bd44ff16..2cba605cb59 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -13,16 +13,15 @@ # Copyright (C) 1994 by Hamish Macdonald # -# test for cross compiling -COMPILE_ARCH = $(shell uname -m) - # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds -ifneq ($(COMPILE_ARCH),$(ARCH)) - # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linux-gnu- +ifneq ($(SUBARCH),$(ARCH)) + ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE := $(call cc-cross-prefix, \ + m68k-linux-gnu- m68k-linux- m68k-unknown-linux-gnu-) + endif endif ifdef CONFIG_SUN3 diff --git a/arch/m68k/amiga/Makefile b/arch/m68k/amiga/Makefile index 8b415651ede..6a0d7650f98 100644 --- a/arch/m68k/amiga/Makefile +++ b/arch/m68k/amiga/Makefile @@ -2,6 +2,6 @@ # Makefile for Linux arch/m68k/amiga source directory # -obj-y := config.o amiints.o cia.o chipram.o amisound.o amiga_ksyms.o +obj-y := config.o amiints.o cia.o chipram.o amisound.o obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c deleted file mode 100644 index 7fdcf6bf3ad..00000000000 --- a/arch/m68k/amiga/amiga_ksyms.c +++ /dev/null @@ -1,33 +0,0 @@ -#include <linux/module.h> -#include <linux/types.h> -#include <asm/ptrace.h> -#include <asm/amigahw.h> -#include <asm/amigaints.h> -#include <asm/amipcmcia.h> - -extern volatile u_short amiga_audio_min_period; -extern u_short amiga_audio_period; - -/* - * Add things here when you find the need for it. - */ -EXPORT_SYMBOL(amiga_model); -EXPORT_SYMBOL(amiga_chipset); -EXPORT_SYMBOL(amiga_hw_present); -EXPORT_SYMBOL(amiga_eclock); -EXPORT_SYMBOL(amiga_colorclock); -EXPORT_SYMBOL(amiga_chip_alloc); -EXPORT_SYMBOL(amiga_chip_free); -EXPORT_SYMBOL(amiga_chip_avail); -EXPORT_SYMBOL(amiga_chip_size); -EXPORT_SYMBOL(amiga_audio_period); -EXPORT_SYMBOL(amiga_audio_min_period); - -#ifdef CONFIG_AMIGA_PCMCIA - EXPORT_SYMBOL(pcmcia_reset); - EXPORT_SYMBOL(pcmcia_copy_tuple); - EXPORT_SYMBOL(pcmcia_program_voltage); - EXPORT_SYMBOL(pcmcia_access_speed); - EXPORT_SYMBOL(pcmcia_write_enable); - EXPORT_SYMBOL(pcmcia_write_disable); -#endif diff --git a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c index 1f5bfb58429..61e5c54625a 100644 --- a/arch/m68k/amiga/amisound.c +++ b/arch/m68k/amiga/amisound.c @@ -12,6 +12,7 @@ #include <linux/timer.h> #include <linux/init.h> #include <linux/string.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/amigahw.h> @@ -21,7 +22,7 @@ static const signed char sine_data[] = { 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 }; -#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0])) +#define DATA_SIZE ARRAY_SIZE(sine_data) #define custom amiga_custom @@ -31,6 +32,7 @@ static const signed char sine_data[] = { */ volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */ +EXPORT_SYMBOL(amiga_audio_min_period); #define MAX_PERIOD (65535) @@ -40,6 +42,7 @@ volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */ */ unsigned short amiga_audio_period = MAX_PERIOD; +EXPORT_SYMBOL(amiga_audio_period); static unsigned long clock_constant; diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c index fa015d80161..d10726f9038 100644 --- a/arch/m68k/amiga/chipram.c +++ b/arch/m68k/amiga/chipram.c @@ -13,10 +13,13 @@ #include <linux/ioport.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/module.h> + #include <asm/page.h> #include <asm/amigahw.h> unsigned long amiga_chip_size; +EXPORT_SYMBOL(amiga_chip_size); static struct resource chipram_res = { .name = "Chip RAM", .start = CHIP_PHYSADDR @@ -67,6 +70,7 @@ void *amiga_chip_alloc(unsigned long size, const char *name) #endif return (void *)ZTWO_VADDR(res->start); } +EXPORT_SYMBOL(amiga_chip_alloc); /* @@ -120,6 +124,7 @@ void amiga_chip_free(void *ptr) } printk("amiga_chip_free: trying to free nonexistent region at %p\n", ptr); } +EXPORT_SYMBOL(amiga_chip_free); unsigned long amiga_chip_avail(void) @@ -129,3 +134,5 @@ unsigned long amiga_chip_avail(void) #endif return chipavail; } +EXPORT_SYMBOL(amiga_chip_avail); + diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 35748531327..50f5daab46b 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/zorro.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -36,13 +37,24 @@ #include <asm/io.h> unsigned long amiga_model; +EXPORT_SYMBOL(amiga_model); + unsigned long amiga_eclock; +EXPORT_SYMBOL(amiga_eclock); + unsigned long amiga_masterclock; + unsigned long amiga_colorclock; +EXPORT_SYMBOL(amiga_colorclock); + unsigned long amiga_chipset; +EXPORT_SYMBOL(amiga_chipset); + unsigned char amiga_vblank; unsigned char amiga_psfreq; + struct amiga_hw_present amiga_hw_present; +EXPORT_SYMBOL(amiga_hw_present); static char s_a500[] __initdata = "A500"; static char s_a500p[] __initdata = "A500+"; diff --git a/arch/m68k/amiga/pcmcia.c b/arch/m68k/amiga/pcmcia.c index 186662ca1a8..7106f0c3639 100644 --- a/arch/m68k/amiga/pcmcia.c +++ b/arch/m68k/amiga/pcmcia.c @@ -15,6 +15,8 @@ #include <linux/types.h> #include <linux/jiffies.h> #include <linux/timer.h> +#include <linux/module.h> + #include <asm/amigayle.h> #include <asm/amipcmcia.h> @@ -30,6 +32,7 @@ void pcmcia_reset(void) while (time_before(jiffies, reset_start_time + 1*HZ/100)); b = gayle_reset; } +EXPORT_SYMBOL(pcmcia_reset); /* copy a tuple, including tuple header. return nb bytes copied */ @@ -61,6 +64,7 @@ int pcmcia_copy_tuple(unsigned char tuple_id, void *tuple, int max_len) return 0; } +EXPORT_SYMBOL(pcmcia_copy_tuple); void pcmcia_program_voltage(int voltage) { @@ -84,6 +88,7 @@ void pcmcia_program_voltage(int voltage) gayle.config = cfg_byte; } +EXPORT_SYMBOL(pcmcia_program_voltage); void pcmcia_access_speed(int speed) { @@ -101,13 +106,17 @@ void pcmcia_access_speed(int speed) cfg_byte = (cfg_byte & 0xf3) | s; gayle.config = cfg_byte; } +EXPORT_SYMBOL(pcmcia_access_speed); void pcmcia_write_enable(void) { gayle.cardstatus = GAYLE_CS_WR|GAYLE_CS_DA; } +EXPORT_SYMBOL(pcmcia_write_enable); void pcmcia_write_disable(void) { gayle.cardstatus = 0; } +EXPORT_SYMBOL(pcmcia_write_disable); + diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 2cb86191f0a..2cd905efe63 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -3,7 +3,7 @@ # obj-y := config.o time.o debug.o ataints.o stdma.o \ - atasound.o stram.o atari_ksyms.o + atasound.o stram.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_HADES) += hades-pci.o diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index b85ca22024c..b45593a60bd 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -40,6 +40,7 @@ #include <linux/kernel_stat.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/module.h> #include <asm/system.h> #include <asm/traps.h> @@ -446,6 +447,7 @@ unsigned long atari_register_vme_int(void) free_vme_vec_bitmap |= 1 << i; return VME_SOURCE_BASE + i; } +EXPORT_SYMBOL(atari_register_vme_int); void atari_unregister_vme_int(unsigned long irq) @@ -455,5 +457,6 @@ void atari_unregister_vme_int(unsigned long irq) free_vme_vec_bitmap &= ~(1 << irq); } } +EXPORT_SYMBOL(atari_unregister_vme_int); diff --git a/arch/m68k/atari/atari_ksyms.c b/arch/m68k/atari/atari_ksyms.c deleted file mode 100644 index a0475715153..00000000000 --- a/arch/m68k/atari/atari_ksyms.c +++ /dev/null @@ -1,35 +0,0 @@ -#include <linux/module.h> - -#include <asm/ptrace.h> -#include <asm/traps.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atarikb.h> -#include <asm/atari_joystick.h> -#include <asm/atari_stdma.h> -#include <asm/atari_stram.h> - -extern void atari_microwire_cmd( int cmd ); -extern int atari_MFP_init_done; -extern int atari_SCC_init_done; -extern int atari_SCC_reset_done; - -EXPORT_SYMBOL(atari_mch_cookie); -EXPORT_SYMBOL(atari_mch_type); -EXPORT_SYMBOL(atari_hw_present); -EXPORT_SYMBOL(atari_switches); -EXPORT_SYMBOL(atari_dont_touch_floppy_select); -EXPORT_SYMBOL(atari_register_vme_int); -EXPORT_SYMBOL(atari_unregister_vme_int); -EXPORT_SYMBOL(stdma_lock); -EXPORT_SYMBOL(stdma_release); -EXPORT_SYMBOL(stdma_others_waiting); -EXPORT_SYMBOL(stdma_islocked); -EXPORT_SYMBOL(atari_stram_alloc); -EXPORT_SYMBOL(atari_stram_free); - -EXPORT_SYMBOL(atari_MFP_init_done); -EXPORT_SYMBOL(atari_SCC_init_done); -EXPORT_SYMBOL(atari_SCC_reset_done); - -EXPORT_SYMBOL(atari_microwire_cmd); diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c index ee04250eb56..d266fe89c12 100644 --- a/arch/m68k/atari/atasound.c +++ b/arch/m68k/atari/atasound.c @@ -22,6 +22,7 @@ #include <linux/fcntl.h> #include <linux/errno.h> #include <linux/mm.h> +#include <linux/module.h> #include <asm/atarihw.h> #include <asm/system.h> @@ -43,6 +44,7 @@ void atari_microwire_cmd (int cmd) while( tt_microwire.mask != 0x7ff) ; } +EXPORT_SYMBOL(atari_microwire_cmd); /* PSG base frequency */ diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index e40e5dcaa34..5945e150555 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/ioport.h> #include <linux/vt_kern.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/setup.h> @@ -43,10 +44,20 @@ #include <asm/io.h> u_long atari_mch_cookie; +EXPORT_SYMBOL(atari_mch_cookie); + u_long atari_mch_type; +EXPORT_SYMBOL(atari_mch_type); + struct atari_hw_present atari_hw_present; +EXPORT_SYMBOL(atari_hw_present); + u_long atari_switches; +EXPORT_SYMBOL(atari_switches); + int atari_dont_touch_floppy_select; +EXPORT_SYMBOL(atari_dont_touch_floppy_select); + int atari_rtc_year_offset; /* local function prototypes */ diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c index fbeed8c8ecb..043ddbc61c7 100644 --- a/arch/m68k/atari/debug.c +++ b/arch/m68k/atari/debug.c @@ -15,17 +15,23 @@ #include <linux/console.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/atarihw.h> #include <asm/atariints.h> /* Flag that Modem1 port is already initialized and used */ int atari_MFP_init_done; +EXPORT_SYMBOL(atari_MFP_init_done); + /* Flag that Modem1 port is already initialized and used */ int atari_SCC_init_done; +EXPORT_SYMBOL(atari_SCC_init_done); + /* Can be set somewhere, if a SCC master reset has already be done and should * not be repeated; used by kgdb */ int atari_SCC_reset_done; +EXPORT_SYMBOL(atari_SCC_reset_done); static struct console atari_console_driver = { .name = "debug", diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c index bee2b1443e3..2bbabc00870 100644 --- a/arch/m68k/atari/hades-pci.c +++ b/arch/m68k/atari/hades-pci.c @@ -376,8 +376,8 @@ struct pci_bus_info * __init init_hades_pci(void) */ bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL); - if (!bus) - return NULL; + if (unlikely(!bus)) + goto iounmap_base_virt; /* * Claim resources. The m68k has no separate I/O space, both @@ -385,43 +385,25 @@ struct pci_bus_info * __init init_hades_pci(void) * the I/O resources are requested in memory space as well. */ - if (request_resource(&iomem_resource, &config_space) != 0) - { - kfree(bus); - return NULL; - } + if (unlikely(request_resource(&iomem_resource, &config_space) != 0)) + goto free_bus; - if (request_resource(&iomem_resource, &io_space) != 0) - { - release_resource(&config_space); - kfree(bus); - return NULL; - } + if (unlikely(request_resource(&iomem_resource, &io_space) != 0)) + goto release_config_space; bus->mem_space.start = HADES_MEM_BASE; bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1; bus->mem_space.name = pci_mem_name; #if 1 - if (request_resource(&iomem_resource, &bus->mem_space) != 0) - { - release_resource(&io_space); - release_resource(&config_space); - kfree(bus); - return NULL; - } + if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0)) + goto release_io_space; #endif bus->io_space.start = pci_io_base_virt; bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1; bus->io_space.name = pci_io_name; #if 1 - if (request_resource(&ioport_resource, &bus->io_space) != 0) - { - release_resource(&bus->mem_space); - release_resource(&io_space); - release_resource(&config_space); - kfree(bus); - return NULL; - } + if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0)) + goto release_bus_mem_space; #endif /* * Set hardware dependent functions. @@ -438,5 +420,21 @@ struct pci_bus_info * __init init_hades_pci(void) tt_mfp.active_edge &= ~0x27; return bus; + +release_bus_mem_space: + release_resource(&bus->mem_space); +release_io_space: + release_resource(&io_space); +release_config_space: + release_resource(&config_space); +free_bus: + kfree(bus); +iounmap_base_virt: + iounmap((void *)pci_io_base_virt); + + for (i = 0; i < N_SLOTS; i++) + iounmap((void *)pci_conf_base_virt[i]); + + return NULL; } #endif diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index ab3fd5202b2..d1bd029a34a 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/wait.h> +#include <linux/module.h> #include <asm/atari_stdma.h> #include <asm/atariints.h> @@ -91,6 +92,7 @@ void stdma_lock(irq_handler_t handler, void *data) stdma_isr_data = data; local_irq_restore(flags); } +EXPORT_SYMBOL(stdma_lock); /* @@ -117,6 +119,7 @@ void stdma_release(void) local_irq_restore(flags); } +EXPORT_SYMBOL(stdma_release); /* @@ -134,6 +137,7 @@ int stdma_others_waiting(void) { return waitqueue_active(&stdma_wait); } +EXPORT_SYMBOL(stdma_others_waiting); /* @@ -155,6 +159,7 @@ int stdma_islocked(void) { return stdma_locked; } +EXPORT_SYMBOL(stdma_islocked); /* diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c index bf4588cbe37..8dda6515887 100644 --- a/arch/m68k/atari/stram.c +++ b/arch/m68k/atari/stram.c @@ -20,6 +20,7 @@ #include <linux/bootmem.h> #include <linux/mount.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <asm/setup.h> #include <asm/machdep.h> @@ -208,6 +209,7 @@ void *atari_stram_alloc(long size, const char *owner) } return( addr ); } +EXPORT_SYMBOL(atari_stram_alloc); void atari_stram_free( void *addr ) @@ -237,6 +239,7 @@ void atari_stram_free( void *addr ) printk( KERN_ERR "atari_stram_free: cannot free block at %p " "(called from %p)\n", addr, __builtin_return_address(0) ); } +EXPORT_SYMBOL(atari_stram_free); /* ------------------------------------------------------------------------ */ diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 15b80abfe94..ff9dffa5b86 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -678,7 +678,6 @@ CONFIG_LOGO_MAC_CLUT224=y # CONFIG_MAC_SCC=y CONFIG_MAC_HID=y -CONFIG_MAC_ADBKEYCODES=y CONFIG_SERIAL_CONSOLE=y # diff --git a/arch/m68k/hp300/Makefile b/arch/m68k/hp300/Makefile index 288b9c67c9b..96d4244c82f 100644 --- a/arch/m68k/hp300/Makefile +++ b/arch/m68k/hp300/Makefile @@ -2,4 +2,4 @@ # Makefile for Linux arch/m68k/hp300 source directory # -obj-y := ksyms.o config.o time.o reboot.o +obj-y := config.o time.o reboot.o diff --git a/arch/m68k/hp300/ksyms.c b/arch/m68k/hp300/ksyms.c deleted file mode 100644 index 8202830763d..00000000000 --- a/arch/m68k/hp300/ksyms.c +++ /dev/null @@ -1,9 +0,0 @@ -/* - * linux/arch/m68k/hp300/ksyms.c - * - * Copyright (C) 1998 Philip Blundell <philb@gnu.org> - * - * This file contains the HP300-specific kernel symbols. None yet. :-) - */ - -#include <linux/module.h> diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 918f5dbeaef..6dfa3b3c0e2 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -742,7 +742,7 @@ sys_call_table: .long sys_epoll_pwait /* 315 */ .long sys_utimensat .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate /* 320 */ diff --git a/arch/m68k/mac/Makefile b/arch/m68k/mac/Makefile index 995a09d912f..1d265ba365a 100644 --- a/arch/m68k/mac/Makefile +++ b/arch/m68k/mac/Makefile @@ -3,4 +3,4 @@ # obj-y := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \ - baboon.o macboing.o debug.o misc.o mac_ksyms.o + baboon.o macboing.o debug.o misc.o diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 01b468b9392..735a49b4b93 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -58,8 +58,6 @@ extern struct mem_info m68k_memory[NUM_MEMINFO]; extern struct mem_info m68k_ramdisk; -extern char m68k_command_line[CL_SIZE]; - void *mac_env; /* Loaded by the boot asm */ /* The phys. video addr. - might be bogus on some machines */ diff --git a/arch/m68k/mac/mac_ksyms.c b/arch/m68k/mac/mac_ksyms.c deleted file mode 100644 index 6e37ceb0f3b..00000000000 --- a/arch/m68k/mac/mac_ksyms.c +++ /dev/null @@ -1,8 +0,0 @@ -#include <linux/module.h> -#include <asm/ptrace.h> -#include <asm/traps.h> - -/* Says whether we're using A/UX interrupts or not */ -extern int via_alt_mapping; - -EXPORT_SYMBOL(via_alt_mapping); diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 8df270e950f..fa485df4160 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/ide.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/macintosh.h> @@ -41,7 +42,9 @@ volatile __u8 *via1, *via2; /* See note in mac_via.h about how this is possibly not useful */ volatile long *via_memory_bogon=(long *)&via_memory_bogon; #endif -int rbv_present, via_alt_mapping; +int rbv_present; +int via_alt_mapping; +EXPORT_SYMBOL(via_alt_mapping); __u8 rbv_clear; /* diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile index 950e82f2164..edb3f6e6ee6 100644 --- a/arch/m68k/mvme16x/Makefile +++ b/arch/m68k/mvme16x/Makefile @@ -2,4 +2,4 @@ # Makefile for Linux arch/m68k/mvme16x source directory # -obj-y := config.o rtc.o mvme16x_ksyms.o +obj-y := config.o rtc.o diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index daa78516140..24cbc303045 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -25,6 +25,7 @@ #include <linux/genhd.h> #include <linux/rtc.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -58,6 +59,7 @@ static irq_handler_t tick_handler; unsigned short mvme16x_config; +EXPORT_SYMBOL(mvme16x_config); int mvme16x_parse_bootinfo(const struct bi_record *bi) diff --git a/arch/m68k/mvme16x/mvme16x_ksyms.c b/arch/m68k/mvme16x/mvme16x_ksyms.c deleted file mode 100644 index 4a8a3634bb4..00000000000 --- a/arch/m68k/mvme16x/mvme16x_ksyms.c +++ /dev/null @@ -1,6 +0,0 @@ -#include <linux/module.h> -#include <linux/types.h> -#include <asm/ptrace.h> -#include <asm/mvme16xhw.h> - -EXPORT_SYMBOL(mvme16x_config); diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug index 9ff47bd09ae..ed6d9a83bfd 100644 --- a/arch/m68knommu/Kconfig.debug +++ b/arch/m68knommu/Kconfig.debug @@ -21,13 +21,6 @@ config BOOTPARAM_STRING default 'console=ttyS0,19200' depends on BOOTPARAM -config DUMPTOFLASH - bool "Panic/Dump to FLASH" - depends on COLDFIRE - help - Dump any panic of trap output into a flash memory segment - for later analysis. - config NO_KERNEL_MSG bool "Suppress Kernel BUG Messages" help diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig index 5a0ecaaee3b..648113075f9 100644 --- a/arch/m68knommu/defconfig +++ b/arch/m68knommu/defconfig @@ -597,7 +597,6 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_FULLDEBUG is not set # CONFIG_HIGHPROFILE is not set # CONFIG_BOOTPARAM is not set -# CONFIG_DUMPTOFLASH is not set # CONFIG_NO_KERNEL_MSG is not set # CONFIG_BDM_DISABLE is not set diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c index f795062aba1..53fad149028 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68knommu/kernel/m68k_ksyms.c @@ -24,14 +24,6 @@ extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(dump_fpu); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(ip_fast_csum); @@ -46,9 +38,6 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck); it's OK to leave it out of version control. */ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memscan); -EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__down_failed); EXPORT_SYMBOL(__down_failed_interruptible); diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index 332345d7675..81507c53d4a 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c @@ -64,9 +64,6 @@ void (*mach_power_off)(void); #ifdef CONFIG_M68VZ328 #define CPU "MC68VZ328" #endif -#ifdef CONFIG_M68332 - #define CPU "MC68332" -#endif #ifdef CONFIG_M68360 #define CPU "MC68360" #endif diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S index 9620093514b..1b02b882006 100644 --- a/arch/m68knommu/kernel/syscalltable.S +++ b/arch/m68knommu/kernel/syscalltable.S @@ -336,7 +336,7 @@ ENTRY(sys_call_table) .long sys_epoll_pwait /* 315 */ .long sys_utimensat .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate /* 320 */ diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 82480a1717d..f798139e888 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -660,7 +660,7 @@ einval: li v0, -EINVAL sys sys_ioprio_get 2 /* 4315 */ sys sys_utimensat 4 sys sys_signalfd 3 - sys sys_timerfd 4 + sys sys_ni_syscall 0 sys sys_eventfd 1 sys sys_fallocate 6 /* 4320 */ .endm diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index c2c10876da2..a626be6baea 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -475,7 +475,7 @@ sys_call_table: PTR sys_ioprio_get PTR sys_utimensat /* 5275 */ PTR sys_signalfd - PTR sys_timerfd + PTR sys_ni_syscall PTR sys_eventfd PTR sys_fallocate .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 01993ec3368..9d5bcaf1b38 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -401,7 +401,7 @@ EXPORT(sysn32_call_table) PTR sys_ioprio_get PTR compat_sys_utimensat PTR compat_sys_signalfd /* 5280 */ - PTR compat_sys_timerfd + PTR sys_ni_syscall PTR sys_eventfd PTR sys_fallocate .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index dd68afce7da..fd2019c1ec2 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -523,7 +523,7 @@ sys_call_table: PTR sys_ioprio_get /* 4315 */ PTR compat_sys_utimensat PTR compat_sys_signalfd - PTR compat_sys_timerfd + PTR sys_ni_syscall PTR sys_eventfd PTR sys32_fallocate /* 4320 */ .size sys_call_table,.-sys_call_table diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b94d4502a47..cf030b00441 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -256,6 +256,9 @@ config IOMMU_VMERGE Most drivers don't have this problem; it is safe to say Y here. +config IOMMU_HELPER + def_bool PPC64 + config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC) diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 84239076a5b..3a317cb0636 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c @@ -31,8 +31,8 @@ static inline unsigned long device_to_mask(struct device *dev) static void *dma_iommu_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { - return iommu_alloc_coherent(dev->archdata.dma_data, size, dma_handle, - device_to_mask(dev), flag, + return iommu_alloc_coherent(dev, dev->archdata.dma_data, size, + dma_handle, device_to_mask(dev), flag, dev->archdata.numa_node); } @@ -52,7 +52,7 @@ static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { - return iommu_map_single(dev->archdata.dma_data, vaddr, size, + return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size, device_to_mask(dev), direction); } @@ -68,7 +68,7 @@ static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle, static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - return iommu_map_sg(dev->archdata.dma_data, sglist, nelems, + return iommu_map_sg(dev, sglist, nelems, device_to_mask(dev), direction); } diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index a3c406aca66..8f1f4e539c4 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -31,6 +31,7 @@ #include <linux/string.h> #include <linux/dma-mapping.h> #include <linux/bitops.h> +#include <linux/iommu-helper.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/iommu.h> @@ -81,17 +82,19 @@ static int __init setup_iommu(char *str) __setup("protect4gb=", setup_protect4gb); __setup("iommu=", setup_iommu); -static unsigned long iommu_range_alloc(struct iommu_table *tbl, +static unsigned long iommu_range_alloc(struct device *dev, + struct iommu_table *tbl, unsigned long npages, unsigned long *handle, unsigned long mask, unsigned int align_order) { - unsigned long n, end, i, start; + unsigned long n, end, start; unsigned long limit; int largealloc = npages > 15; int pass = 0; unsigned long align_mask; + unsigned long boundary_size; align_mask = 0xffffffffffffffffl >> (64 - align_order); @@ -136,14 +139,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, start &= mask; } - n = find_next_zero_bit(tbl->it_map, limit, start); - - /* Align allocation */ - n = (n + align_mask) & ~align_mask; - - end = n + npages; + if (dev) + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + 1 << IOMMU_PAGE_SHIFT); + else + boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT); + /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */ - if (unlikely(end >= limit)) { + n = iommu_area_alloc(tbl->it_map, limit, start, npages, + tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT, + align_mask); + if (n == -1) { if (likely(pass < 2)) { /* First failure, just rescan the half of the table. * Second failure, rescan the other half of the table. @@ -158,14 +164,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, } } - for (i = n; i < end; i++) - if (test_bit(i, tbl->it_map)) { - start = i+1; - goto again; - } - - for (i = n; i < end; i++) - __set_bit(i, tbl->it_map); + end = n + npages; /* Bump the hint to a new block for small allocs. */ if (largealloc) { @@ -184,16 +183,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, return n; } -static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page, - unsigned int npages, enum dma_data_direction direction, - unsigned long mask, unsigned int align_order) +static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, + void *page, unsigned int npages, + enum dma_data_direction direction, + unsigned long mask, unsigned int align_order) { unsigned long entry, flags; dma_addr_t ret = DMA_ERROR_CODE; spin_lock_irqsave(&(tbl->it_lock), flags); - entry = iommu_range_alloc(tbl, npages, NULL, mask, align_order); + entry = iommu_range_alloc(dev, tbl, npages, NULL, mask, align_order); if (unlikely(entry == DMA_ERROR_CODE)) { spin_unlock_irqrestore(&(tbl->it_lock), flags); @@ -224,7 +224,6 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, unsigned int npages) { unsigned long entry, free_entry; - unsigned long i; entry = dma_addr >> IOMMU_PAGE_SHIFT; free_entry = entry - tbl->it_offset; @@ -246,9 +245,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, } ppc_md.tce_free(tbl, entry, npages); - - for (i = 0; i < npages; i++) - __clear_bit(free_entry+i, tbl->it_map); + iommu_area_free(tbl->it_map, free_entry, npages); } static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, @@ -270,16 +267,18 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, spin_unlock_irqrestore(&(tbl->it_lock), flags); } -int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, +int iommu_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, unsigned long mask, enum dma_data_direction direction) { + struct iommu_table *tbl = dev->archdata.dma_data; dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart; int outcount, incount, i; unsigned int align; unsigned long handle; + unsigned int max_seg_size; BUG_ON(direction == DMA_NONE); @@ -298,6 +297,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, spin_lock_irqsave(&(tbl->it_lock), flags); + max_seg_size = dma_get_max_seg_size(dev); for_each_sg(sglist, s, nelems, i) { unsigned long vaddr, npages, entry, slen; @@ -314,7 +314,7 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE && (vaddr & ~PAGE_MASK) == 0) align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; - entry = iommu_range_alloc(tbl, npages, &handle, + entry = iommu_range_alloc(dev, tbl, npages, &handle, mask >> IOMMU_PAGE_SHIFT, align); DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen); @@ -344,7 +344,8 @@ int iommu_map_sg(struct iommu_table *tbl, struct scatterlist *sglist, /* We cannot merge if: * - allocated dma_addr isn't contiguous to previous allocation */ - if (novmerge || (dma_addr != dma_next)) { + if (novmerge || (dma_addr != dma_next) || + (outs->dma_length + s->length > max_seg_size)) { /* Can't merge: create a new segment */ segstart = s; outcount++; @@ -452,9 +453,6 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) { unsigned long sz; - unsigned long start_index, end_index; - unsigned long entries_per_4g; - unsigned long index; static int welcomed = 0; struct page *page; @@ -476,6 +474,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) #ifdef CONFIG_CRASH_DUMP if (ppc_md.tce_get) { + unsigned long index; unsigned long tceval; unsigned long tcecount = 0; @@ -506,23 +505,6 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); #endif - /* - * DMA cannot cross 4 GB boundary. Mark last entry of each 4 - * GB chunk as reserved. - */ - if (protect4gb) { - entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT; - - /* Mark the last bit before a 4GB boundary as used */ - start_index = tbl->it_offset | (entries_per_4g - 1); - start_index -= tbl->it_offset; - - end_index = tbl->it_size; - - for (index = start_index; index < end_index - 1; index += entries_per_4g) - __set_bit(index, tbl->it_map); - } - if (!welcomed) { printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n", novmerge ? "disabled" : "enabled"); @@ -570,9 +552,9 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name) * need not be page aligned, the dma_addr_t returned will point to the same * byte within the page as vaddr. */ -dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, - size_t size, unsigned long mask, - enum dma_data_direction direction) +dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, + void *vaddr, size_t size, unsigned long mask, + enum dma_data_direction direction) { dma_addr_t dma_handle = DMA_ERROR_CODE; unsigned long uaddr; @@ -589,7 +571,7 @@ dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr, ((unsigned long)vaddr & ~PAGE_MASK) == 0) align = PAGE_SHIFT - IOMMU_PAGE_SHIFT; - dma_handle = iommu_alloc(tbl, vaddr, npages, direction, + dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction, mask >> IOMMU_PAGE_SHIFT, align); if (dma_handle == DMA_ERROR_CODE) { if (printk_ratelimit()) { @@ -621,8 +603,9 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, * Returns the virtual address of the buffer and sets dma_handle * to the dma address (mapping) of the first page. */ -void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, - dma_addr_t *dma_handle, unsigned long mask, gfp_t flag, int node) +void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, + size_t size, dma_addr_t *dma_handle, + unsigned long mask, gfp_t flag, int node) { void *ret = NULL; dma_addr_t mapping; @@ -656,7 +639,7 @@ void *iommu_alloc_coherent(struct iommu_table *tbl, size_t size, /* Set up tces to cover the allocated range */ nio_pages = size >> IOMMU_PAGE_SHIFT; io_order = get_iommu_order(size); - mapping = iommu_alloc(tbl, ret, nio_pages, DMA_BIDIRECTIONAL, + mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL, mask >> IOMMU_PAGE_SHIFT, io_order); if (mapping == DMA_ERROR_CODE) { free_pages((unsigned long)ret, order); diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 64488723162..f80f90c4d58 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -86,7 +86,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) return ret; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { free_pages((unsigned long)pgd, PGDIR_ORDER); } @@ -123,7 +123,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) return ptepage; } -void pte_free_kernel(pte_t *pte) +void pte_free_kernel(struct mm_struct *mm, pte_t *pte) { #ifdef CONFIG_SMP hash_page_sync(); @@ -131,7 +131,7 @@ void pte_free_kernel(pte_t *pte) free_page((unsigned long)pte); } -void pte_free(struct page *ptepage) +void pte_free(struct mm_struct *mm, struct page *ptepage) { #ifdef CONFIG_SMP hash_page_sync(); diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 6a0c6f6675c..11fa3c772ed 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c @@ -199,7 +199,7 @@ static struct iommu_table vio_iommu_table; void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) { - return iommu_alloc_coherent(&vio_iommu_table, size, dma_handle, + return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle, DMA_32BIT_MASK, flag, -1); } EXPORT_SYMBOL_GPL(iseries_hv_alloc); @@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(iseries_hv_free); dma_addr_t iseries_hv_map(void *vaddr, size_t size, enum dma_data_direction direction) { - return iommu_map_single(&vio_iommu_table, vaddr, size, + return iommu_map_single(NULL, &vio_iommu_table, vaddr, size, DMA_32BIT_MASK, direction); } diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index fadacfd1880..409fcaa4994 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -74,7 +74,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm) return ret; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { free_pages((unsigned long)pgd, PGDIR_ORDER); } @@ -111,7 +111,7 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) return ptepage; } -void pte_free_kernel(pte_t *pte) +void pte_free_kernel(struct mm_struct *mm, pte_t *pte) { #ifdef CONFIG_SMP hash_page_sync(); @@ -119,7 +119,7 @@ void pte_free_kernel(pte_t *pte) free_page((unsigned long)pte); } -void pte_free(struct page *ptepage) +void pte_free(struct mm_struct *mm, struct page *ptepage) { #ifdef CONFIG_SMP hash_page_sync(); diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 82cbffd0365..92a4f7b4323 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -16,6 +16,9 @@ config LOCKDEP_SUPPORT config STACKTRACE_SUPPORT def_bool y +config HAVE_LATENCYTOP_SUPPORT + def_bool y + config RWSEM_GENERIC_SPINLOCK bool @@ -47,6 +50,11 @@ config NO_IOMEM config NO_DMA def_bool y +config GENERIC_LOCKBREAK + bool + default y + depends on SMP && PREEMPT + mainmenu "Linux Kernel Configuration" config S390 diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 2283933a9a9..4599fa06bd8 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -6,4 +6,12 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" +config DEBUG_PAGEALLOC + bool "Debug page memory allocations" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a slowdown, but helps to find certain types of + memory corruptions. + endmenu diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 6ee1bedbd1b..062c3d4c039 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1698,14 +1698,6 @@ compat_sys_signalfd_wrapper: llgfr %r4,%r4 # compat_size_t jg compat_sys_signalfd - .globl compat_sys_timerfd_wrapper -compat_sys_timerfd_wrapper: - lgfr %r2,%r2 # int - lgfr %r3,%r3 # int - lgfr %r4,%r4 # int - llgtr %r5,%r5 # struct compat_itimerspec * - jg compat_sys_timerfd - .globl sys_eventfd_wrapper sys_eventfd_wrapper: llgfr %r2,%r2 # unsigned int diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1a6dac8df6f..6766e37fe8e 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -11,6 +11,7 @@ #include <linux/sys.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/cache.h> #include <asm/lowcore.h> #include <asm/errno.h> @@ -830,9 +831,7 @@ mcck_return: * Restart interruption handler, kick starter for additional CPUs */ #ifdef CONFIG_SMP -#ifndef CONFIG_HOTPLUG_CPU - .section .init.text,"ax" -#endif + __CPUINIT .globl restart_int_handler restart_int_handler: l %r15,__LC_SAVE_AREA+60 # load ksp @@ -845,9 +844,7 @@ restart_int_handler: br %r14 # branch to start_secondary restart_addr: .long start_secondary -#ifndef CONFIG_HOTPLUG_CPU .previous -#endif #else /* * If we do not run with SMP enabled, let the new CPU crash ... diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index a3e47b893f0..efde6e178f6 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -11,6 +11,7 @@ #include <linux/sys.h> #include <linux/linkage.h> +#include <linux/init.h> #include <asm/cache.h> #include <asm/lowcore.h> #include <asm/errno.h> @@ -801,9 +802,7 @@ mcck_return: * Restart interruption handler, kick starter for additional CPUs */ #ifdef CONFIG_SMP -#ifndef CONFIG_HOTPLUG_CPU - .section .init.text,"ax" -#endif + __CPUINIT .globl restart_int_handler restart_int_handler: lg %r15,__LC_SAVE_AREA+120 # load ksp @@ -814,9 +813,7 @@ restart_int_handler: lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on jg start_secondary -#ifndef CONFIG_HOTPLUG_CPU .previous -#endif #else /* * If we do not run with SMP enabled, let the new CPU crash ... diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index db28cca81fe..60acdc266db 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -439,7 +439,7 @@ static void ipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&ipl_info.data.ccw.dev_id); } -static int ipl_init(void) +static int __init ipl_init(void) { int rc; @@ -471,8 +471,11 @@ out: return 0; } -static struct shutdown_action ipl_action = {SHUTDOWN_ACTION_IPL_STR, ipl_run, - ipl_init}; +static struct shutdown_action __refdata ipl_action = { + .name = SHUTDOWN_ACTION_IPL_STR, + .fn = ipl_run, + .init = ipl_init, +}; /* * reipl shutdown action: Reboot Linux on shutdown. @@ -792,7 +795,7 @@ static int __init reipl_fcp_init(void) return 0; } -static int reipl_init(void) +static int __init reipl_init(void) { int rc; @@ -819,8 +822,11 @@ static int reipl_init(void) return 0; } -static struct shutdown_action reipl_action = {SHUTDOWN_ACTION_REIPL_STR, - reipl_run, reipl_init}; +static struct shutdown_action __refdata reipl_action = { + .name = SHUTDOWN_ACTION_REIPL_STR, + .fn = reipl_run, + .init = reipl_init, +}; /* * dump shutdown action: Dump Linux on shutdown. @@ -998,7 +1004,7 @@ static int __init dump_fcp_init(void) return 0; } -static int dump_init(void) +static int __init dump_init(void) { int rc; @@ -1020,8 +1026,11 @@ static int dump_init(void) return 0; } -static struct shutdown_action dump_action = {SHUTDOWN_ACTION_DUMP_STR, - dump_run, dump_init}; +static struct shutdown_action __refdata dump_action = { + .name = SHUTDOWN_ACTION_DUMP_STR, + .fn = dump_run, + .init = dump_init, +}; /* * vmcmd shutdown action: Trigger vm command on shutdown. diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 766c783bd7a..29ae165d174 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -77,7 +77,7 @@ unsigned long machine_flags = 0; unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; +struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ static unsigned long __initdata memory_end; @@ -145,7 +145,7 @@ __setup("condev=", condev_setup); static int __init conmode_setup(char *str) { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) SET_CONSOLE_SCLP; #endif @@ -183,7 +183,7 @@ static void __init conmode_default(void) */ cpcmd("TERM CONMODE 3215", NULL, 0, NULL); if (ptr == NULL) { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif return; @@ -193,7 +193,7 @@ static void __init conmode_default(void) SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; -#elif defined(CONFIG_SCLP_CONSOLE) +#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } else if (strncmp(ptr + 8, "3215", 4) == 0) { @@ -201,7 +201,7 @@ static void __init conmode_default(void) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; -#elif defined(CONFIG_SCLP_CONSOLE) +#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } @@ -212,7 +212,7 @@ static void __init conmode_default(void) SET_CONSOLE_3270; #endif } else { -#if defined(CONFIG_SCLP_CONSOLE) +#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif } @@ -528,7 +528,7 @@ static void __init setup_memory_end(void) memory_size = 0; memory_end &= PAGE_MASK; - max_mem = memory_end ? min(VMALLOC_START, memory_end) : VMALLOC_START; + max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS; memory_end = min(max_mem, memory_end); /* diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index aa37fa15451..85060659fb1 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -225,12 +225,11 @@ EXPORT_SYMBOL(smp_call_function_single); * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int -smp_call_function_mask(cpumask_t mask, - void (*func)(void *), void *info, - int wait) +int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info, + int wait) { preempt_disable(); + cpu_clear(smp_processor_id(), mask); __smp_call_function_map(func, info, 0, wait, mask); preempt_enable(); return 0; @@ -1008,7 +1007,7 @@ static struct notifier_block __cpuinitdata smp_cpu_nb = { .notifier_call = smp_cpu_notify, }; -static int smp_add_present_cpu(int cpu) +static int __devinit smp_add_present_cpu(int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; @@ -1036,8 +1035,8 @@ out: } #ifdef CONFIG_HOTPLUG_CPU -static ssize_t rescan_store(struct sys_device *dev, const char *buf, - size_t count) +static ssize_t __ref rescan_store(struct sys_device *dev, + const char *buf, size_t count) { cpumask_t newcpus; int cpu; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index da692472996..85e46a5d0e0 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -14,7 +14,8 @@ static unsigned long save_context_stack(struct stack_trace *trace, unsigned long sp, unsigned long low, - unsigned long high) + unsigned long high, + int savesched) { struct stack_frame *sf; struct pt_regs *regs; @@ -47,10 +48,12 @@ static unsigned long save_context_stack(struct stack_trace *trace, return sp; regs = (struct pt_regs *)sp; addr = regs->psw.addr & PSW_ADDR_INSN; - if (!trace->skip) - trace->entries[trace->nr_entries++] = addr; - else - trace->skip--; + if (savesched || !in_sched_functions(addr)) { + if (!trace->skip) + trace->entries[trace->nr_entries++] = addr; + else + trace->skip--; + } if (trace->nr_entries >= trace->max_entries) return sp; low = sp; @@ -66,15 +69,27 @@ void save_stack_trace(struct stack_trace *trace) orig_sp = sp & PSW_ADDR_INSN; new_sp = save_context_stack(trace, orig_sp, S390_lowcore.panic_stack - PAGE_SIZE, - S390_lowcore.panic_stack); + S390_lowcore.panic_stack, 1); if (new_sp != orig_sp) return; new_sp = save_context_stack(trace, new_sp, S390_lowcore.async_stack - ASYNC_SIZE, - S390_lowcore.async_stack); + S390_lowcore.async_stack, 1); if (new_sp != orig_sp) return; save_context_stack(trace, new_sp, S390_lowcore.thread_info, - S390_lowcore.thread_info + THREAD_SIZE); + S390_lowcore.thread_info + THREAD_SIZE, 1); +} + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + unsigned long sp, low, high; + + sp = tsk->thread.ksp & PSW_ADDR_INSN; + low = (unsigned long) task_stack_page(tsk); + high = (unsigned long) task_pt_regs(tsk); + save_context_stack(trace, sp, low, high, 0); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; } diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9e26ed9fe4e..25eac7802fc 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -325,5 +325,5 @@ SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper) SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper) SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */ SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper) -SYSCALL(sys_timerfd,sys_timerfd,compat_sys_timerfd_wrapper) +NI_SYSCALL /* 317 old sys_timer_fd */ SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 52b8342c6bf..1a2fdb6991d 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -271,7 +271,10 @@ void die(const char * str, struct pt_regs * regs, long err) printk("PREEMPT "); #endif #ifdef CONFIG_SMP - printk("SMP"); + printk("SMP "); +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + printk("DEBUG_PAGEALLOC"); #endif printk("\n"); notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 7d43c3cd3ef..b4607155e8d 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -35,7 +35,7 @@ SECTIONS KPROBES_TEXT *(.fixup) *(.gnu.warning) - } = 0x0700 + } :text = 0x0700 _etext = .; /* End of text section */ diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index b234bb4a6da..983ec6ec0e7 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -167,6 +167,33 @@ void __init mem_init(void) PFN_ALIGN((unsigned long)&_eshared) - 1); } +#ifdef CONFIG_DEBUG_PAGEALLOC +void kernel_map_pages(struct page *page, int numpages, int enable) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + unsigned long address; + int i; + + for (i = 0; i < numpages; i++) { + address = page_to_phys(page + i); + pgd = pgd_offset_k(address); + pud = pud_offset(pgd, address); + pmd = pmd_offset(pud, address); + pte = pte_offset_kernel(pmd, address); + if (!enable) { + ptep_invalidate(address, pte); + continue; + } + *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); + /* Flush cpu write queue. */ + mb(); + } +} +#endif + void free_initmem(void) { unsigned long addr; diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 79d13a166a3..7c1287ccf78 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -62,7 +62,7 @@ void __meminit memmap_init(unsigned long size, int nid, unsigned long zone, } } -static void __init_refok *vmem_alloc_pages(unsigned int order) +static void __ref *vmem_alloc_pages(unsigned int order) { if (slab_is_available()) return (void *)__get_free_pages(GFP_KERNEL, order); @@ -250,7 +250,7 @@ static int insert_memory_segment(struct memory_segment *seg) { struct memory_segment *tmp; - if (seg->start + seg->size >= VMALLOC_START || + if (seg->start + seg->size >= VMEM_MAX_PHYS || seg->start + seg->size < seg->start) return -ERANGE; @@ -360,7 +360,6 @@ void __init vmem_map_init(void) { int i; - BUILD_BUG_ON((unsigned long)VMEM_MAP + VMEM_MAP_SIZE > VMEM_MAP_MAX); NODE_DATA(0)->node_mem_map = VMEM_MAP; for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 55722840859..ee010f4532a 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -79,7 +79,7 @@ sys_call_table: /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare /*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy /*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait -/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate +/*310*/ .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 070a4846c0c..4b9115a4d92 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c @@ -580,7 +580,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, /* Step 1: Prepare scatter list. */ - npages = prepare_sg(sglist, nelems); + npages = prepare_sg(dev, sglist, nelems); /* Step 2: Allocate a cluster and context, if necessary. */ diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c index efd5dff85f6..72a4acfe8c7 100644 --- a/arch/sparc64/kernel/iommu_common.c +++ b/arch/sparc64/kernel/iommu_common.c @@ -4,6 +4,7 @@ * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ +#include <linux/dma-mapping.h> #include "iommu_common.h" /* You are _strongly_ advised to enable the following debugging code @@ -201,21 +202,24 @@ void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int np } #endif -unsigned long prepare_sg(struct scatterlist *sg, int nents) +unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents) { struct scatterlist *dma_sg = sg; unsigned long prev; u32 dent_addr, dent_len; + unsigned int max_seg_size; prev = (unsigned long) sg_virt(sg); prev += (unsigned long) (dent_len = sg->length); dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); + max_seg_size = dma_get_max_seg_size(dev); while (--nents) { unsigned long addr; sg = sg_next(sg); addr = (unsigned long) sg_virt(sg); - if (! VCONTIG(prev, addr)) { + if (! VCONTIG(prev, addr) || + dent_len + sg->length > max_seg_size) { dma_sg->dma_address = dent_addr; dma_sg->dma_length = dent_len; dma_sg = sg_next(dma_sg); diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h index 75b5a581452..a90d046e802 100644 --- a/arch/sparc64/kernel/iommu_common.h +++ b/arch/sparc64/kernel/iommu_common.h @@ -9,6 +9,7 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/scatterlist.h> +#include <linux/device.h> #include <asm/iommu.h> #include <asm/scatterlist.h> @@ -46,4 +47,4 @@ extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int #define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) -extern unsigned long prepare_sg(struct scatterlist *sg, int nents); +extern unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 1aa8e044b10..5ea2eab1ccd 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -490,7 +490,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, goto bad; /* Step 1: Prepare scatter list. */ - npages = prepare_sg(sglist, nelems); + npages = prepare_sg(dev, sglist, nelems); /* Step 2: Allocate a cluster and context, if necessary. */ spin_lock_irqsave(&iommu->lock, flags); @@ -625,8 +625,8 @@ static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm) /* XXX register error interrupt handlers XXX */ } -static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, - struct iommu *iommu) +static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm, + struct iommu *iommu) { struct iommu_arena *arena = &iommu->arena; unsigned long i, cnt = 0; @@ -653,7 +653,7 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, return cnt; } -static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) +static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; struct property *prop; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 06d10907d8c..b8058906e72 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -80,7 +80,7 @@ sys_call_table32: .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare /*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait -/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate +/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate #endif /* CONFIG_COMPAT */ @@ -152,7 +152,7 @@ sys_call_table: .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare /*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait -/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate +/*310*/ .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 55945db1313..99e51d059a0 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -68,6 +68,10 @@ config IRQ_RELEASE_METHOD bool default y +config HZ + int + default 100 + menu "UML-specific options" config STATIC_LINK @@ -95,23 +99,6 @@ config LD_SCRIPT_DYN default y depends on !LD_SCRIPT_STATIC -config NET - bool "Networking support" - help - Unless you really know what you are doing, you should say Y here. - The reason is that some programs need kernel networking support even - when running on a stand-alone machine that isn't connected to any - other computer. If you are upgrading from an older kernel, you - should consider updating your networking tools too because changes - in the kernel and the tools often go hand in hand. The tools are - contained in the package net-tools, the location and version number - of which are given in <file:Documentation/Changes>. - - For a general introduction to Linux networking, it is highly - recommended to read the NET-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - source "fs/Kconfig.binfmt" config HOSTFS @@ -145,7 +132,7 @@ config HPPFS by removing or changing anything in /proc which gives away the identity of a UML. - See <http://user-mode-linux.sf.net/hppfs.html> for more information. + See <http://user-mode-linux.sf.net/old/hppfs.html> for more information. You only need this if you are setting up a UML honeypot. Otherwise, it is safe to say 'N' here. @@ -189,8 +176,7 @@ config MAGIC_SYSRQ config SMP bool "Symmetric multi-processing support (EXPERIMENTAL)" default n - #SMP_BROKEN is for x86_64. - depends on EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN)) + depends on BROKEN help This option enables UML SMP support. It is NOT related to having a real SMP box. Not directly, at least. diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char index 9a78d354f0b..3a4b396d797 100644 --- a/arch/um/Kconfig.char +++ b/arch/um/Kconfig.char @@ -18,7 +18,7 @@ config SSL lines on the UML that are usually made to show up on the host as ttys or ptys. - See <http://user-mode-linux.sourceforge.net/input.html> for more + See <http://user-mode-linux.sourceforge.net/old/input.html> for more information and command line examples of how to use this facility. Unless you have a specific reason for disabling this, say Y. diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 1f6462ffd3e..8fce5e536b0 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -4,12 +4,12 @@ source "lib/Kconfig.debug" config GPROF bool "Enable gprof support" - depends on DEBUG_INFO + depends on DEBUG_INFO && FRAME_POINTER help This allows profiling of a User-Mode Linux kernel with the gprof utility. - See <http://user-mode-linux.sourceforge.net/gprof.html> for more + See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more details. If you're involved in UML kernel development and want to use gprof, @@ -22,7 +22,7 @@ config GCOV This option allows developers to retrieve coverage data from a UML session. - See <http://user-mode-linux.sourceforge.net/gprof.html> for more + See <http://user-mode-linux.sourceforge.net/old/gprof.html> for more details. If you're involved in UML kernel development and want to use gcov, diff --git a/arch/um/Kconfig.net b/arch/um/Kconfig.net index 66e50026ade..9e9a4aaa703 100644 --- a/arch/um/Kconfig.net +++ b/arch/um/Kconfig.net @@ -14,7 +14,7 @@ config UML_NET For more information, including explanations of the networking and sample configurations, see - <http://user-mode-linux.sourceforge.net/networking.html>. + <http://user-mode-linux.sourceforge.net/old/networking.html>. If you'd like to be able to enable networking in the User-Mode linux environment, say Y; otherwise say N. Note that you must @@ -38,7 +38,7 @@ config UML_NET_ETHERTAP CONFIG_NETLINK_DEV configured as Y or M. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Ethertap networking. @@ -72,7 +72,7 @@ config UML_NET_SLIP To use this, your host must support slip devices. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html>. That site + <http://user-mode-linux.sourceforge.net/old/networking.html>. has examples of the UML command line to use to enable slip networking, and details of a few quirks with it. @@ -96,7 +96,7 @@ config UML_NET_DAEMON networking daemon on the host. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Daemon networking. @@ -144,7 +144,7 @@ config UML_NET_MCAST To use this, your host kernel(s) must support IP Multicasting. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable Multicast networking, and notes about the security of this approach. @@ -165,7 +165,7 @@ config UML_NET_PCAP installed in order to build the pcap transport into UML. For more information, see - <http://user-mode-linux.sourceforge.net/networking.html> That site + <http://user-mode-linux.sourceforge.net/old/networking.html> That site has examples of the UML command line to use to enable this option. If you intend to use UML as a network monitor for the host, say diff --git a/arch/um/Makefile b/arch/um/Makefile index ba6813a4aa3..cb4af9bf207 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -49,7 +49,7 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) # # These apply to USER_CFLAGS to. -KBUILD_CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ +KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ -Din6addr_loopback=kernel_in6addr_loopback \ -Din6addr_any=kernel_in6addr_any @@ -58,7 +58,7 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\ $(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \ - -D_FILE_OFFSET_BITS=64 + $(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH) @@ -130,7 +130,9 @@ CPPFLAGS_vmlinux.lds = -U$(SUBARCH) -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ # The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc -CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) +LD_FLAGS_CMDLINE = $(foreach opt,$(LDFLAGS),-Wl,$(opt)) + +CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS) $(LD_FLAGS_CMDLINE) define cmd_vmlinux__ $(CC) $(CFLAGS_vmlinux) -o $@ \ -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ @@ -158,7 +160,7 @@ ifneq ($(KBUILD_SRC),) $(Q)mkdir -p $(objtree)/include/asm-um $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ else - $(Q)cd $(TOPDIR)/$(dir $@) ; \ + $(Q)cd $(srctree)/$(dir $@) ; \ ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) endif @@ -168,7 +170,7 @@ ifneq ($(KBUILD_SRC),) $(Q)mkdir -p $(objtree)/include/asm-um $(Q)ln -fsn $(srctree)/include/asm-$(HEADER_ARCH) include/asm-um/arch else - $(Q)cd $(TOPDIR)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch + $(Q)cd $(srctree)/include/asm-um && ln -fsn ../asm-$(HEADER_ARCH) arch endif $(objtree)/$(ARCH_DIR)/include: diff --git a/arch/um/Makefile-tt b/arch/um/Makefile-tt deleted file mode 100644 index 03f7b10cfd0..00000000000 --- a/arch/um/Makefile-tt +++ /dev/null @@ -1,5 +0,0 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - diff --git a/arch/um/defconfig b/arch/um/defconfig index f609edede06..86db2862f22 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -77,7 +77,7 @@ CONFIG_LD_SCRIPT_DYN=y CONFIG_NET=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m -# CONFIG_HOSTFS is not set +CONFIG_HOSTFS=y # CONFIG_HPPFS is not set CONFIG_MCONSOLE=y CONFIG_MAGIC_SYSRQ=y @@ -188,7 +188,7 @@ CONFIG_CON_CHAN="xterm" CONFIG_SSL_CHAN="pts" CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LEGACY_PTY_COUNT=32 # CONFIG_WATCHDOG is not set CONFIG_UML_SOUND=m CONFIG_SOUND=m @@ -508,7 +508,7 @@ CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set -CONFIG_DEBUG_SLAB=y +# CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SLAB_LEAK is not set # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_SPINLOCK is not set diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 83bf15a3dda..2c898c4d6b6 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -8,6 +8,7 @@ #include "chan_kern.h" #include "irq_kern.h" #include "irq_user.h" +#include "kern_util.h" #include "os.h" #define LINE_BUFSIZE 4096 @@ -48,7 +49,7 @@ static int write_room(struct line *line) n = line->head - line->tail; if (n <= 0) - n = LINE_BUFSIZE + n; /* The other case */ + n += LINE_BUFSIZE; /* The other case */ return n - 1; } @@ -58,17 +59,10 @@ int line_write_room(struct tty_struct *tty) unsigned long flags; int room; - if (tty->stopped) - return 0; - spin_lock_irqsave(&line->lock, flags); room = write_room(line); spin_unlock_irqrestore(&line->lock, flags); - /*XXX: Warning to remove */ - if (0 == room) - printk(KERN_DEBUG "%s: %s: no room left in buffer\n", - __FUNCTION__,tty->name); return room; } @@ -79,8 +73,7 @@ int line_chars_in_buffer(struct tty_struct *tty) int ret; spin_lock_irqsave(&line->lock, flags); - - /*write_room subtracts 1 for the needed NULL, so we readd it.*/ + /* write_room subtracts 1 for the needed NULL, so we readd it.*/ ret = LINE_BUFSIZE - (write_room(line) + 1); spin_unlock_irqrestore(&line->lock, flags); @@ -184,10 +177,6 @@ void line_flush_buffer(struct tty_struct *tty) unsigned long flags; int err; - /*XXX: copied from line_write, verify if it is correct!*/ - if (tty->stopped) - return; - spin_lock_irqsave(&line->lock, flags); err = flush_buffer(line); spin_unlock_irqrestore(&line->lock, flags); @@ -213,9 +202,6 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len) unsigned long flags; int n, ret = 0; - if (tty->stopped) - return 0; - spin_lock_irqsave(&line->lock, flags); if (line->head != line->tail) ret = buffer_data(line, buf, len); @@ -788,9 +774,11 @@ static irqreturn_t winch_interrupt(int irq, void *data) tty = winch->tty; if (tty != NULL) { line = tty->driver_data; - chan_window_size(&line->chan_list, &tty->winsize.ws_row, - &tty->winsize.ws_col); - kill_pgrp(tty->pgrp, SIGWINCH, 1); + if (line != NULL) { + chan_window_size(&line->chan_list, &tty->winsize.ws_row, + &tty->winsize.ws_col); + kill_pgrp(tty->pgrp, SIGWINCH, 1); + } } out: if (winch->fd != -1) diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 0f3c7d14a6e..ebb265c07e4 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -1,23 +1,25 @@ /* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) - * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/console.h" -#include "linux/ctype.h" -#include "linux/interrupt.h" -#include "linux/list.h" -#include "linux/mm.h" -#include "linux/module.h" -#include "linux/notifier.h" -#include "linux/reboot.h" -#include "linux/proc_fs.h" -#include "linux/slab.h" -#include "linux/syscalls.h" -#include "linux/utsname.h" -#include "linux/workqueue.h" -#include "asm/uaccess.h" +#include <linux/console.h> +#include <linux/ctype.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <linux/syscalls.h> +#include <linux/utsname.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <asm/uaccess.h> + #include "init.h" #include "irq_kern.h" #include "irq_user.h" @@ -305,7 +307,9 @@ void mconsole_stop(struct mc_request *req) deactivate_fd(req->originating_fd, MCONSOLE_IRQ); os_set_fd_block(req->originating_fd, 1); mconsole_reply(req, "stopped", 0, 0); - while (mconsole_get_request(req->originating_fd, req)) { + for (;;) { + if (!mconsole_get_request(req->originating_fd, req)) + continue; if (req->cmd->handler == mconsole_go) break; if (req->cmd->handler == mconsole_stop) { @@ -358,7 +362,7 @@ struct unplugged_pages { void *pages[UNPLUGGED_PER_PAGE]; }; -static DECLARE_MUTEX(plug_mem_mutex); +static DEFINE_MUTEX(plug_mem_mutex); static unsigned long long unplugged_pages_count = 0; static LIST_HEAD(unplugged_pages); static int unplug_index = UNPLUGGED_PER_PAGE; @@ -394,7 +398,7 @@ static int mem_config(char *str, char **error_out) diff /= PAGE_SIZE; - down(&plug_mem_mutex); + mutex_lock(&plug_mem_mutex); for (i = 0; i < diff; i++) { struct unplugged_pages *unplugged; void *addr; @@ -451,7 +455,7 @@ static int mem_config(char *str, char **error_out) err = 0; out_unlock: - up(&plug_mem_mutex); + mutex_unlock(&plug_mem_mutex); out: return err; } @@ -741,7 +745,6 @@ void mconsole_stack(struct mc_request *req) { char *ptr = req->request.data; int pid_requested= -1; - struct task_struct *from = NULL; struct task_struct *to = NULL; /* @@ -763,9 +766,7 @@ void mconsole_stack(struct mc_request *req) return; } - from = current; - - to = find_task_by_pid(pid_requested); + to = find_task_by_pid_ns(pid_requested, &init_pid_ns); if ((to == NULL) || (pid_requested == 0)) { mconsole_reply(req, "Couldn't find that pid", 1, 0); return; @@ -795,6 +796,8 @@ static int __init mconsole_init(void) printk(KERN_ERR "Failed to initialize management console\n"); return 1; } + if (os_set_fd_block(sock, 0)) + goto out; register_reboot_notifier(&reboot_notifier); @@ -803,7 +806,7 @@ static int __init mconsole_init(void) "mconsole", (void *)sock); if (err) { printk(KERN_ERR "Failed to get IRQ for management console\n"); - return 1; + goto out; } if (notify_socket != NULL) { @@ -819,6 +822,10 @@ static int __init mconsole_init(void) printk(KERN_INFO "mconsole (version %d) initialized on %s\n", MCONSOLE_VERSION, mconsole_socket_name); return 0; + + out: + os_close_file(sock); + return 1; } __initcall(mconsole_init); diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 430c024a19b..13af2f03ed8 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -83,9 +83,8 @@ int mconsole_get_request(int fd, struct mc_request *req) int len; req->originlen = sizeof(req->origin); - req->len = recvfrom(fd, &req->request, sizeof(req->request), - MSG_DONTWAIT, (struct sockaddr *) req->origin, - &req->originlen); + req->len = recvfrom(fd, &req->request, sizeof(req->request), 0, + (struct sockaddr *) req->origin, &req->originlen); if (req->len < 0) return 0; diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 3c6c44ca1ff..1e8f41a9951 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -318,7 +318,7 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name) if (str == NULL) goto random; - for (i = 0;i < 6; i++) { + for (i = 0; i < 6; i++) { addr[i] = simple_strtoul(str, &end, 16); if ((end == str) || ((*end != ':') && (*end != ',') && (*end != '\0'))) { @@ -343,14 +343,13 @@ static void setup_etheraddr(char *str, unsigned char *addr, char *name) } if (!is_local_ether_addr(addr)) { printk(KERN_WARNING - "Warning: attempt to assign a globally valid ethernet " + "Warning: Assigning a globally valid ethernet " "address to a device\n"); - printk(KERN_WARNING "You should better enable the 2nd " - "rightmost bit in the first byte of the MAC,\n"); + printk(KERN_WARNING "You should set the 2nd rightmost bit in " + "the first byte of the MAC,\n"); printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n", addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4], addr[5]); - goto random; } return; @@ -368,7 +367,6 @@ static struct platform_driver uml_net_driver = { .name = DRIVER_NAME, }, }; -static int driver_registered; static void net_device_release(struct device *dev) { @@ -383,6 +381,12 @@ static void net_device_release(struct device *dev) free_netdev(netdev); } +/* + * Ensures that platform_driver_register is called only once by + * eth_configure. Will be set in an initcall. + */ +static int driver_registered; + static void eth_configure(int n, void *init, char *mac, struct transport *transport) { diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 29185cad9ff..abf2653f551 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -201,7 +201,7 @@ static int change_tramp(char **argv, char *output, int output_len) close(fds[1]); if (pid > 0) - helper_wait(pid, 0, "change_tramp"); + helper_wait(pid); return pid; } diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 330543b3129..19930081d3d 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c @@ -6,6 +6,7 @@ #include "linux/completion.h" #include "linux/interrupt.h" #include "linux/list.h" +#include "linux/mutex.h" #include "asm/atomic.h" #include "init.h" #include "irq_kern.h" @@ -120,7 +121,7 @@ static int port_accept(struct port_list *port) return 0; } -static DECLARE_MUTEX(ports_sem); +static DEFINE_MUTEX(ports_mutex); static LIST_HEAD(ports); static void port_work_proc(struct work_struct *unused) @@ -161,7 +162,7 @@ void *port_data(int port_num) struct port_dev *dev = NULL; int fd; - down(&ports_sem); + mutex_lock(&ports_mutex); list_for_each(ele, &ports) { port = list_entry(ele, struct port_list, list); if (port->port == port_num) @@ -216,7 +217,7 @@ void *port_data(int port_num) out_free: kfree(port); out: - up(&ports_sem); + mutex_unlock(&ports_mutex); return dev; } diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index e942e836f99..71f0959c153 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -5,6 +5,7 @@ * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. */ +#include <linux/sched.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/miscdevice.h> diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index b8711e50da8..8b80505a3fb 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -109,7 +109,7 @@ static int slip_tramp(char **argv, int fd) read_output(fds[0], output, output_len); printk("%s", output); - err = helper_wait(pid, 0, argv[0]); + err = helper_wait(pid); close(fds[0]); out_free: diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index 89c1be225fd..a0ada8fec72 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -98,7 +98,7 @@ static void slirp_close(int fd, void *data) "(%d)\n", pri->pid, errno); } #endif - err = helper_wait(pri->pid, 1, "slirp_close"); + err = helper_wait(pri->pid); if (err < 0) return; diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 875d60d0c6a..f1786e64607 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -15,7 +15,6 @@ #include "line.h" #include "ssl.h" #include "chan_kern.h" -#include "kern_util.h" #include "kern.h" #include "init.h" #include "irq_user.h" diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 656036e90b1..cec0c33cdd3 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -22,7 +22,6 @@ #include "stdio_console.h" #include "line.h" #include "chan_kern.h" -#include "kern_util.h" #include "irq_user.h" #include "mconsole_kern.h" #include "init.h" diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 99f9f9605e9..be3a2797dac 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -49,6 +49,7 @@ #include "irq_user.h" #include "irq_kern.h" #include "ubd_user.h" +#include "kern_util.h" #include "os.h" #include "mem.h" #include "mem_kern.h" @@ -229,7 +230,7 @@ static int proc_ide_read_media(char *page, char **start, off_t off, int count, return len; } -static void make_ide_entries(char *dev_name) +static void make_ide_entries(const char *dev_name) { struct proc_dir_entry *dir, *ent; char name[64]; @@ -244,7 +245,7 @@ static void make_ide_entries(char *dev_name) ent->data = NULL; ent->read_proc = proc_ide_read_media; ent->write_proc = NULL; - sprintf(name,"ide0/%s", dev_name); + snprintf(name, sizeof(name), "ide0/%s", dev_name); proc_symlink(dev_name, proc_ide_root, name); } @@ -437,7 +438,10 @@ __uml_help(ubd_setup, " machine by running 'dd' on the device. <n> must be in the range\n" " 0 to 7. Appending an 'r' to the number will cause that device\n" " to be mounted read-only. For example ubd1r=./ext_fs. Appending\n" -" an 's' will cause data to be written to disk on the host immediately.\n\n" +" an 's' will cause data to be written to disk on the host immediately.\n" +" 'c' will cause the device to be treated as being shared between multiple\n" +" UMLs and file locking will be turned off - this is appropriate for a\n" +" cluster filesystem and inappropriate at almost all other times.\n\n" ); static int udb_setup(char *str) @@ -456,20 +460,6 @@ __uml_help(udb_setup, " in the boot output.\n\n" ); -static int fakehd_set = 0; -static int fakehd(char *str) -{ - printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n"); - fakehd_set = 1; - return 1; -} - -__setup("fakehd", fakehd); -__uml_help(fakehd, -"fakehd\n" -" Change the ubd device name to \"hd\".\n\n" -); - static void do_ubd_request(struct request_queue * q); /* Only changed by ubd_init, which is an initcall. */ @@ -718,8 +708,10 @@ static int ubd_add(int n, char **error_out) ubd_disk_register(fake_major, ubd_dev->size, n, &fake_gendisk[n]); - /* perhaps this should also be under the "if (fake_major)" above */ - /* using the fake_disk->disk_name and also the fakehd_set name */ + /* + * Perhaps this should also be under the "if (fake_major)" above + * using the fake_disk->disk_name + */ if (fake_ide) make_ide_entries(ubd_gendisk[n]->disk_name); diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 48fc7452bc1..b591bb9c41d 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -16,7 +16,6 @@ #include <sys/mman.h> #include <sys/param.h> #include "asm/types.h" -#include "kern_util.h" #include "user.h" #include "ubd_user.h" #include "os.h" diff --git a/arch/um/drivers/vde_user.c b/arch/um/drivers/vde_user.c index d9941fe5f93..56533db2534 100644 --- a/arch/um/drivers/vde_user.c +++ b/arch/um/drivers/vde_user.c @@ -80,7 +80,7 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init) vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL); if (vpri->args == NULL) { - printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args" + printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args " "allocation failed"); return; } diff --git a/arch/um/include/arch.h b/arch/um/include/arch.h index 49c601ff2ba..2de92a08a76 100644 --- a/arch/um/include/arch.h +++ b/arch/um/include/arch.h @@ -10,6 +10,6 @@ extern void arch_check_bugs(void); extern int arch_fixup(unsigned long address, struct uml_pt_regs *regs); -extern int arch_handle_signal(int sig, struct uml_pt_regs *regs); +extern void arch_examine_signal(int sig, struct uml_pt_regs *regs); #endif diff --git a/arch/um/include/as-layout.h b/arch/um/include/as-layout.h index a5cdf953e04..606bb5c7fdf 100644 --- a/arch/um/include/as-layout.h +++ b/arch/um/include/as-layout.h @@ -10,23 +10,31 @@ #include "kern_constants.h" /* - * Assembly doesn't want any casting, but C does, so define these - * without casts here, and define new symbols with casts inside the C - * section. + * Stolen from linux/const.h, which can't be directly included since + * this is used in userspace code, which has no access to the kernel + * headers. Changed to be suitable for adding casts to the start, + * rather than "UL" to the end. */ -#define ASM_STUB_CODE (UML_CONFIG_TOP_ADDR - 2 * UM_KERN_PAGE_SIZE) -#define ASM_STUB_DATA (UML_CONFIG_TOP_ADDR - UM_KERN_PAGE_SIZE) -#define ASM_STUB_START ASM_STUB_CODE -/* - * This file is included by the assembly stubs, which just want the - * definitions above. +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specifiers unilaterally. We + * use the following macros to deal with this. */ -#ifndef __ASSEMBLY__ -#define STUB_CODE ((unsigned long) ASM_STUB_CODE) -#define STUB_DATA ((unsigned long) ASM_STUB_DATA) -#define STUB_START ((unsigned long) ASM_STUB_START) +#ifdef __ASSEMBLY__ +#define _AC(X, Y) (Y) +#else +#define __AC(X, Y) (X (Y)) +#define _AC(X, Y) __AC(X, Y) +#endif + +#define STUB_START _AC(, 0x100000) +#define STUB_CODE _AC((unsigned long), STUB_START) +#define STUB_DATA _AC((unsigned long), STUB_CODE + UM_KERN_PAGE_SIZE) +#define STUB_END _AC((unsigned long), STUB_DATA + UM_KERN_PAGE_SIZE) + +#ifndef __ASSEMBLY__ #include "sysdep/ptrace.h" diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index 5a2263e05bb..9b9ced85b70 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -48,7 +48,7 @@ extern void register_winch_irq(int fd, int tty_fd, int pid, #define __channel_help(fn, prefix) \ __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ " Attach a console or serial line to a host channel. See\n" \ -" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \ +" http://user-mode-linux.sourceforge.net/old/input.html for a complete\n" \ " description of this switch.\n\n" \ ); diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 0edab695ed4..b54bd35585c 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -18,6 +18,7 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING); DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); DEFINE_STR(UM_KERN_INFO, KERN_INFO); DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); +DEFINE_STR(UM_KERN_CONT, KERN_CONT); DEFINE(UM_ELF_CLASS, ELF_CLASS); DEFINE(UM_ELFCLASS32, ELFCLASS32); diff --git a/arch/um/include/init.h b/arch/um/include/init.h index cebc6cae919..b00a95741d4 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/init.h @@ -40,6 +40,20 @@ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void); +#ifndef __KERNEL__ +#ifndef __section +# define __section(S) __attribute__ ((__section__(#S))) +#endif + +#if __GNUC_MINOR__ >= 3 +# define __used __attribute__((__used__)) +#else +# define __used __attribute__((__unused__)) +#endif + +#else +#include <linux/compiler.h> +#endif /* These are for everybody (although not all archs will actually discard it in modules) */ #define __init __section(.init.text) @@ -127,14 +141,3 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; #endif #endif /* _LINUX_UML_INIT_H */ - -/* - * 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/include/irq_user.h b/arch/um/include/irq_user.h index 884a9c17eea..e60b31873de 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h @@ -14,7 +14,6 @@ struct irq_fd { int fd; int type; int irq; - int pid; int events; int current_events; }; diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 74ce8e5370a..3c341222d25 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -9,107 +9,61 @@ #include "sysdep/ptrace.h" #include "sysdep/faultinfo.h" -typedef void (*kern_hndl)(int, struct uml_pt_regs *); - -struct kern_handlers { - kern_hndl relay_signal; - kern_hndl winch; - kern_hndl bus_handler; - kern_hndl page_fault; - kern_hndl sigio_handler; - kern_hndl timer_handler; -}; - -extern const struct kern_handlers handlinfo_kern; +extern int uml_exitcode; extern int ncpus; -extern char *gdb_init; extern int kmalloc_ok; -extern int jail; -extern int nsyscalls; -#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) #define UML_ROUND_UP(addr) \ - UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) + ((((unsigned long) addr) + PAGE_SIZE - 1) & PAGE_MASK) -extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); -extern int kernel_thread_proc(void *data); -extern void syscall_segv(int sig); -extern int current_pid(void); extern unsigned long alloc_stack(int order, int atomic); +extern void free_stack(unsigned long stack, int order); + extern int do_signal(void); -extern int is_stack_fault(unsigned long sp); +extern void copy_sc(struct uml_pt_regs *regs, void *from); +extern void interrupt_end(void); +extern void relay_signal(int sig, struct uml_pt_regs *regs); + extern unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, struct uml_pt_regs *regs); extern int handle_page_fault(unsigned long address, unsigned long ip, int is_write, int is_user, int *code_out); -extern void syscall_ready(void); -extern void set_tracing(void *t, int tracing); -extern int is_tracing(void *task); -extern int segv_syscall(void); -extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); -extern unsigned long page_mask(void); -extern int need_finish_fork(void); -extern void free_stack(unsigned long stack, int order); -extern void add_input_request(int op, void (*proc)(int), void *arg); -extern char *current_cmd(void); -extern void timer_handler(int sig, struct uml_pt_regs *regs); -extern int set_signals(int enable); -extern int pid_to_processor_id(int pid); -extern void deliver_signals(void *t); -extern int next_trap_index(int max); -extern void default_idle(void); -extern void finish_fork(void); -extern void paging_init(void); -extern void init_flush_vm(void); -extern void *syscall_sp(void *t); -extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); + extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); -extern void interrupt_end(void); -extern void initial_thread_cb(void (*proc)(void *), void *arg); -extern int debugger_signal(int status, int pid); -extern void debugger_parent_signal(int status, int pid); -extern void child_signal(int pid, int status); -extern int init_ptrace_proxy(int idle_pid, int startup, int stop); -extern int init_parent_proxy(int pid); -extern int singlestepping(void *t); -extern void check_stack_overflow(void *ptr); -extern void relay_signal(int sig, struct uml_pt_regs *regs); -extern int user_context(unsigned long sp); -extern void timer_irq(struct uml_pt_regs *regs); -extern void do_uml_exitcalls(void); -extern int attach_debugger(int idle_pid, int pid, int stop); -extern int config_gdb(char *str); -extern int remove_gdb(void); -extern char *uml_strdup(char *string); -extern void unprotect_kernel_mem(void); -extern void protect_kernel_mem(void); -extern void uml_cleanup(void); -extern void lock_signalled_task(void *t); -extern void IPI_handler(int cpu); -extern int jail_setup(char *line, int *add); -extern void *get_init_task(void); -extern int clear_user_proc(void *buf, int size); -extern int copy_to_user_proc(void *to, void *from, int size); -extern int copy_from_user_proc(void *to, void *from, int size); -extern int strlen_user_proc(char *str); -extern long execute_syscall(void *r); extern int smp_sigio_handler(void); -extern void *get_current(void); -extern struct task_struct *get_task(int pid, int require); -extern void machine_halt(void); +extern void initial_thread_cb(void (*proc)(void *), void *arg); extern int is_syscall(unsigned long addr); +extern void timer_handler(int sig, struct uml_pt_regs *regs); -extern void free_irq(unsigned int, void *); -extern int cpu(void); +extern void timer_handler(int sig, struct uml_pt_regs *regs); -extern void time_init_kern(void); +extern int start_uml(void); +extern void paging_init(void); -/* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */ +extern void uml_cleanup(void); +extern void do_uml_exitcalls(void); + +/* + * Are we disallowed to sleep? Used to choose between GFP_KERNEL and + * GFP_ATOMIC. + */ extern int __cant_sleep(void); -extern void sigio_handler(int sig, struct uml_pt_regs *regs); -extern void copy_sc(struct uml_pt_regs *regs, void *from); +extern void *get_current(void); +extern int copy_from_user_proc(void *to, void *from, int size); +extern int cpu(void); +extern char *uml_strdup(const char *string); + extern unsigned long to_irq_stack(unsigned long *mask_out); -unsigned long from_irq_stack(int nested); -extern int start_uml(void); +extern unsigned long from_irq_stack(int nested); + +extern void syscall_trace(struct uml_pt_regs *regs, int entryexit); +extern int singlestepping(void *t); + +extern void segv_handler(int sig, struct uml_pt_regs *regs); +extern void bus_handler(int sig, struct uml_pt_regs *regs); +extern void winch(int sig, struct uml_pt_regs *regs); +extern void fatal_sigsegv(void) __attribute__ ((noreturn)); + + #endif diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index a54514d2cc3..46384acd547 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -46,9 +46,6 @@ extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) -extern unsigned long host_task_size; -extern unsigned long task_size; - extern int init_mem_user(void); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); @@ -59,9 +56,7 @@ extern void setup_physmem(unsigned long start, unsigned long usable, unsigned long len, unsigned long long highmem); extern void add_iomem(char *name, int fd, unsigned long size); extern unsigned long phys_offset(unsigned long phys); -extern void unmap_physmem(void); extern void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x); -extern unsigned long get_kmem_end(void); #endif diff --git a/arch/um/include/misc_constants.h b/arch/um/include/misc_constants.h deleted file mode 100644 index 989bc08de36..00000000000 --- a/arch/um/include/misc_constants.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __MISC_CONSTANT_H_ -#define __MISC_CONSTANT_H_ - -#include <user_constants.h> - -#endif diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 6f0d1c741bc..0b6b6273330 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -8,7 +8,6 @@ #include <stdarg.h> #include "irq_user.h" -#include "kern_util.h" #include "longjmp.h" #include "mm_id.h" #include "sysdep/tls.h" @@ -128,33 +127,31 @@ static inline struct openflags of_cloexec(struct openflags flags) extern int os_stat_file(const char *file_name, struct uml_stat *buf); extern int os_stat_fd(const int fd, struct uml_stat *buf); extern int os_access(const char *file, int mode); -extern int os_get_exec_close(int fd, int *close_on_exec); extern int os_set_exec_close(int fd); extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); extern int os_get_ifname(int fd, char *namebuf); extern int os_set_slip(int fd); -extern int os_set_owner(int fd, int pid); extern int os_mode_fd(int fd, int mode); extern int os_seek_file(int fd, unsigned long long offset); -extern int os_open_file(char *file, struct openflags flags, int mode); +extern int os_open_file(const char *file, struct openflags flags, int mode); extern int os_read_file(int fd, void *buf, int len); extern int os_write_file(int fd, const void *buf, int count); -extern int os_file_size(char *file, unsigned long long *size_out); -extern int os_file_modtime(char *file, unsigned long *modtime); +extern int os_file_size(const char *file, unsigned long long *size_out); +extern int os_file_modtime(const char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); -extern int os_set_fd_async(int fd, int owner); +extern int os_set_fd_async(int fd); extern int os_clear_fd_async(int fd); extern int os_set_fd_block(int fd, int blocking); extern int os_accept_connection(int fd); -extern int os_create_unix_socket(char *file, int len, int close_on_exec); +extern int os_create_unix_socket(const char *file, int len, int close_on_exec); extern int os_shutdown_socket(int fd, int r, int w); extern void os_close_file(int fd); extern int os_rcv_fd(int fd, int *helper_pid_out); extern int create_unix_socket(char *file, int len, int close_on_exec); -extern int os_connect_socket(char *name); +extern int os_connect_socket(const char *name); extern int os_file_type(char *file); -extern int os_file_mode(char *file, struct openflags *mode_out); +extern int os_file_mode(const char *file, struct openflags *mode_out); extern int os_lock_file(int fd, int excl); extern void os_flush_stdout(void); extern int os_stat_filesystem(char *path, long *bsize_out, @@ -168,14 +165,10 @@ extern int os_fchange_dir(int fd); /* start_up.c */ extern void os_early_checks(void); -extern int can_do_skas(void); +extern void can_do_skas(void); extern void os_check_bugs(void); extern void check_host_supports_tls(int *supports_tls, int *tls_min); -/* Make sure they are clear when running in TT mode. Required by - * SEGV_MAYBE_FIXABLE */ -#define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) - /* mem.c */ extern int create_mem_file(unsigned long long len); @@ -214,7 +207,7 @@ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv); extern int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long *stack_out); -extern int helper_wait(int pid, int nohang, char *pname); +extern int helper_wait(int pid); /* tls.c */ @@ -237,16 +230,12 @@ extern void unblock_signals(void); extern int get_signals(void); extern int set_signals(int enable); -/* trap.c */ -extern void os_fill_handlinfo(struct kern_handlers h); - /* util.c */ extern void stack_protections(unsigned long address); extern int raw(int fd); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(char *buf, int len); -extern int setjmp_wrapper(void (*proc)(void *, void *), ...); -extern void os_dump_core(void); +extern void os_dump_core(void) __attribute__ ((noreturn)); /* time.c */ extern void idle_sleep(unsigned long long nsecs); @@ -275,11 +264,9 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr, extern int is_skas_winch(int pid, int fd, void *data); extern int start_userspace(unsigned long stub_stack); extern int copy_context_skas0(unsigned long stack, int pid); -extern void save_registers(int pid, struct uml_pt_regs *regs); -extern void restore_registers(int pid, struct uml_pt_regs *regs); extern void userspace(struct uml_pt_regs *regs); -extern void map_stub_pages(int fd, unsigned long code, - unsigned long data, unsigned long stack); +extern int map_stub_pages(int fd, unsigned long code, unsigned long data, + unsigned long stack); extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); extern void switch_threads(jmp_buf *me, jmp_buf *you); extern int start_idle_thread(void *stack, jmp_buf *switch_buf); @@ -298,16 +285,12 @@ extern void os_free_irq_later(struct irq_fd *active_fds, extern int os_get_pollfd(int i); extern void os_set_pollfd(int i, int fd); extern void os_set_ioignore(void); -extern void init_irq_signals(int on_sigstack); /* sigio.c */ extern int add_sigio_fd(int fd); extern int ignore_sigio_fd(int fd); extern void maybe_sigio_broken(int fd, int read); -/* skas/trap */ -extern void sig_handler_common_skas(int sig, void *sc_ptr); - /* sys-x86_64/prctl.c */ extern int os_arch_prctl(int pid, int code, unsigned long *addr); diff --git a/arch/um/include/ptrace_user.h b/arch/um/include/ptrace_user.h index f3450e6bc18..4bce6e01288 100644 --- a/arch/um/include/ptrace_user.h +++ b/arch/um/include/ptrace_user.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -10,12 +10,6 @@ extern int ptrace_getregs(long pid, unsigned long *regs_out); extern int ptrace_setregs(long pid, unsigned long *regs_in); -extern int ptrace_getfpregs(long pid, unsigned long *regs_out); -extern int ptrace_setfpregs(long pid, unsigned long *regs); -extern void arch_enter_kernel(void *task, int pid); -extern void arch_leave_kernel(void *task, int pid); -extern void ptrace_pokeuser(unsigned long addr, unsigned long data); - /* syscall emulation path in ptrace */ @@ -54,7 +48,8 @@ extern int sysemu_supported; (((int[3][3] ) { \ { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \ { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \ - { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, PTRACE_SYSEMU_SINGLESTEP }}) \ + { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \ + PTRACE_SYSEMU_SINGLESTEP } }) \ [sysemu_mode][singlestep_mode]) #endif diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h index 0e27406a43a..9ea1ae3c8f4 100644 --- a/arch/um/include/registers.h +++ b/arch/um/include/registers.h @@ -9,14 +9,13 @@ #include "sysdep/ptrace.h" #include "sysdep/archsetjmp.h" -extern void init_thread_registers(struct uml_pt_regs *to); extern int save_fp_registers(int pid, unsigned long *fp_regs); extern int restore_fp_registers(int pid, unsigned long *fp_regs); extern int save_fpx_registers(int pid, unsigned long *fp_regs); extern int restore_fpx_registers(int pid, unsigned long *fp_regs); -extern void save_registers(int pid, struct uml_pt_regs *regs); -extern void restore_registers(int pid, struct uml_pt_regs *regs); -extern void init_registers(int pid); +extern int save_registers(int pid, struct uml_pt_regs *regs); +extern int restore_registers(int pid, struct uml_pt_regs *regs); +extern int init_registers(int pid); extern void get_safe_registers(unsigned long *regs); extern unsigned long get_thread_reg(int reg, jmp_buf *buf); diff --git a/arch/um/include/signal_kern.h b/arch/um/include/signal_kern.h deleted file mode 100644 index aeb5d5ab1df..00000000000 --- a/arch/um/include/signal_kern.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __SIGNAL_KERN_H__ -#define __SIGNAL_KERN_H__ - -extern int have_signals(void *t); - -#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/include/skas/mode-skas.h b/arch/um/include/skas/mode-skas.h deleted file mode 100644 index e065feb000d..00000000000 --- a/arch/um/include/skas/mode-skas.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) - * Licensed under the GPL - */ - -#ifndef __MODE_SKAS_H__ -#define __MODE_SKAS_H__ - -extern void kill_off_processes_skas(void); - -#endif diff --git a/arch/um/include/sysdep-i386/syscalls.h b/arch/um/include/sysdep-i386/syscalls.h index 57bd79efbee..905698197e3 100644 --- a/arch/um/include/sysdep-i386/syscalls.h +++ b/arch/um/include/sysdep-i386/syscalls.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -18,7 +18,8 @@ extern syscall_handler_t old_mmap_i386; extern syscall_handler_t *sys_call_table[]; #define EXECUTE_SYSCALL(syscall, regs) \ - ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) + ((long (*)(struct syscall_args)) \ + (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) extern long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h index c978b589df4..a307237b796 100644 --- a/arch/um/include/sysdep-x86_64/kernel-offsets.h +++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h @@ -17,16 +17,7 @@ #define OFFSET(sym, str, mem) \ DEFINE(sym, offsetof(struct str, mem)); -#define __NO_STUBS 1 -#undef __SYSCALL -#undef _ASM_X86_64_UNISTD_H_ -#define __SYSCALL(nr, sym) [nr] = 1, -static char syscalls[] = { -#include <asm/arch/unistd.h> -}; - void foo(void) { #include <common-offsets.h> -DEFINE(UM_NR_syscall_max, sizeof(syscalls) - 1); } diff --git a/arch/um/include/sysdep-x86_64/syscalls.h b/arch/um/include/sysdep-x86_64/syscalls.h index cf72256609e..7cfb0b08565 100644 --- a/arch/um/include/sysdep-x86_64/syscalls.h +++ b/arch/um/include/sysdep-x86_64/syscalls.h @@ -30,6 +30,4 @@ extern long old_mmap(unsigned long addr, unsigned long len, extern syscall_handler_t sys_modify_ldt; extern syscall_handler_t sys_arch_prctl; -#define NR_syscalls (UM_NR_syscall_max + 1) - #endif diff --git a/arch/um/include/um_mmu.h b/arch/um/include/um_mmu.h index 8855d8df512..82865fcf687 100644 --- a/arch/um/include/um_mmu.h +++ b/arch/um/include/um_mmu.h @@ -12,10 +12,6 @@ typedef struct mm_context { struct mm_id id; - unsigned long last_page_table; -#ifdef CONFIG_3_LEVEL_PGTABLES - unsigned long last_pmd; -#endif struct uml_ldt ldt; } mm_context_t; diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h index fdfc06b8560..2b6fc8e0f07 100644 --- a/arch/um/include/um_uaccess.h +++ b/arch/um/include/um_uaccess.h @@ -6,7 +6,9 @@ #ifndef __ARCH_UM_UACCESS_H #define __ARCH_UM_UACCESS_H -#include "asm/fixmap.h" +#include <asm/elf.h> +#include <asm/fixmap.h> +#include "sysdep/archsetjmp.h" #define __under_task_size(addr, size) \ (((unsigned long) (addr) < TASK_SIZE) && \ diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 8196450451c..76a62c0cb2b 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -19,12 +19,13 @@ void flush_thread(void) { void *data = NULL; - unsigned long end = proc_mm ? task_size : STUB_START; int ret; arch_flush_thread(¤t->thread.arch); - ret = unmap(¤t->mm->context.id, 0, end, 1, &data); + ret = unmap(¤t->mm->context.id, 0, STUB_START, 0, &data); + ret = ret || unmap(¤t->mm->context.id, STUB_END, + TASK_SIZE - STUB_END, 1, &data); if (ret) { printk(KERN_ERR "flush_thread - clearing address space failed, " "err = %d\n", ret); diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index c716b5a6db1..984f80e668c 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -1,15 +1,17 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/init.h" -#include "linux/ctype.h" -#include "linux/proc_fs.h" -#include "asm/uaccess.h" +#include <linux/ctype.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/proc_fs.h> +#include <linux/types.h> +#include <asm/uaccess.h> -/* If read and write race, the read will still atomically read a valid +/* + * If read and write race, the read will still atomically read a valid * value. */ int uml_exitcode = 0; @@ -19,18 +21,19 @@ static int read_proc_exitcode(char *page, char **start, off_t off, { int len, val; - /* Save uml_exitcode in a local so that we don't need to guarantee + /* + * Save uml_exitcode in a local so that we don't need to guarantee * that sprintf accesses it atomically. */ val = uml_exitcode; len = sprintf(page, "%d\n", val); len -= off; - if(len <= off+count) + if (len <= off+count) *eof = 1; *start = page + off; - if(len > count) + if (len > count) len = count; - if(len < 0) + if (len < 0) len = 0; return len; } @@ -41,11 +44,11 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer, char *end, buf[sizeof("nnnnn\0")]; int tmp; - if(copy_from_user(buf, buffer, count)) + if (copy_from_user(buf, buffer, count)) return -EFAULT; tmp = simple_strtol(buf, &end, 0); - if((*end != '\0') && !isspace(*end)) + if ((*end != '\0') && !isspace(*end)) return -EINVAL; uml_exitcode = tmp; @@ -57,7 +60,7 @@ static int make_proc_exitcode(void) struct proc_dir_entry *ent; ent = create_proc_entry("exitcode", 0600, &proc_root); - if(ent == NULL){ + if (ent == NULL) { printk(KERN_WARNING "make_proc_exitcode : Failed to register " "/proc/exitcode\n"); return 0; diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c index 734f873cab1..72eccd2a411 100644 --- a/arch/um/kernel/gmon_syms.c +++ b/arch/um/kernel/gmon_syms.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -8,12 +8,13 @@ extern void __bb_init_func(void *) __attribute__((weak)); EXPORT_SYMBOL(__bb_init_func); -/* This is defined (and referred to in profiling stub code) only by some GCC +/* + * This is defined (and referred to in profiling stub code) only by some GCC * versions in libgcov. * * Since SuSE backported the fix, we cannot handle it depending on GCC version. - * So, unconditionally export it. But also give it a weak declaration, which will - * be overridden by any other one. + * So, unconditionally export it. But also give it a weak declaration, which + * will be overridden by any other one. */ extern void __gcov_init(void *) __attribute__((weak)); diff --git a/arch/um/kernel/gprof_syms.c b/arch/um/kernel/gprof_syms.c index 9244f018d44..e2f043d0de6 100644 --- a/arch/um/kernel/gprof_syms.c +++ b/arch/um/kernel/gprof_syms.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -7,14 +7,3 @@ extern void mcount(void); EXPORT_SYMBOL(mcount); - -/* - * 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/initrd.c b/arch/um/kernel/initrd.c index 16dc43e9d94..fa015565001 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -7,7 +7,6 @@ #include "linux/bootmem.h" #include "linux/initrd.h" #include "asm/types.h" -#include "kern_util.h" #include "initrd.h" #include "init.h" #include "os.h" @@ -21,18 +20,27 @@ static int __init read_initrd(void) long long size; int err; - if(initrd == NULL) + if (initrd == NULL) return 0; err = os_file_size(initrd, &size); - if(err) + if (err) return 0; + /* + * This is necessary because alloc_bootmem craps out if you + * ask for no memory. + */ + if (size == 0) { + printk(KERN_ERR "\"%\" is a zero-size initrd\n"); + return 0; + } + area = alloc_bootmem(size); - if(area == NULL) + if (area == NULL) return 0; - if(load_initrd(initrd, area, size) == -1) + if (load_initrd(initrd, area, size) == -1) return 0; initrd_start = (unsigned long) area; @@ -59,13 +67,15 @@ int load_initrd(char *filename, void *buf, int size) int fd, n; fd = os_open_file(filename, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Opening '%s' failed - err = %d\n", filename, -fd); + if (fd < 0) { + printk(KERN_ERR "Opening '%s' failed - err = %d\n", filename, + -fd); return -1; } n = os_read_file(fd, buf, size); - if(n != size){ - printk("Read of %d bytes from '%s' failed, err = %d\n", size, + if (n != size) { + printk(KERN_ERR "Read of %d bytes from '%s' failed, " + "err = %d\n", size, filename, -n); return -1; } diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index ba11ccd6a8a..91587f8db34 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -107,10 +107,9 @@ int activate_fd(int irq, int fd, int type, void *dev_id) struct pollfd *tmp_pfd; struct irq_fd *new_fd, *irq_fd; unsigned long flags; - int pid, events, err, n; + int events, err, n; - pid = os_getpid(); - err = os_set_fd_async(fd, pid); + err = os_set_fd_async(fd); if (err < 0) goto out; @@ -127,7 +126,6 @@ int activate_fd(int irq, int fd, int type, void *dev_id) .fd = fd, .type = type, .irq = irq, - .pid = pid, .events = events, .current_events = 0 } ); diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 7c7142ba3bd..5311ee93ede 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -18,15 +18,11 @@ EXPORT_SYMBOL(set_signals); EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(sys_waitpid); -EXPORT_SYMBOL(task_size); EXPORT_SYMBOL(flush_tlb_range); -EXPORT_SYMBOL(host_task_size); EXPORT_SYMBOL(arch_validate); -EXPORT_SYMBOL(get_kmem_end); EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(empty_zero_page); -EXPORT_SYMBOL(um_virt_to_phys); EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); @@ -40,7 +36,6 @@ EXPORT_SYMBOL(uml_strdup); EXPORT_SYMBOL(os_stat_fd); EXPORT_SYMBOL(os_stat_file); EXPORT_SYMBOL(os_access); -EXPORT_SYMBOL(os_get_exec_close); EXPORT_SYMBOL(os_set_exec_close); EXPORT_SYMBOL(os_getpid); EXPORT_SYMBOL(os_open_file); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 59822dee438..d872fdce1d7 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -1,49 +1,41 @@ /* - * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/stddef.h" -#include "linux/kernel.h" -#include "linux/mm.h" -#include "linux/bootmem.h" -#include "linux/swap.h" -#include "linux/highmem.h" -#include "linux/gfp.h" -#include "asm/page.h" -#include "asm/fixmap.h" -#include "asm/pgalloc.h" -#include "kern_util.h" +#include <linux/stddef.h> +#include <linux/bootmem.h> +#include <linux/gfp.h> +#include <linux/highmem.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <asm/fixmap.h> +#include <asm/page.h> #include "as-layout.h" +#include "init.h" #include "kern.h" +#include "kern_util.h" #include "mem_user.h" -#include "um_uaccess.h" #include "os.h" -#include "linux/types.h" -#include "linux/string.h" -#include "init.h" -#include "kern_constants.h" /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */ unsigned long *empty_zero_page = NULL; /* allocated in paging_init and unchanged thereafter */ unsigned long *empty_bad_page = NULL; + +/* + * Initialized during boot, and readonly for initializing page tables + * afterwards + */ pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* Initialized at boot time, and readonly after that */ unsigned long long highmem; int kmalloc_ok = 0; +/* Used during early boot */ static unsigned long brk_end; -void unmap_physmem(void) -{ - os_unmap_memory((void *) brk_end, uml_reserved - brk_end); -} - -static void map_cb(void *unused) -{ - map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); -} - #ifdef CONFIG_HIGHMEM static void setup_highmem(unsigned long highmem_start, unsigned long highmem_len) @@ -53,7 +45,7 @@ static void setup_highmem(unsigned long highmem_start, int i; highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; - for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ + for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) { page = &mem_map[highmem_pfn + i]; ClearPageReserved(page); init_page_count(page); @@ -65,14 +57,13 @@ static void setup_highmem(unsigned long highmem_start, void __init mem_init(void) { /* clear the zero-page */ - memset((void *) empty_zero_page, 0, PAGE_SIZE); + memset(empty_zero_page, 0, PAGE_SIZE); /* Map in the area just after the brk now that kmalloc is about * to be turned on. */ brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); - map_cb(NULL); - initial_thread_cb(map_cb, NULL); + map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); free_bootmem(__pa(brk_end), uml_reserved - brk_end); uml_reserved = brk_end; @@ -85,7 +76,7 @@ void __init mem_init(void) #endif num_physpages = totalram_pages; max_pfn = totalram_pages; - printk(KERN_INFO "Memory: %luk available\n", + printk(KERN_INFO "Memory: %luk available\n", (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); kmalloc_ok = 1; @@ -119,7 +110,7 @@ static void __init one_md_table_init(pud_t *pud) #endif } -static void __init fixrange_init(unsigned long start, unsigned long end, +static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { pgd_t *pgd; @@ -138,7 +129,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end, if (pud_none(*pud)) one_md_table_init(pud); pmd = pmd_offset(pud, vaddr); - for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { + for (; (j < PTRS_PER_PMD) && (vaddr < end); pmd++, j++) { one_page_table_init(pmd); vaddr += PMD_SIZE; } @@ -152,7 +143,7 @@ pgprot_t kmap_prot; #define kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\ - (vaddr)), (vaddr)) + (vaddr)), (vaddr)) static void __init kmap_init(void) { @@ -197,21 +188,23 @@ static void __init fixaddr_user_init( void) pud_t *pud; pmd_t *pmd; pte_t *pte; - unsigned long paddr, vaddr = FIXADDR_USER_START; + phys_t p; + unsigned long v, vaddr = FIXADDR_USER_START; - if ( ! size ) + if (!size) return; fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir); - paddr = (unsigned long)alloc_bootmem_low_pages( size); - memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size); - paddr = __pa(paddr); - for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE){ + v = (unsigned long) alloc_bootmem_low_pages(size); + memcpy((void *) v , (void *) FIXADDR_USER_START, size); + p = __pa(v); + for ( ; size > 0; size -= PAGE_SIZE, vaddr += PAGE_SIZE, + p += PAGE_SIZE) { pgd = swapper_pg_dir + pgd_index(vaddr); pud = pud_offset(pgd, vaddr); pmd = pmd_offset(pud, vaddr); pte = pte_offset_kernel(pmd, vaddr); - pte_set_val( (*pte), paddr, PAGE_READONLY); + pte_set_val(*pte, p, PAGE_READONLY); } #endif } @@ -223,7 +216,7 @@ void __init paging_init(void) empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); - for(i = 0; i < ARRAY_SIZE(zones_size); i++) + for (i = 0; i < ARRAY_SIZE(zones_size); i++) zones_size[i] = 0; zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) - @@ -253,32 +246,33 @@ struct page *arch_validate(struct page *page, gfp_t mask, int order) int i; again: - if(page == NULL) + if (page == NULL) return page; - if(PageHighMem(page)) + if (PageHighMem(page)) return page; addr = (unsigned long) page_address(page); - for(i = 0; i < (1 << order); i++){ + for (i = 0; i < (1 << order); i++) { current->thread.fault_addr = (void *) addr; - if(__do_copy_to_user((void __user *) addr, &zero, + if (__do_copy_to_user((void __user *) addr, &zero, sizeof(zero), ¤t->thread.fault_addr, - ¤t->thread.fault_catcher)){ - if(!(mask & __GFP_WAIT)) + ¤t->thread.fault_catcher)) { + if (!(mask & __GFP_WAIT)) return NULL; else break; } addr += PAGE_SIZE; } - if(i == (1 << order)) + if (i == (1 << order)) return page; page = alloc_pages(mask, order); goto again; } -/* This can't do anything because nothing in the kernel image can be freed +/* + * This can't do anything because nothing in the kernel image can be freed * since it's not in kernel physical memory. */ @@ -290,8 +284,8 @@ void free_initmem(void) void free_initrd_mem(unsigned long start, unsigned long end) { if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", - (end - start) >> 10); + printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", + (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); init_page_count(virt_to_page(start)); @@ -308,32 +302,31 @@ void show_mem(void) int highmem = 0; struct page *page; - printk("Mem-info:\n"); + printk(KERN_INFO "Mem-info:\n"); show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + printk(KERN_INFO "Free swap: %6ldkB\n", + nr_swap_pages<<(PAGE_SHIFT-10)); pfn = max_mapnr; - while(pfn-- > 0) { + while (pfn-- > 0) { page = pfn_to_page(pfn); total++; - if(PageHighMem(page)) + if (PageHighMem(page)) highmem++; - if(PageReserved(page)) + if (PageReserved(page)) reserved++; - else if(PageSwapCache(page)) + else if (PageSwapCache(page)) cached++; - else if(page_count(page)) + else if (page_count(page)) shared += page_count(page) - 1; } - printk("%d pages of RAM\n", total); - printk("%d pages of HIGHMEM\n", highmem); - printk("%d reserved pages\n", reserved); - printk("%d pages shared\n", shared); - printk("%d pages swap cached\n", cached); + printk(KERN_INFO "%d pages of RAM\n", total); + printk(KERN_INFO "%d pages of HIGHMEM\n", highmem); + printk(KERN_INFO "%d reserved pages\n", reserved); + printk(KERN_INFO "%d pages shared\n", shared); + printk(KERN_INFO "%d pages swap cached\n", cached); } -/* - * Allocate and free page tables. - */ +/* Allocate and free page tables. */ pgd_t *pgd_alloc(struct mm_struct *mm) { @@ -341,14 +334,14 @@ pgd_t *pgd_alloc(struct mm_struct *mm) if (pgd) { memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(pgd + USER_PTRS_PER_PGD, - swapper_pg_dir + USER_PTRS_PER_PGD, + memcpy(pgd + USER_PTRS_PER_PGD, + swapper_pg_dir + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } return pgd; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { free_page((unsigned long) pgd); } @@ -368,3 +361,15 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); return pte; } + +#ifdef CONFIG_3_LEVEL_PGTABLES +pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + + if (pmd) + memset(pmd, 0, PAGE_SIZE); + + return pmd; +} +#endif diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index e66432f4248..9757085a022 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -55,16 +55,6 @@ int __init init_maps(unsigned long physmem, unsigned long iomem, return 0; } -/* Changed during early boot */ -static unsigned long kmem_top = 0; - -unsigned long get_kmem_end(void) -{ - if (kmem_top == 0) - kmem_top = host_task_size - 1024 * 1024; - return kmem_top; -} - void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x) { @@ -174,10 +164,10 @@ __uml_setup("iomem=", parse_iomem, * setup_iomem, both of which run during early boot. Afterwards, it's * unchanged. */ -struct iomem_region *iomem_regions = NULL; +struct iomem_region *iomem_regions; -/* Initialized in parse_iomem */ -int iomem_size = 0; +/* Initialized in parse_iomem and unchanged thereafter */ +int iomem_size; unsigned long find_iomem(char *driver, unsigned long *len_out) { diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 0eae00b3e58..c07961bedb7 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -4,19 +4,21 @@ * Licensed under the GPL */ -#include "linux/stddef.h" -#include "linux/err.h" -#include "linux/hardirq.h" -#include "linux/mm.h" -#include "linux/personality.h" -#include "linux/proc_fs.h" -#include "linux/ptrace.h" -#include "linux/random.h" -#include "linux/sched.h" -#include "linux/tick.h" -#include "linux/threads.h" -#include "asm/pgtable.h" -#include "asm/uaccess.h" +#include <linux/stddef.h> +#include <linux/err.h> +#include <linux/hardirq.h> +#include <linux/gfp.h> +#include <linux/mm.h> +#include <linux/personality.h> +#include <linux/proc_fs.h> +#include <linux/ptrace.h> +#include <linux/random.h> +#include <linux/sched.h> +#include <linux/tick.h> +#include <linux/threads.h> +#include <asm/current.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> #include "as-layout.h" #include "kern_util.h" #include "os.h" @@ -30,7 +32,7 @@ */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; -static inline int external_pid(struct task_struct *task) +static inline int external_pid(void) { /* FIXME: Need to look up userspace_pid by cpu */ return userspace_pid[0]; @@ -40,7 +42,7 @@ int pid_to_processor_id(int pid) { int i; - for(i = 0; i < ncpus; i++) { + for (i = 0; i < ncpus; i++) { if (cpu_tasks[i].pid == pid) return i; } @@ -60,8 +62,6 @@ unsigned long alloc_stack(int order, int atomic) if (atomic) flags = GFP_ATOMIC; page = __get_free_pages(flags, order); - if (page == 0) - return 0; return page; } @@ -80,15 +80,15 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) static inline void set_current(struct task_struct *task) { cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) - { external_pid(task), task }); + { external_pid(), task }); } -extern void arch_switch_to(struct task_struct *from, struct task_struct *to); +extern void arch_switch_to(struct task_struct *to); void *_switch_to(void *prev, void *next, void *last) { struct task_struct *from = prev; - struct task_struct *to= next; + struct task_struct *to = next; to->thread.prev_sched = from; set_current(to); @@ -99,13 +99,13 @@ void *_switch_to(void *prev, void *next, void *last) switch_threads(&from->thread.switch_buf, &to->thread.switch_buf); - arch_switch_to(current->thread.prev_sched, current); + arch_switch_to(current); if (current->thread.saved_task) show_regs(&(current->thread.regs)); - next= current->thread.saved_task; - prev= current; - } while(current->thread.saved_task); + to = current->thread.saved_task; + from = current; + } while (current->thread.saved_task); return current->thread.prev_sched; @@ -163,8 +163,6 @@ void new_thread_handler(void) void fork_handler(void) { force_flush_all(); - if (current->thread.prev_sched == NULL) - panic("blech"); schedule_tail(current->thread.prev_sched); @@ -173,7 +171,7 @@ void fork_handler(void) * arch_switch_to isn't needed. We could want to apply this to * improve performance. -bb */ - arch_switch_to(current->thread.prev_sched, current); + arch_switch_to(current); current->thread.prev_sched = NULL; @@ -204,7 +202,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { - init_thread_registers(&p->thread.regs.regs); + get_safe_registers(p->thread.regs.regs.gp); p->thread.request.u.thread = current->thread.request.u.thread; handler = new_thread_handler; } @@ -237,7 +235,7 @@ void default_idle(void) { unsigned long long nsecs; - while(1) { + while (1) { /* endless idle loop with no priority at all */ /* @@ -256,53 +254,10 @@ void default_idle(void) void cpu_idle(void) { - cpu_tasks[current_thread->cpu].pid = os_getpid(); + cpu_tasks[current_thread_info()->cpu].pid = os_getpid(); default_idle(); } -void *um_virt_to_phys(struct task_struct *task, unsigned long addr, - pte_t *pte_out) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - pte_t ptent; - - if (task->mm == NULL) - return ERR_PTR(-EINVAL); - pgd = pgd_offset(task->mm, addr); - if (!pgd_present(*pgd)) - return ERR_PTR(-EINVAL); - - pud = pud_offset(pgd, addr); - if (!pud_present(*pud)) - return ERR_PTR(-EINVAL); - - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) - return ERR_PTR(-EINVAL); - - pte = pte_offset_kernel(pmd, addr); - ptent = *pte; - if (!pte_present(ptent)) - return ERR_PTR(-EINVAL); - - if (pte_out != NULL) - *pte_out = ptent; - return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK); -} - -char *current_cmd(void) -{ -#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) - return "(Unknown)"; -#else - void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); - return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); -#endif -} - void dump_thread(struct pt_regs *regs, struct user *u) { } @@ -317,7 +272,7 @@ int user_context(unsigned long sp) unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - return stack != (unsigned long) current_thread; + return stack != (unsigned long) current_thread_info(); } extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; @@ -331,7 +286,7 @@ void do_uml_exitcalls(void) (*call)(); } -char *uml_strdup(char *string) +char *uml_strdup(const char *string) { return kstrdup(string, GFP_KERNEL); } @@ -359,7 +314,7 @@ int strlen_user_proc(char __user *str) int smp_sigio_handler(void) { #ifdef CONFIG_SMP - int cpu = current_thread->cpu; + int cpu = current_thread_info()->cpu; IPI_handler(cpu); if (cpu != 0) return 1; @@ -369,7 +324,7 @@ int smp_sigio_handler(void) int cpu(void) { - return current_thread->cpu; + return current_thread_info()->cpu; } static atomic_t using_sysemu = ATOMIC_INIT(0); @@ -435,7 +390,7 @@ int singlestepping(void * t) { struct task_struct *task = t ? t : current; - if ( ! (task->ptrace & PT_DTRACE) ) + if (!(task->ptrace & PT_DTRACE)) return 0; if (task->thread.singlestep_syscall) @@ -459,3 +414,46 @@ unsigned long arch_align_stack(unsigned long sp) return sp & ~0xf; } #endif + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long stack_page, sp, ip; + bool seen_sched = 0; + + if ((p == NULL) || (p == current) || (p->state == TASK_RUNNING)) + return 0; + + stack_page = (unsigned long) task_stack_page(p); + /* Bail if the process has no kernel stack for some reason */ + if (stack_page == 0) + return 0; + + sp = p->thread.switch_buf->JB_SP; + /* + * Bail if the stack pointer is below the bottom of the kernel + * stack for some reason + */ + if (sp < stack_page) + return 0; + + while (sp < stack_page + THREAD_SIZE) { + ip = *((unsigned long *) sp); + if (in_sched_functions(ip)) + /* Ignore everything until we're above the scheduler */ + seen_sched = 1; + else if (kernel_text_address(ip) && seen_sched) + return ip; + + sp += sizeof(unsigned long); + } + + return 0; +} + +int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu) +{ + int cpu = current_thread_info()->cpu; + + return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu); +} + diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c index 04cebcf0679..00197d3d21e 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c @@ -4,6 +4,7 @@ */ #include "linux/sched.h" +#include "kern_util.h" #include "os.h" #include "skas.h" @@ -11,7 +12,7 @@ void (*pm_power_off)(void); static void kill_off_processes(void) { - if(proc_mm) + if (proc_mm) /* * FIXME: need to loop over userspace_pids */ @@ -21,8 +22,8 @@ static void kill_off_processes(void) int pid, me; me = os_getpid(); - for_each_process(p){ - if(p->mm == NULL) + for_each_process(p) { + if (p->mm == NULL) continue; pid = p->mm->context.id.u.pid; diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 89f9866a135..2b272b63b51 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c @@ -1,18 +1,12 @@ /* - * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/list.h" -#include "linux/slab.h" -#include "linux/signal.h" -#include "linux/interrupt.h" -#include "init.h" -#include "sigio.h" -#include "irq_user.h" +#include <linux/interrupt.h> #include "irq_kern.h" #include "os.h" +#include "sigio.h" /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; @@ -33,9 +27,9 @@ int write_sigio_irq(int fd) err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, IRQF_DISABLED|IRQF_SAMPLE_RANDOM, "write sigio", NULL); - if(err){ - printk("write_sigio_irq : um_request_irq failed, err = %d\n", - err); + if (err) { + printk(KERN_ERR "write_sigio_irq : um_request_irq failed, " + "err = %d\n", err); return -1; } sigio_irq_fd = fd; diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index 19cb9773393..b0fce720c4d 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -3,12 +3,12 @@ * Licensed under the GPL */ -#include "linux/module.h" -#include "linux/ptrace.h" -#include "linux/sched.h" -#include "asm/siginfo.h" -#include "asm/signal.h" -#include "asm/unistd.h" +#include <linux/module.h> +#include <linux/ptrace.h> +#include <linux/sched.h> +#include <asm/siginfo.h> +#include <asm/signal.h> +#include <asm/unistd.h> #include "frame_kern.h" #include "kern_util.h" #include "sigcontext.h" @@ -36,7 +36,7 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, /* Did we come from a system call? */ if (PT_REGS_SYSCALL_NR(regs) >= 0) { /* If so, check system call restarting.. */ - switch(PT_REGS_SYSCALL_RET(regs)) { + switch (PT_REGS_SYSCALL_RET(regs)) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: PT_REGS_SYSCALL_RET(regs) = -EINTR; @@ -116,7 +116,7 @@ static int kern_do_signal(struct pt_regs *regs) /* Did we come from a system call? */ if (!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)) { /* Restart the system call - no handlers present */ - switch(PT_REGS_SYSCALL_RET(regs)) { + switch (PT_REGS_SYSCALL_RET(regs)) { case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 8d07a7acb90..2c8583c1a34 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -1,17 +1,20 @@ -#include <sched.h> +/* + * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) + * Licensed under the GPL + */ + #include <signal.h> -#include <sys/mman.h> -#include <sys/time.h> +#include <sched.h> #include <asm/unistd.h> +#include <sys/time.h> #include "as-layout.h" +#include "kern_constants.h" #include "ptrace_user.h" -#include "skas.h" #include "stub-data.h" -#include "uml-config.h" #include "sysdep/stub.h" -#include "kern_constants.h" -/* This is in a separate file because it needs to be compiled with any +/* + * This is in a separate file because it needs to be compiled with any * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled * * Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize @@ -26,25 +29,26 @@ stub_clone_handler(void) err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *)); - if(err != 0) + if (err != 0) goto out; err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); - if(err) + if (err) goto out; - err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, + err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, (long) &data->timer, 0); - if(err) + if (err) goto out; remap_stack(data->fd, data->offset); goto done; out: - /* save current result. - * Parent: pid; - * child: retcode of mmap already saved and it jumps around this + /* + * save current result. + * Parent: pid; + * child: retcode of mmap already saved and it jumps around this * assignment */ data->err = err; diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index f859ec306cd..78b3e9f69d5 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -34,33 +34,14 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long 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.last_page_table = pmd_page_vaddr(*pmd); -#ifdef CONFIG_3_LEVEL_PGTABLES - mm->context.last_pmd = (unsigned long) __va(pud_val(*pud)); -#endif - *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); *pte = pte_mkread(*pte); return 0; out_pmd: - pud_free(pud); + pud_free(mm, pud); out_pte: - pmd_free(pmd); + pmd_free(mm, pmd); out: return -ENOMEM; } @@ -76,24 +57,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) stack = get_zeroed_page(GFP_KERNEL); if (stack == 0) goto out; - - /* - * 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); - - ret = init_stub_pte(mm, STUB_CODE, - (unsigned long) &__syscall_stub_start); - if (ret) - goto out_free; - - ret = init_stub_pte(mm, STUB_DATA, stack); - if (ret) - goto out_free; - - mm->nr_ptes--; } to_mm->id.stack = stack; @@ -114,6 +77,11 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) to_mm->id.u.pid = copy_context_skas0(stack, from_mm->id.u.pid); else to_mm->id.u.pid = start_userspace(stack); + + if (to_mm->id.u.pid < 0) { + ret = to_mm->id.u.pid; + goto out_free; + } } ret = init_new_ldt(to_mm, from_mm); @@ -132,24 +100,87 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) return ret; } +void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +{ + struct page **pages; + int err, ret; + + if (!skas_needs_stub) + return; + + ret = init_stub_pte(mm, STUB_CODE, + (unsigned long) &__syscall_stub_start); + if (ret) + goto out; + + ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack); + if (ret) + goto out; + + pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL); + if (pages == NULL) { + printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page " + "pointers\n"); + goto out; + } + + pages[0] = virt_to_page(&__syscall_stub_start); + pages[1] = virt_to_page(mm->context.id.stack); + + /* dup_mmap already holds mmap_sem */ + err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, + VM_READ | VM_MAYREAD | VM_EXEC | + VM_MAYEXEC | VM_DONTCOPY, pages); + if (err) { + printk(KERN_ERR "install_special_mapping returned %d\n", err); + goto out_free; + } + return; + +out_free: + kfree(pages); +out: + force_sigsegv(SIGSEGV, current); +} + +void arch_exit_mmap(struct mm_struct *mm) +{ + pte_t *pte; + + pte = virt_to_pte(mm, STUB_CODE); + if (pte != NULL) + pte_clear(mm, STUB_CODE, pte); + + pte = virt_to_pte(mm, STUB_DATA); + if (pte == NULL) + return; + + pte_clear(mm, STUB_DATA, pte); +} + void destroy_context(struct mm_struct *mm) { struct mm_context *mmu = &mm->context; if (proc_mm) os_close_file(mmu->id.u.mm_fd); - else + else { + /* + * If init_new_context wasn't called, this will be + * zero, resulting in a kill(0), which will result in the + * whole UML suddenly dying. Also, cover negative and + * 1 cases, since they shouldn't happen either. + */ + if (mmu->id.u.pid < 2) { + printk(KERN_ERR "corrupt mm_context - pid = %d\n", + mmu->id.u.pid); + return; + } os_kill_ptraced_process(mmu->id.u.pid, 1); + } - if (!proc_mm || !ptrace_faultinfo) { + if (skas_needs_stub) free_page(mmu->id.stack); - pte_lock_deinit(virt_to_page(mmu->last_page_table)); - pte_free_kernel((pte_t *) mmu->last_page_table); - dec_zone_page_state(virt_to_page(mmu->last_page_table), NR_PAGETABLE); -#ifdef CONFIG_3_LEVEL_PGTABLES - pmd_free((pmd_t *) mmu->last_pmd); -#endif - } free_ldt(mmu); } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index fce389c2342..2e9852c0d48 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -6,19 +6,25 @@ #include "linux/init.h" #include "linux/sched.h" #include "as-layout.h" +#include "kern.h" #include "os.h" #include "skas.h" int new_mm(unsigned long stack) { - int fd; + int fd, err; fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); if (fd < 0) return fd; - if (skas_needs_stub) - map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); + if (skas_needs_stub) { + err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack); + if (err) { + os_close_file(fd); + return err; + } + } return fd; } @@ -49,8 +55,14 @@ int __init start_uml(void) { stack_protections((unsigned long) &cpu0_irqstack); set_sigstack(cpu0_irqstack, THREAD_SIZE); - if (proc_mm) + if (proc_mm) { userspace_pid[0] = start_userspace(0); + if (userspace_pid[0] < 0) { + printf("start_uml - start_userspace returned %d\n", + userspace_pid[0]); + exit(1); + } + } init_new_thread_signals(); diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c index 50b476f2b38..4e3b820bd2b 100644 --- a/arch/um/kernel/skas/syscall.c +++ b/arch/um/kernel/skas/syscall.c @@ -9,6 +9,9 @@ #include "sysdep/ptrace.h" #include "sysdep/syscalls.h" +extern int syscall_table_size; +#define NR_syscalls (syscall_table_size / sizeof(void *)) + void handle_syscall(struct uml_pt_regs *r) { struct pt_regs *regs = container_of(r, struct pt_regs, regs); @@ -17,9 +20,6 @@ void handle_syscall(struct uml_pt_regs *r) syscall_trace(r, 0); - current->thread.nsyscalls++; - nsyscalls++; - /* * This should go in the declaration of syscall, but when I do that, * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 1d8b119f2d0..e22c96993db 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -3,128 +3,130 @@ * Licensed under the GPL */ -#include "linux/err.h" -#include "linux/highmem.h" -#include "linux/mm.h" -#include "asm/current.h" -#include "asm/page.h" -#include "asm/pgtable.h" +#include <linux/err.h> +#include <linux/highmem.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <asm/current.h> +#include <asm/page.h> +#include <asm/pgtable.h> #include "kern_util.h" #include "os.h" -extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, - pte_t *pte_out); - -static unsigned long maybe_map(unsigned long virt, int is_write) +pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr) { - pte_t pte; - int err; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + if (mm == NULL) + return NULL; + + pgd = pgd_offset(mm, addr); + if (!pgd_present(*pgd)) + return NULL; + + pud = pud_offset(pgd, addr); + if (!pud_present(*pud)) + return NULL; - void *phys = um_virt_to_phys(current, virt, &pte); - int dummy_code; + pmd = pmd_offset(pud, addr); + if (!pmd_present(*pmd)) + return NULL; + + return pte_offset_kernel(pmd, addr); +} + +static pte_t *maybe_map(unsigned long virt, int is_write) +{ + pte_t *pte = virt_to_pte(current->mm, virt); + int err, dummy_code; - if (IS_ERR(phys) || (is_write && !pte_write(pte))) { + if ((pte == NULL) || !pte_present(*pte) || + (is_write && !pte_write(*pte))) { err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); if (err) - return -1UL; - phys = um_virt_to_phys(current, virt, NULL); + return NULL; + pte = virt_to_pte(current->mm, virt); } - if (IS_ERR(phys)) - phys = (void *) -1; + if (!pte_present(*pte)) + pte = NULL; - return (unsigned long) phys; + return pte; } static int do_op_one_page(unsigned long addr, int len, int is_write, int (*op)(unsigned long addr, int len, void *arg), void *arg) { + jmp_buf buf; struct page *page; - int n; + pte_t *pte; + int n, faulted; - addr = maybe_map(addr, is_write); - if (addr == -1UL) + pte = maybe_map(addr, is_write); + if (pte == NULL) return -1; - page = phys_to_page(addr); + page = pte_page(*pte); addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK); - n = (*op)(addr, len, arg); + current->thread.fault_catcher = &buf; + + faulted = UML_SETJMP(&buf); + if (faulted == 0) + n = (*op)(addr, len, arg); + else + n = -1; + + current->thread.fault_catcher = NULL; kunmap_atomic(page, KM_UML_USERCOPY); return n; } -static void do_buffer_op(void *jmpbuf, void *arg_ptr) +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long, int, void *), void *arg) { - va_list args; - unsigned long addr; - int len, is_write, size, remain, n; - int (*op)(unsigned long, int, void *); - void *arg; - int *res; - - va_copy(args, *(va_list *)arg_ptr); - addr = va_arg(args, unsigned long); - len = va_arg(args, int); - is_write = va_arg(args, int); - op = va_arg(args, void *); - arg = va_arg(args, void *); - res = va_arg(args, int *); - va_end(args); + int size, remain, n; + size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); remain = len; - current->thread.fault_catcher = jmpbuf; n = do_op_one_page(addr, size, is_write, op, arg); if (n != 0) { - *res = (n < 0 ? remain : 0); + remain = (n < 0 ? remain : 0); goto out; } addr += size; remain -= size; - if (remain == 0) { - *res = 0; + if (remain == 0) goto out; - } - while(addr < ((addr + remain) & PAGE_MASK)) { + while (addr < ((addr + remain) & PAGE_MASK)) { n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); if (n != 0) { - *res = (n < 0 ? remain : 0); + remain = (n < 0 ? remain : 0); goto out; } addr += PAGE_SIZE; remain -= PAGE_SIZE; } - if (remain == 0) { - *res = 0; + if (remain == 0) goto out; - } n = do_op_one_page(addr, remain, is_write, op, arg); - if (n != 0) - *res = (n < 0 ? remain : 0); - else *res = 0; - out: - current->thread.fault_catcher = NULL; -} - -static int buffer_op(unsigned long addr, int len, int is_write, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) -{ - int faulted, res; - - faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, - &res); - if (!faulted) - return res; + if (n != 0) { + remain = (n < 0 ? remain : 0); + goto out; + } - return addr + len - (unsigned long) current->thread.fault_addr; + return 0; + out: + return remain; } static int copy_chunk_from_user(unsigned long from, int len, void *arg) diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 36d89cf8d20..e1062ec36d4 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -21,7 +21,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); #include "asm/smp.h" #include "asm/processor.h" #include "asm/spinlock.h" -#include "kern_util.h" #include "kern.h" #include "irq_user.h" #include "os.h" @@ -61,7 +60,7 @@ void smp_send_stop(void) continue; os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); } - printk(KERN_INFO "done\n"); + printk(KERN_CONT "done\n"); } static cpumask_t smp_commenced_mask = CPU_MASK_NONE; @@ -75,8 +74,7 @@ static int idle_proc(void *cpup) if (err < 0) panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); - os_set_fd_async(cpu_data[cpu].ipi_pipe[0], - current->thread.mode.tt.extern_pid); + os_set_fd_async(cpu_data[cpu].ipi_pipe[0]); wmb(); if (cpu_test_and_set(cpu, cpu_callin_map)) { @@ -129,8 +127,7 @@ void smp_prepare_cpus(unsigned int maxcpus) if (err < 0) panic("CPU#0 failed to create IPI pipe, errno = %d", -err); - os_set_fd_async(cpu_data[me].ipi_pipe[0], - current->thread.mode.tt.extern_pid); + os_set_fd_async(cpu_data[me].ipi_pipe[0]); for (cpu = 1; cpu < ncpus; cpu++) { printk(KERN_INFO "Booting processor %d...\n", cpu); @@ -143,9 +140,8 @@ void smp_prepare_cpus(unsigned int maxcpus) while (waittime-- && !cpu_isset(cpu, cpu_callin_map)) cpu_relax(); - if (cpu_isset(cpu, cpu_callin_map)) - printk(KERN_INFO "done\n"); - else printk(KERN_INFO "failed\n"); + printk(KERN_INFO "%s\n", + cpu_isset(cpu, cpu_calling_map) ? "done" : "failed"); } } diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index b9d92b2089a..9cffc628a37 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -13,9 +13,6 @@ #include "asm/uaccess.h" #include "asm/unistd.h" -/* Unlocked, I don't care if this is a bit off */ -int nsyscalls = 0; - long sys_fork(void) { long ret; diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 93263571d81..56d43d0a396 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -1,38 +1,37 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/sched.h" -#include "linux/kernel.h" -#include "linux/module.h" -#include "linux/kallsyms.h" -#include "asm/page.h" -#include "asm/processor.h" +#include <linux/kallsyms.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> #include "sysrq.h" /* Catch non-i386 SUBARCH's. */ #if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) void show_trace(struct task_struct *task, unsigned long * stack) { - unsigned long addr; + unsigned long addr; - if (!stack) { + if (!stack) { stack = (unsigned long*) &stack; WARN_ON(1); } - printk("Call Trace: \n"); - while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack; + printk(KERN_INFO "Call Trace: \n"); + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack; if (__kernel_text_address(addr)) { - printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); - print_symbol(" %s", addr); - printk("\n"); - } - stack++; - } - printk("\n"); + printk(KERN_INFO "%08lx: [<%08lx>]", + (unsigned long) stack, addr); + print_symbol(KERN_CONT " %s", addr); + printk(KERN_CONT "\n"); + } + stack++; + } + printk(KERN_INFO "\n"); } #endif @@ -67,14 +66,13 @@ void show_stack(struct task_struct *task, unsigned long *esp) } stack = esp; - for(i = 0; i < kstack_depth_to_print; i++) { + for (i = 0; i < kstack_depth_to_print; i++) { if (kstack_end(stack)) break; if (i && ((i % 8) == 0)) - printk("\n "); + printk("\n" KERN_INFO " "); printk("%08lx ", *stack++); } - printk("Call Trace: \n"); show_trace(task, esp); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 1ac746a9eae..e066e84493b 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -3,12 +3,12 @@ * Licensed under the GPL */ -#include "linux/clockchips.h" -#include "linux/interrupt.h" -#include "linux/jiffies.h" -#include "linux/threads.h" -#include "asm/irq.h" -#include "asm/param.h" +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/threads.h> +#include <asm/irq.h> +#include <asm/param.h> #include "kern_util.h" #include "os.h" @@ -32,7 +32,7 @@ void timer_handler(int sig, struct uml_pt_regs *regs) static void itimer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - switch(mode) { + switch (mode) { case CLOCK_EVT_MODE_PERIODIC: set_interval(); break; diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index f4a0e407eee..d175d0566af 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -3,9 +3,10 @@ * Licensed under the GPL */ -#include "linux/mm.h" -#include "asm/pgtable.h" -#include "asm/tlbflush.h" +#include <linux/mm.h> +#include <linux/sched.h> +#include <asm/pgtable.h> +#include <asm/tlbflush.h> #include "as-layout.h" #include "mem_user.h" #include "os.h" @@ -56,7 +57,7 @@ static int do_ops(struct host_vm_change *hvc, int end, for (i = 0; i < end && !ret; i++) { op = &hvc->ops[i]; - switch(op->type) { + switch (op->type) { case MMAP: ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len, op->u.mmap.prot, op->u.mmap.fd, @@ -183,27 +184,30 @@ static inline int update_pte_range(pmd_t *pmd, unsigned long addr, pte = pte_offset_kernel(pmd, addr); do { + if ((addr >= STUB_START) && (addr < STUB_END)) + continue; + r = pte_read(*pte); w = pte_write(*pte); x = pte_exec(*pte); if (!pte_young(*pte)) { r = 0; w = 0; - } else if (!pte_dirty(*pte)) { + } else if (!pte_dirty(*pte)) w = 0; - } + prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | (x ? UM_PROT_EXEC : 0)); if (hvc->force || pte_newpage(*pte)) { if (pte_present(*pte)) ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, PAGE_SIZE, prot, hvc); - else ret = add_munmap(addr, PAGE_SIZE, hvc); - } - else if (pte_newprot(*pte)) + else + ret = add_munmap(addr, PAGE_SIZE, hvc); + } else if (pte_newprot(*pte)) ret = add_mprotect(addr, PAGE_SIZE, prot, hvc); *pte = pte_mkuptodate(*pte); - } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret)); + } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret)); return ret; } @@ -225,7 +229,7 @@ static inline int update_pmd_range(pud_t *pud, unsigned long addr, } } else ret = update_pte_range(pmd, addr, next, hvc); - } while (pmd++, addr = next, ((addr != end) && !ret)); + } while (pmd++, addr = next, ((addr < end) && !ret)); return ret; } @@ -247,7 +251,7 @@ static inline int update_pud_range(pgd_t *pgd, unsigned long addr, } } else ret = update_pmd_range(pud, addr, next, hvc); - } while (pud++, addr = next, ((addr != end) && !ret)); + } while (pud++, addr = next, ((addr < end) && !ret)); return ret; } @@ -270,7 +274,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, } } else ret = update_pud_range(pgd, addr, next, &hvc); - } while (pgd++, addr = next, ((addr != end_addr) && !ret)); + } while (pgd++, addr = next, ((addr < end_addr) && !ret)); if (!ret) ret = do_ops(&hvc, hvc.index, 1); @@ -485,9 +489,6 @@ void __flush_tlb_one(unsigned long addr) static void fix_range(struct mm_struct *mm, unsigned long start_addr, unsigned long end_addr, int force) { - if (!proc_mm && (end_addr > STUB_START)) - end_addr = STUB_START; - fix_range_common(mm, start_addr, end_addr, force); } @@ -499,10 +500,9 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, else fix_range(vma->vm_mm, start, end, 0); } -void flush_tlb_mm(struct mm_struct *mm) +void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, + unsigned long end) { - unsigned long end; - /* * Don't bother flushing if this address space is about to be * destroyed. @@ -510,8 +510,17 @@ void flush_tlb_mm(struct mm_struct *mm) if (atomic_read(&mm->mm_users) == 0) return; - end = proc_mm ? task_size : STUB_START; - fix_range(mm, 0, end, 0); + fix_range(mm, start, end, 0); +} + +void flush_tlb_mm(struct mm_struct *mm) +{ + struct vm_area_struct *vma = mm->mmap; + + while (vma != NULL) { + fix_range(mm, vma->vm_start, vma->vm_end, 0); + vma = vma->vm_next; + } } void force_flush_all(void) diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index cb3321f8e0a..44e49041949 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -13,6 +13,7 @@ #include "as-layout.h" #include "kern_util.h" #include "os.h" +#include "skas.h" #include "sysdep/sigcontext.h" /* @@ -128,7 +129,19 @@ static void bad_segv(struct faultinfo fi, unsigned long ip) force_sig_info(SIGSEGV, &si, current); } -static void segv_handler(int sig, struct uml_pt_regs *regs) +void fatal_sigsegv(void) +{ + force_sigsegv(SIGSEGV, current); + do_signal(); + /* + * This is to tell gcc that we're not returning - do_signal + * can, in general, return, but in this case, it's not, since + * we just got a fatal SIGSEGV queued. + */ + os_dump_core(); +} + +void segv_handler(int sig, struct uml_pt_regs *regs) { struct faultinfo * fi = UPT_FAULTINFO(regs); @@ -216,9 +229,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void relay_signal(int sig, struct uml_pt_regs *regs) { - if (arch_handle_signal(sig, regs)) - return; - if (!UPT_IS_USER(regs)) { if (sig == SIGBUS) printk(KERN_ERR "Bus error - the host /dev/shm or /tmp " @@ -226,31 +236,24 @@ void relay_signal(int sig, struct uml_pt_regs *regs) panic("Kernel mode signal %d", sig); } + arch_examine_signal(sig, regs); + current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); force_sig(sig, current); } -static void bus_handler(int sig, struct uml_pt_regs *regs) +void bus_handler(int sig, struct uml_pt_regs *regs) { if (current->thread.fault_catcher != NULL) UML_LONGJMP(current->thread.fault_catcher, 1); else relay_signal(sig, regs); } -static void winch(int sig, struct uml_pt_regs *regs) +void winch(int sig, struct uml_pt_regs *regs) { do_IRQ(WINCH_IRQ, regs); } -const struct kern_handlers handlinfo_kern = { - .relay_signal = relay_signal, - .winch = winch, - .bus_handler = bus_handler, - .page_fault = segv_handler, - .sigio_handler = sigio_handler, - .timer_handler = timer_handler -}; - void trap_init(void) { } diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c index d7436aacd26..f0f4b040d7c 100644 --- a/arch/um/kernel/uaccess.c +++ b/arch/um/kernel/uaccess.c @@ -1,10 +1,11 @@ /* * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -/* These are here rather than tt/uaccess.c because skas mode needs them in +/* + * These are here rather than tt/uaccess.c because skas mode needs them in * order to do SIGBUS recovery when a tmpfs mount runs out of room. */ @@ -25,6 +26,8 @@ int __do_copy_to_user(void *to, const void *from, int n, fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) to)); + if (!faulted) + return 0; + else + return n - (fault - (unsigned long) to); } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index f1c71393f57..468aba990db 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -3,22 +3,23 @@ * Licensed under the GPL */ -#include "linux/delay.h" -#include "linux/mm.h" -#include "linux/module.h" -#include "linux/seq_file.h" -#include "linux/string.h" -#include "linux/utsname.h" -#include "asm/pgtable.h" -#include "asm/processor.h" -#include "asm/setup.h" -#include "arch.h" +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/seq_file.h> +#include <linux/string.h> +#include <linux/utsname.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/setup.h> #include "as-layout.h" +#include "arch.h" #include "init.h" #include "kern.h" +#include "kern_util.h" #include "mem_user.h" #include "os.h" -#include "skas.h" #define DEFAULT_COMMAND_LINE "root=98:0" @@ -100,8 +101,6 @@ const struct seq_operations cpuinfo_op = { }; /* Set in linux_main */ -unsigned long host_task_size; -unsigned long task_size; unsigned long uml_physmem; unsigned long uml_reserved; /* Also modified in mem_init */ unsigned long start_vm; @@ -197,20 +196,19 @@ __uml_setup("--help", Usage, " Prints this message.\n\n" ); -static int __init uml_checksetup(char *line, int *add) +static void __init uml_checksetup(char *line, int *add) { struct uml_param *p; p = &__uml_setup_start; - while(p < &__uml_setup_end) { + while (p < &__uml_setup_end) { int n; n = strlen(p->str); if (!strncmp(line, p->str, n) && p->setup_func(line + n, add)) - return 1; + return; p++; } - return 0; } static void __init uml_postsetup(void) @@ -218,13 +216,30 @@ static void __init uml_postsetup(void) initcall_t *p; p = &__uml_postsetup_start; - while(p < &__uml_postsetup_end) { + while (p < &__uml_postsetup_end) { (*p)(); p++; } return; } +static int panic_exit(struct notifier_block *self, unsigned long unused1, + void *unused2) +{ + bust_spinlocks(1); + show_regs(&(current->thread.regs)); + bust_spinlocks(0); + uml_exitcode = 1; + os_dump_core(); + return 0; +} + +static struct notifier_block panic_exit_notifier = { + .notifier_call = panic_exit, + .next = NULL, + .priority = 0 +}; + /* Set during early boot */ unsigned long brk_start; unsigned long end_iomem; @@ -234,20 +249,6 @@ EXPORT_SYMBOL(end_iomem); extern char __binary_start; -static unsigned long set_task_sizes_skas(unsigned long *task_size_out) -{ - /* Round up to the nearest 4M */ - unsigned long host_task_size = ROUND_4M((unsigned long) - &host_task_size); - - if (!skas_needs_stub) - *task_size_out = host_task_size; - else - *task_size_out = STUB_START & PGDIR_MASK; - - return host_task_size; -} - int __init linux_main(int argc, char **argv) { unsigned long avail, diff; @@ -278,13 +279,6 @@ int __init linux_main(int argc, char **argv) printf("UML running in %s mode\n", mode); - host_task_size = set_task_sizes_skas(&task_size); - - /* - * Setting up handlers to 'sig_info' struct - */ - os_fill_handlinfo(handlinfo_kern); - brk_start = (unsigned long) sbrk(0); /* @@ -309,7 +303,7 @@ int __init linux_main(int argc, char **argv) highmem = 0; iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; - max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; + max_physmem = CONFIG_TOP_ADDR - uml_physmem - iomem_size - MIN_VMALLOC; /* * Zones have to begin on a 1 << MAX_ORDER page boundary, @@ -341,7 +335,7 @@ int __init linux_main(int argc, char **argv) } virtmem_size = physmem_size; - avail = get_kmem_end() - start_vm; + avail = CONFIG_TOP_ADDR - start_vm; if (physmem_size > avail) virtmem_size = avail; end_vm = start_vm + virtmem_size; @@ -350,6 +344,9 @@ int __init linux_main(int argc, char **argv) printf("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); + atomic_notifier_chain_register(&panic_notifier_list, + &panic_exit_notifier); + uml_postsetup(); stack_protections((unsigned long) &init_thread_info); @@ -358,29 +355,8 @@ int __init linux_main(int argc, char **argv) return start_uml(); } -extern int uml_exitcode; - -static int panic_exit(struct notifier_block *self, unsigned long unused1, - void *unused2) -{ - bust_spinlocks(1); - show_regs(&(current->thread.regs)); - bust_spinlocks(0); - uml_exitcode = 1; - os_dump_core(); - return 0; -} - -static struct notifier_block panic_exit_notifier = { - .notifier_call = panic_exit, - .next = NULL, - .priority = 0 -}; - void __init setup_arch(char **cmdline_p) { - atomic_notifier_chain_register(&panic_notifier_list, - &panic_exit_notifier); paging_init(); strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 039e16efcd5..81e07e2be3a 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -1,13 +1,12 @@ -/* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "asm/errno.h" +#include <asm/errno.h> #include "init.h" -#include "os.h" #include "kern.h" -#include "linux/kernel.h" +#include "os.h" /* Changed by set_umid_arg */ static int umid_inited = 0; @@ -16,16 +15,16 @@ static int __init set_umid_arg(char *name, int *add) { int err; - if(umid_inited){ + if (umid_inited) { printf("umid already set\n"); return 0; } *add = 0; err = set_umid(name); - if(err == -EEXIST) + if (err == -EEXIST) printf("umid '%s' already in use\n", name); - else if(!err) + else if (!err) umid_inited = 1; return 0; diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 8e129af8170..8a48d6a3006 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -4,7 +4,7 @@ # obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ - registers.o sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o \ + registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ obj-$(CONFIG_TTY_LOG) += tty_log.o @@ -12,7 +12,7 @@ user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ - trap.o tty.o tls.o uaccess.o umid.o util.o + tty.o tls.o uaccess.o umid.o util.o CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index 93dc0c80eba..b8d8c9ca8d4 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -12,6 +12,7 @@ #include "aio.h" #include "init.h" #include "kern_constants.h" +#include "kern_util.h" #include "os.h" #include "user.h" diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 07ca0cb472a..6fb0b174f53 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -131,7 +131,7 @@ static int etap_tramp(char *dev, char *gate, int control_me, } if (c != 1) { printk(UM_KERN_ERR "etap_tramp : uml_net failed\n"); - err = helper_wait(pid, 0, "uml_net"); + err = helper_wait(pid); } return err; } diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 1037a3b6386..2448be03fd7 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -14,6 +14,7 @@ #include <sys/wait.h> #include <sys/uio.h> #include "kern_constants.h" +#include "kern_util.h" #include "os.h" #include "tuntap.h" #include "user.h" @@ -107,7 +108,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, "errno = %d\n", errno); return err; } - helper_wait(pid, 0, "tuntap_open_tramp"); + helper_wait(pid); cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL) { @@ -148,7 +149,7 @@ static int tuntap_open(void *data) memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); - if (ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0) { + if (ioctl(pri->fd, TUNSETIFF, &ifr) < 0) { err = -errno; printk(UM_KERN_ERR "TUNSETIFF failed, errno = %d\n", errno); diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index f8346275862..b5afcfd0f86 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -8,18 +8,16 @@ #include <errno.h> #include <fcntl.h> #include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> #include <sys/ioctl.h> #include <sys/mount.h> -#include <sys/uio.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include "kern_constants.h" #include "os.h" #include "user.h" -#include "kern_util.h" -static void copy_stat(struct uml_stat *dst, struct stat64 *src) +static void copy_stat(struct uml_stat *dst, const struct stat64 *src) { *dst = ((struct uml_stat) { .ust_dev = src->st_dev, /* device */ @@ -43,10 +41,10 @@ int os_stat_fd(const int fd, struct uml_stat *ubuf) int err; CATCH_EINTR(err = fstat64(fd, &sbuf)); - if(err < 0) + if (err < 0) return -errno; - if(ubuf != NULL) + if (ubuf != NULL) copy_stat(ubuf, &sbuf); return err; } @@ -56,27 +54,26 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf) struct stat64 sbuf; int err; - do { - err = stat64(file_name, &sbuf); - } while((err < 0) && (errno == EINTR)) ; - - if(err < 0) + CATCH_EINTR(err = stat64(file_name, &sbuf)); + if (err < 0) return -errno; - if(ubuf != NULL) + if (ubuf != NULL) copy_stat(ubuf, &sbuf); return err; } -int os_access(const char* file, int mode) +int os_access(const char *file, int mode) { int amode, err; - amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | - (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + amode = (mode & OS_ACC_R_OK ? R_OK : 0) | + (mode & OS_ACC_W_OK ? W_OK : 0) | + (mode & OS_ACC_X_OK ? X_OK : 0) | + (mode & OS_ACC_F_OK ? F_OK : 0); err = access(file, amode); - if(err < 0) + if (err < 0) return -errno; return 0; @@ -88,7 +85,7 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) int err; err = ioctl(fd, cmd, arg); - if(err < 0) + if (err < 0) return -errno; return err; @@ -97,7 +94,7 @@ int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) /* FIXME: ensure namebuf in os_get_if_name is big enough */ int os_get_ifname(int fd, char* namebuf) { - if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) + if (ioctl(fd, SIOCGIFNAME, namebuf) < 0) return -errno; return 0; @@ -108,37 +105,22 @@ int os_set_slip(int fd) int disc, sencap; disc = N_SLIP; - if(ioctl(fd, TIOCSETD, &disc) < 0) + if (ioctl(fd, TIOCSETD, &disc) < 0) return -errno; sencap = 0; - if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0) + if (ioctl(fd, SIOCSIFENCAP, &sencap) < 0) return -errno; return 0; } -int os_set_owner(int fd, int pid) -{ - if(fcntl(fd, F_SETOWN, pid) < 0){ - int save_errno = errno; - - if(fcntl(fd, F_GETOWN, 0) != pid) - return -save_errno; - } - - return 0; -} - int os_mode_fd(int fd, int mode) { int err; - do { - err = fchmod(fd, mode); - } while((err < 0) && (errno==EINTR)) ; - - if(err < 0) + CATCH_EINTR(err = fchmod(fd, mode)); + if (err < 0) return -errno; return 0; @@ -150,64 +132,73 @@ int os_file_type(char *file) int err; err = os_stat_file(file, &buf); - if(err < 0) + if (err < 0) return err; - if(S_ISDIR(buf.ust_mode)) + if (S_ISDIR(buf.ust_mode)) return OS_TYPE_DIR; - else if(S_ISLNK(buf.ust_mode)) + else if (S_ISLNK(buf.ust_mode)) return OS_TYPE_SYMLINK; - else if(S_ISCHR(buf.ust_mode)) + else if (S_ISCHR(buf.ust_mode)) return OS_TYPE_CHARDEV; - else if(S_ISBLK(buf.ust_mode)) + else if (S_ISBLK(buf.ust_mode)) return OS_TYPE_BLOCKDEV; - else if(S_ISFIFO(buf.ust_mode)) + else if (S_ISFIFO(buf.ust_mode)) return OS_TYPE_FIFO; - else if(S_ISSOCK(buf.ust_mode)) + else if (S_ISSOCK(buf.ust_mode)) return OS_TYPE_SOCK; else return OS_TYPE_FILE; } -int os_file_mode(char *file, struct openflags *mode_out) +int os_file_mode(const char *file, struct openflags *mode_out) { int err; *mode_out = OPENFLAGS(); err = access(file, W_OK); - if(err && (errno != EACCES)) + if (err && (errno != EACCES)) return -errno; - else if(!err) + else if (!err) *mode_out = of_write(*mode_out); err = access(file, R_OK); - if(err && (errno != EACCES)) + if (err && (errno != EACCES)) return -errno; - else if(!err) + else if (!err) *mode_out = of_read(*mode_out); return err; } -int os_open_file(char *file, struct openflags flags, int mode) +int os_open_file(const char *file, struct openflags flags, int mode) { int fd, err, f = 0; - if(flags.r && flags.w) f = O_RDWR; - else if(flags.r) f = O_RDONLY; - else if(flags.w) f = O_WRONLY; + if (flags.r && flags.w) + f = O_RDWR; + else if (flags.r) + f = O_RDONLY; + else if (flags.w) + f = O_WRONLY; else f = 0; - if(flags.s) f |= O_SYNC; - if(flags.c) f |= O_CREAT; - if(flags.t) f |= O_TRUNC; - if(flags.e) f |= O_EXCL; + if (flags.s) + f |= O_SYNC; + if (flags.c) + f |= O_CREAT; + if (flags.t) + f |= O_TRUNC; + if (flags.e) + f |= O_EXCL; + if (flags.a) + f |= O_APPEND; fd = open64(file, f, mode); - if(fd < 0) + if (fd < 0) return -errno; - if(flags.cl && fcntl(fd, F_SETFD, 1)){ + if (flags.cl && fcntl(fd, F_SETFD, 1)) { err = -errno; close(fd); return err; @@ -216,7 +207,7 @@ int os_open_file(char *file, struct openflags flags, int mode) return fd; } -int os_connect_socket(char *name) +int os_connect_socket(const char *name) { struct sockaddr_un sock; int fd, err; @@ -225,13 +216,13 @@ int os_connect_socket(char *name) snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); fd = socket(AF_UNIX, SOCK_STREAM, 0); - if(fd < 0) { + if (fd < 0) { err = -errno; goto out; } err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); - if(err) { + if (err) { err = -errno; goto out_close; } @@ -254,7 +245,7 @@ int os_seek_file(int fd, unsigned long long offset) unsigned long long actual; actual = lseek64(fd, offset, SEEK_SET); - if(actual != offset) + if (actual != offset) return -errno; return 0; } @@ -263,7 +254,7 @@ int os_read_file(int fd, void *buf, int len) { int n = read(fd, buf, len); - if(n < 0) + if (n < 0) return -errno; return n; } @@ -272,37 +263,38 @@ int os_write_file(int fd, const void *buf, int len) { int n = write(fd, (void *) buf, len); - if(n < 0) + if (n < 0) return -errno; return n; } -int os_file_size(char *file, unsigned long long *size_out) +int os_file_size(const char *file, unsigned long long *size_out) { struct uml_stat buf; int err; err = os_stat_file(file, &buf); - if(err < 0){ - printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + if (err < 0) { + printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, + -err); return err; } - if(S_ISBLK(buf.ust_mode)){ + if (S_ISBLK(buf.ust_mode)) { int fd; long blocks; fd = open(file, O_RDONLY, 0); - if(fd < 0) { + if (fd < 0) { err = -errno; - printk("Couldn't open \"%s\", errno = %d\n", file, - errno); + printk(UM_KERN_ERR "Couldn't open \"%s\", " + "errno = %d\n", file, errno); return err; } - if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ + if (ioctl(fd, BLKGETSIZE, &blocks) < 0) { err = -errno; - printk("Couldn't get the block size of \"%s\", " - "errno = %d\n", file, errno); + printk(UM_KERN_ERR "Couldn't get the block size of " + "\"%s\", errno = %d\n", file, errno); close(fd); return err; } @@ -314,14 +306,15 @@ int os_file_size(char *file, unsigned long long *size_out) return 0; } -int os_file_modtime(char *file, unsigned long *modtime) +int os_file_modtime(const char *file, unsigned long *modtime) { struct uml_stat buf; int err; err = os_stat_file(file, &buf); - if(err < 0){ - printk("Couldn't stat \"%s\" : err = %d\n", file, -err); + if (err < 0) { + printk(UM_KERN_ERR "Couldn't stat \"%s\" : err = %d\n", file, + -err); return err; } @@ -329,26 +322,13 @@ int os_file_modtime(char *file, unsigned long *modtime) return 0; } -int os_get_exec_close(int fd, int *close_on_exec) -{ - int ret; - - CATCH_EINTR(ret = fcntl(fd, F_GETFD)); - - if(ret < 0) - return -errno; - - *close_on_exec = (ret & FD_CLOEXEC) ? 1 : 0; - return ret; -} - int os_set_exec_close(int fd) { int err; CATCH_EINTR(err = fcntl(fd, F_SETFD, FD_CLOEXEC)); - if(err < 0) + if (err < 0) return -errno; return err; } @@ -358,53 +338,51 @@ int os_pipe(int *fds, int stream, int close_on_exec) int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; err = socketpair(AF_UNIX, type, 0, fds); - if(err < 0) + if (err < 0) return -errno; - if(!close_on_exec) + if (!close_on_exec) return 0; err = os_set_exec_close(fds[0]); - if(err < 0) + if (err < 0) goto error; err = os_set_exec_close(fds[1]); - if(err < 0) + if (err < 0) goto error; return 0; error: - printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); + printk(UM_KERN_ERR "os_pipe : Setting FD_CLOEXEC failed, err = %d\n", + -err); close(fds[1]); close(fds[0]); return err; } -int os_set_fd_async(int fd, int owner) +int os_set_fd_async(int fd) { - int err; + int err, flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; - /* XXX This should do F_GETFL first */ - if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){ + flags |= O_ASYNC | O_NONBLOCK; + if (fcntl(fd, F_SETFL, flags) < 0) { err = -errno; - printk("os_set_fd_async : failed to set O_ASYNC and " - "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); + printk(UM_KERN_ERR "os_set_fd_async : failed to set O_ASYNC " + "and O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); return err; } -#ifdef notdef - if(fcntl(fd, F_SETFD, 1) < 0){ - printk("os_set_fd_async : Setting FD_CLOEXEC failed, " - "errno = %d\n", errno); - } -#endif - if((fcntl(fd, F_SETSIG, SIGIO) < 0) || - (fcntl(fd, F_SETOWN, owner) < 0)){ + if ((fcntl(fd, F_SETSIG, SIGIO) < 0) || + (fcntl(fd, F_SETOWN, os_getpid()) < 0)) { err = -errno; - printk("os_set_fd_async : Failed to fcntl F_SETOWN " - "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, - owner, errno); + printk(UM_KERN_ERR "os_set_fd_async : Failed to fcntl F_SETOWN " + "(or F_SETSIG) fd %d, errno = %d\n", fd, errno); return err; } @@ -413,10 +391,14 @@ int os_set_fd_async(int fd, int owner) int os_clear_fd_async(int fd) { - int flags = fcntl(fd, F_GETFL); + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; flags &= ~(O_ASYNC | O_NONBLOCK); - if(fcntl(fd, F_SETFL, flags) < 0) + if (fcntl(fd, F_SETFL, flags) < 0) return -errno; return 0; } @@ -426,11 +408,15 @@ int os_set_fd_block(int fd, int blocking) int flags; flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; - if(blocking) flags &= ~O_NONBLOCK; - else flags |= O_NONBLOCK; + if (blocking) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; - if(fcntl(fd, F_SETFL, flags) < 0) + if (fcntl(fd, F_SETFL, flags) < 0) return -errno; return 0; @@ -441,7 +427,7 @@ int os_accept_connection(int fd) int new; new = accept(fd, NULL, 0); - if(new < 0) + if (new < 0) return -errno; return new; } @@ -462,15 +448,17 @@ int os_shutdown_socket(int fd, int r, int w) { int what, err; - if(r && w) what = SHUT_RDWR; - else if(r) what = SHUT_RD; - else if(w) what = SHUT_WR; - else { - printk("os_shutdown_socket : neither r or w was set\n"); + if (r && w) + what = SHUT_RDWR; + else if (r) + what = SHUT_RD; + else if (w) + what = SHUT_WR; + else return -EINVAL; - } + err = shutdown(fd, what); - if(err < 0) + if (err < 0) return -errno; return 0; } @@ -494,19 +482,20 @@ int os_rcv_fd(int fd, int *helper_pid_out) msg.msg_flags = 0; n = recvmsg(fd, &msg, 0); - if(n < 0) + if (n < 0) return -errno; - else if(n != iov.iov_len) + else if (n != iov.iov_len) *helper_pid_out = -1; cmsg = CMSG_FIRSTHDR(&msg); - if(cmsg == NULL){ - printk("rcv_fd didn't receive anything, error = %d\n", errno); + if (cmsg == NULL) { + printk(UM_KERN_ERR "rcv_fd didn't receive anything, " + "error = %d\n", errno); return -1; } - if((cmsg->cmsg_level != SOL_SOCKET) || - (cmsg->cmsg_type != SCM_RIGHTS)){ - printk("rcv_fd didn't receive a descriptor\n"); + if ((cmsg->cmsg_level != SOL_SOCKET) || + (cmsg->cmsg_type != SCM_RIGHTS)) { + printk(UM_KERN_ERR "rcv_fd didn't receive a descriptor\n"); return -1; } @@ -514,29 +503,28 @@ int os_rcv_fd(int fd, int *helper_pid_out) return new; } -int os_create_unix_socket(char *file, int len, int close_on_exec) +int os_create_unix_socket(const char *file, int len, int close_on_exec) { struct sockaddr_un addr; int sock, err; sock = socket(PF_UNIX, SOCK_DGRAM, 0); - if(sock < 0) + if (sock < 0) return -errno; - if(close_on_exec) { + if (close_on_exec) { err = os_set_exec_close(sock); - if(err < 0) - printk("create_unix_socket : close_on_exec failed, " - "err = %d", -err); + if (err < 0) + printk(UM_KERN_ERR "create_unix_socket : " + "close_on_exec failed, err = %d", -err); } addr.sun_family = AF_UNIX; - /* XXX Be more careful about overflow */ snprintf(addr.sun_path, len, "%s", file); err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); - if(err < 0) + if (err < 0) return -errno; return sock; @@ -557,17 +545,18 @@ int os_lock_file(int fd, int excl) int err, save; err = fcntl(fd, F_SETLK, &lock); - if(!err) + if (!err) goto out; save = -errno; err = fcntl(fd, F_GETLK, &lock); - if(err){ + if (err) { err = -errno; goto out; } - printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); + printk(UM_KERN_ERR "F_SETLK failed, file already locked by pid %d\n", + lock.l_pid); err = save; out: return err; diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index fba3f0fefee..f4bd349d441 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -1,22 +1,19 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sched.h> -#include <limits.h> -#include <sys/signal.h> -#include <sys/wait.h> #include <sys/socket.h> -#include "user.h" +#include <sys/wait.h> +#include "kern_constants.h" #include "kern_util.h" #include "os.h" #include "um_malloc.h" -#include "kern_constants.h" +#include "user.h" struct helper_data { void (*pre_exec)(void*); @@ -30,21 +27,19 @@ static int helper_child(void *arg) { struct helper_data *data = arg; char **argv = data->argv; - int errval; + int err; if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); - errval = execvp_noalloc(data->buf, argv[0], argv); - printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], - -errval); - write(data->fd, &errval, sizeof(errval)); - kill(os_getpid(), SIGKILL); + err = execvp_noalloc(data->buf, argv[0], argv); + + /* If the exec succeeds, we don't get here */ + write(data->fd, &err, sizeof(err)); + return 0; } -/* Returns either the pid of the child process we run or -E* on failure. - * XXX The alloc_stack here breaks if this is called in the tracing thread, so - * we need to receive a preallocated stack (a local buffer is ok). */ +/* Returns either the pid of the child process we run or -E* on failure. */ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) { struct helper_data data; @@ -58,14 +53,15 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); if (ret < 0) { ret = -errno; - printk("run_helper : pipe failed, errno = %d\n", errno); + printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n", + errno); goto out_free; } ret = os_set_exec_close(fds[1]); if (ret < 0) { - printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n", - -ret); + printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, " + "ret = %d\n", -ret); goto out_close; } @@ -79,7 +75,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) pid = clone(helper_child, (void *) sp, CLONE_VM, &data); if (pid < 0) { ret = -errno; - printk("run_helper : clone failed, errno = %d\n", errno); + printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n", + errno); goto out_free2; } @@ -96,10 +93,9 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) } else { if (n < 0) { n = -errno; - printk("run_helper : read on pipe failed, ret = %d\n", - -n); + printk(UM_KERN_ERR "run_helper : read on pipe failed, " + "ret = %d\n", -n); ret = n; - kill(pid, SIGKILL); } CATCH_EINTR(waitpid(pid, NULL, __WCLONE)); } @@ -129,50 +125,40 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, pid = clone(proc, (void *) sp, flags, arg); if (pid < 0) { err = -errno; - printk("run_helper_thread : clone failed, errno = %d\n", - errno); + printk(UM_KERN_ERR "run_helper_thread : clone failed, " + "errno = %d\n", errno); return err; } if (stack_out == NULL) { CATCH_EINTR(pid = waitpid(pid, &status, __WCLONE)); if (pid < 0) { err = -errno; - printk("run_helper_thread - wait failed, errno = %d\n", - errno); + printk(UM_KERN_ERR "run_helper_thread - wait failed, " + "errno = %d\n", errno); pid = err; } if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - printk("run_helper_thread - thread returned status " - "0x%x\n", status); + printk(UM_KERN_ERR "run_helper_thread - thread " + "returned status 0x%x\n", status); free_stack(stack, 0); } else *stack_out = stack; return pid; } -int helper_wait(int pid, int nohang, char *pname) +int helper_wait(int pid) { int ret, status; int wflags = __WCLONE; - if (nohang) - wflags |= WNOHANG; - - if (!pname) - pname = "helper_wait"; - CATCH_EINTR(ret = waitpid(pid, &status, wflags)); if (ret < 0) { - printk(UM_KERN_ERR "%s : waitpid process %d failed, " - "errno = %d\n", pname, pid, errno); + printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, " + "errno = %d\n", pid, errno); return -errno; - } else if (nohang && ret == 0) { - printk(UM_KERN_ERR "%s : process %d has not exited\n", - pname, pid); - return -ECHILD; } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - printk(UM_KERN_ERR "%s : process %d didn't exit with " - "status 0\n", pname, pid); + printk(UM_KERN_ERR "helper_wait : process %d exited with " + "status 0x%x\n", pid, status); return -ECHILD; } else return 0; diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index 6aa6f95d652..0348b975e81 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c @@ -1,23 +1,19 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdlib.h> -#include <unistd.h> #include <errno.h> +#include <poll.h> #include <signal.h> #include <string.h> -#include <sys/poll.h> -#include <sys/types.h> -#include <sys/time.h> -#include "kern_util.h" -#include "user.h" -#include "process.h" -#include "sigio.h" #include "irq_user.h" +#include "kern_constants.h" #include "os.h" +#include "process.h" #include "um_malloc.h" +#include "user.h" /* * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd @@ -36,7 +32,7 @@ int os_waiting_for_events(struct irq_fd *active_fds) if (n < 0) { err = -errno; if (errno != EINTR) - printk("sigio_handler: os_waiting_for_events:" + printk(UM_KERN_ERR "os_waiting_for_events:" " poll returned %d, errno = %d\n", n, errno); return err; } @@ -95,24 +91,26 @@ void os_free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg, struct irq_fd *old_fd = *prev; if ((pollfds[i].fd != -1) && (pollfds[i].fd != (*prev)->fd)) { - printk("os_free_irq_by_cb - mismatch between " - "active_fds and pollfds, fd %d vs %d\n", + printk(UM_KERN_ERR "os_free_irq_by_cb - " + "mismatch between active_fds and " + "pollfds, fd %d vs %d\n", (*prev)->fd, pollfds[i].fd); goto out; } pollfds_num--; - /* This moves the *whole* array after pollfds[i] + /* + * This moves the *whole* array after pollfds[i] * (though it doesn't spot as such)! */ memmove(&pollfds[i], &pollfds[i + 1], (pollfds_num - i) * sizeof(pollfds[0])); - if(*last_irq_ptr2 == &old_fd->next) + if (*last_irq_ptr2 == &old_fd->next) *last_irq_ptr2 = prev; *prev = (*prev)->next; - if(old_fd->type == IRQ_WRITE) + if (old_fd->type == IRQ_WRITE) ignore_sigio_fd(old_fd->fd); kfree(old_fd); continue; @@ -138,14 +136,3 @@ void os_set_ioignore(void) { signal(SIGIO, SIG_IGN); } - -void init_irq_signals(int on_sigstack) -{ - int flags; - - flags = on_sigstack ? SA_ONSTACK : 0; - - set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); - signal(SIGWINCH, SIG_IGN); -} diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index 82c3778627b..abb9b0ffd96 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -73,7 +73,7 @@ static void install_fatal_handler(int sig) action.sa_handler = last_ditch_exit; if (sigaction(sig, &action, NULL) < 0) { printf("failed to install handler for signal %d - errno = %d\n", - errno); + sig, errno); exit(1); } } @@ -92,7 +92,8 @@ static void setup_env_path(void) * just use the default + /usr/lib/uml */ if (!old_path || (path_len = strlen(old_path)) == 0) { - putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH); + if (putenv("PATH=:/bin:/usr/bin/" UML_LIB_PATH)) + perror("couldn't putenv"); return; } @@ -100,15 +101,16 @@ static void setup_env_path(void) path_len += strlen("PATH=" UML_LIB_PATH) + 1; new_path = malloc(path_len); if (!new_path) { - perror("coudn't malloc to set a new PATH"); + perror("couldn't malloc to set a new PATH"); return; } snprintf(new_path, path_len, "PATH=%s" UML_LIB_PATH, old_path); - putenv(new_path); + if (putenv(new_path)) { + perror("couldn't putenv to set a new PATH"); + free(new_path); + } } -extern int uml_exitcode; - extern void scan_elf_aux( char **envp); int __init main(int argc, char **argv, char **envp) diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 436f8d20b20..eedc2d88ef8 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -9,7 +9,6 @@ #include <sys/types.h> #include <sys/mman.h> #include <sys/statfs.h> -#include "kern_util.h" #include "user.h" #include "mem_user.h" #include "init.h" @@ -30,7 +29,7 @@ static char *tempdir = NULL; static void __init find_tempdir(void) { - char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; + const char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; int i; char *dir = NULL; @@ -59,9 +58,10 @@ static void __init find_tempdir(void) * read the file as needed. If there's an error, -errno is returned; * if the end of the file is reached, 0 is returned. */ -static int next(int fd, char *buf, int size, char c) +static int next(int fd, char *buf, size_t size, char c) { - int n, len; + ssize_t n; + size_t len; char *ptr; while((ptr = strchr(buf, c)) == NULL){ @@ -172,13 +172,15 @@ int __init make_tempfile(const char *template, char **out_tempname, which_tmpdir(); tempname = malloc(MAXPATHLEN); + if (!tempname) + goto out; find_tempdir(); if (template[0] != '/') strcpy(tempname, tempdir); else tempname[0] = '\0'; - strcat(tempname, template); + strncat(tempname, template, MAXPATHLEN-1-strlen(tempname)); fd = mkstemp(tempname); if(fd < 0){ fprintf(stderr, "open - cannot create %s: %s\n", tempname, @@ -268,6 +270,7 @@ void __init check_tmpexec(void) if(addr == MAP_FAILED){ err = errno; perror("failed"); + close(fd); if(err == EPERM) printf("%s must be not mounted noexec\n",tempdir); exit(1); diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index bda5c3150d6..abf6beae3df 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -249,7 +249,10 @@ void init_new_thread_signals(void) SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); signal(SIGHUP, SIG_IGN); - init_irq_signals(1); + set_handler(SIGIO, (__sighandler_t) sig_handler, + SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, + SIGVTALRM, -1); + signal(SIGWINCH, SIG_IGN); } int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr) diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index a32ba6ab121..830fe6a1518 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c @@ -8,47 +8,41 @@ #include <string.h> #include <sys/ptrace.h> #include "sysdep/ptrace.h" -#include "user.h" -/* This is set once at boot time and not changed thereafter */ - -static unsigned long exec_regs[MAX_REG_NR]; - -void init_thread_registers(struct uml_pt_regs *to) -{ - memcpy(to->gp, exec_regs, sizeof(to->gp)); -} - -void save_registers(int pid, struct uml_pt_regs *regs) +int save_registers(int pid, struct uml_pt_regs *regs) { int err; err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); if (err < 0) - panic("save_registers - saving registers failed, errno = %d\n", - errno); + return -errno; + return 0; } -void restore_registers(int pid, struct uml_pt_regs *regs) +int restore_registers(int pid, struct uml_pt_regs *regs) { int err; err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); if (err < 0) - panic("restore_registers - saving registers failed, " - "errno = %d\n", errno); + return -errno; + return 0; } -void init_registers(int pid) +/* This is set once at boot time and not changed thereafter */ + +static unsigned long exec_regs[MAX_REG_NR]; + +int init_registers(int pid) { int err; err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs); - if (err) - panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", - errno); + if (err < 0) + return -errno; arch_init_registers(pid); + return 0; } void get_safe_registers(unsigned long *regs) diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index dc03e9cccb6..abf47a7c4ab 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -1,34 +1,33 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <unistd.h> -#include <stdlib.h> -#include <termios.h> +#include <errno.h> +#include <fcntl.h> +#include <poll.h> #include <pty.h> +#include <sched.h> #include <signal.h> -#include <fcntl.h> -#include <errno.h> #include <string.h> -#include <sched.h> -#include <sys/socket.h> -#include <sys/poll.h> -#include "init.h" -#include "user.h" +#include "kern_constants.h" #include "kern_util.h" -#include "sigio.h" +#include "init.h" #include "os.h" +#include "sigio.h" #include "um_malloc.h" -#include "init.h" +#include "user.h" -/* Protected by sigio_lock(), also used by sigio_cleanup, which is an +/* + * Protected by sigio_lock(), also used by sigio_cleanup, which is an * exitcall. */ static int write_sigio_pid = -1; static unsigned long write_sigio_stack; -/* These arrays are initialized before the sigio thread is started, and +/* + * These arrays are initialized before the sigio thread is started, and * the descriptors closed after it is killed. So, it can't see them change. * On the UML side, they are changed under the sigio_lock. */ @@ -43,7 +42,8 @@ struct pollfds { int used; }; -/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread +/* + * Protected by sigio_lock(). Used by the sigio thread, but the UML thread * synchronizes with it. */ static struct pollfds current_poll; @@ -57,23 +57,26 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; - signal(SIGWINCH, SIG_IGN); + signal(SIGWINCH, SIG_IGN); fds = ¤t_poll; - while(1){ + while (1) { n = poll(fds->poll, fds->used, -1); - if(n < 0){ - if(errno == EINTR) continue; - printk("write_sigio_thread : poll returned %d, " - "errno = %d\n", n, errno); + if (n < 0) { + if (errno == EINTR) + continue; + printk(UM_KERN_ERR "write_sigio_thread : poll returned " + "%d, errno = %d\n", n, errno); } - for(i = 0; i < fds->used; i++){ + for (i = 0; i < fds->used; i++) { p = &fds->poll[i]; - if(p->revents == 0) continue; - if(p->fd == sigio_private[1]){ + if (p->revents == 0) + continue; + if (p->fd == sigio_private[1]) { CATCH_EINTR(n = read(sigio_private[1], &c, sizeof(c))); - if(n != sizeof(c)) - printk("write_sigio_thread : " + if (n != sizeof(c)) + printk(UM_KERN_ERR + "write_sigio_thread : " "read on socket failed, " "err = %d\n", errno); tmp = current_poll; @@ -89,9 +92,10 @@ static int write_sigio_thread(void *unused) } CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); - if(n != sizeof(c)) - printk("write_sigio_thread : write on socket " - "failed, err = %d\n", errno); + if (n != sizeof(c)) + printk(UM_KERN_ERR "write_sigio_thread : " + "write on socket failed, err = %d\n", + errno); } } @@ -102,12 +106,13 @@ static int need_poll(struct pollfds *polls, int n) { struct pollfd *new; - if(n <= polls->size) + if (n <= polls->size) return 0; new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); - if(new == NULL){ - printk("need_poll : failed to allocate new pollfds\n"); + if (new == NULL) { + printk(UM_KERN_ERR "need_poll : failed to allocate new " + "pollfds\n"); return -ENOMEM; } @@ -119,7 +124,8 @@ static int need_poll(struct pollfds *polls, int n) return 0; } -/* Must be called with sigio_lock held, because it's needed by the marked +/* + * Must be called with sigio_lock held, because it's needed by the marked * critical section. */ static void update_thread(void) @@ -129,15 +135,17 @@ static void update_thread(void) char c; flags = set_signals(0); - n = write(sigio_private[0], &c, sizeof(c)); - if(n != sizeof(c)){ - printk("update_thread : write failed, err = %d\n", errno); + CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); + if (n != sizeof(c)) { + printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", + errno); goto fail; } CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); - if(n != sizeof(c)){ - printk("update_thread : read failed, err = %d\n", errno); + if (n != sizeof(c)) { + printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", + errno); goto fail; } @@ -164,23 +172,23 @@ int add_sigio_fd(int fd) int err = 0, i, n; sigio_lock(); - for(i = 0; i < all_sigio_fds.used; i++){ - if(all_sigio_fds.poll[i].fd == fd) + for (i = 0; i < all_sigio_fds.used; i++) { + if (all_sigio_fds.poll[i].fd == fd) break; } - if(i == all_sigio_fds.used) + if (i == all_sigio_fds.used) goto out; p = &all_sigio_fds.poll[i]; - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) + for (i = 0; i < current_poll.used; i++) { + if (current_poll.poll[i].fd == fd) goto out; } n = current_poll.used; err = need_poll(&next_poll, n + 1); - if(err) + if (err) goto out; memcpy(next_poll.poll, current_poll.poll, @@ -198,27 +206,29 @@ int ignore_sigio_fd(int fd) struct pollfd *p; int err = 0, i, n = 0; - /* This is called from exitcalls elsewhere in UML - if + /* + * This is called from exitcalls elsewhere in UML - if * sigio_cleanup has already run, then update_thread will hang * or fail because the thread is no longer running. */ - if(write_sigio_pid == -1) + if (write_sigio_pid == -1) return -EIO; sigio_lock(); - for(i = 0; i < current_poll.used; i++){ - if(current_poll.poll[i].fd == fd) break; + for (i = 0; i < current_poll.used; i++) { + if (current_poll.poll[i].fd == fd) + break; } - if(i == current_poll.used) + if (i == current_poll.used) goto out; err = need_poll(&next_poll, current_poll.used - 1); - if(err) + if (err) goto out; - for(i = 0; i < current_poll.used; i++){ + for (i = 0; i < current_poll.used; i++) { p = ¤t_poll.poll[i]; - if(p->fd != fd) + if (p->fd != fd) next_poll.poll[n++] = *p; } next_poll.used = current_poll.used - 1; @@ -235,7 +245,8 @@ static struct pollfd *setup_initial_poll(int fd) p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); if (p == NULL) { - printk("setup_initial_poll : failed to allocate poll\n"); + printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " + "poll\n"); return NULL; } *p = ((struct pollfd) { .fd = fd, @@ -261,27 +272,29 @@ static void write_sigio_workaround(void) return; err = os_pipe(l_write_sigio_fds, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 1 failed, " + if (err < 0) { + printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " "err = %d\n", -err); return; } err = os_pipe(l_sigio_private, 1, 1); - if(err < 0){ - printk("write_sigio_workaround - os_pipe 2 failed, " + if (err < 0) { + printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " "err = %d\n", -err); goto out_close1; } p = setup_initial_poll(l_sigio_private[1]); - if(!p) + if (!p) goto out_close2; sigio_lock(); - /* Did we race? Don't try to optimize this, please, it's not so likely - * to happen, and no more than once at the boot. */ - if(write_sigio_pid != -1) + /* + * Did we race? Don't try to optimize this, please, it's not so likely + * to happen, and no more than once at the boot. + */ + if (write_sigio_pid != -1) goto out_free; current_poll = ((struct pollfds) { .poll = p, @@ -333,19 +346,19 @@ void maybe_sigio_broken(int fd, int read) { int err; - if(!isatty(fd)) + if (!isatty(fd)) return; - if((read || pty_output_sigio) && (!read || pty_close_sigio)) + if ((read || pty_output_sigio) && (!read || pty_close_sigio)) return; write_sigio_workaround(); sigio_lock(); err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); - if(err){ - printk("maybe_sigio_broken - failed to add pollfd for " - "descriptor %d\n", fd); + if (err) { + printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " + "for descriptor %d\n", fd); goto out; } @@ -388,7 +401,7 @@ static void openpty_cb(void *arg) struct openpty_arg *info = arg; info->err = 0; - if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) + if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) info->err = -errno; } @@ -397,17 +410,17 @@ static int async_pty(int master, int slave) int flags; flags = fcntl(master, F_GETFL); - if(flags < 0) + if (flags < 0) return -errno; - if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)) + if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || + (fcntl(master, F_SETOWN, os_getpid()) < 0)) return -errno; - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) return -errno; - return(0); + return 0; } static void __init check_one_sigio(void (*proc)(int, int)) @@ -417,34 +430,49 @@ static void __init check_one_sigio(void (*proc)(int, int)) int master, slave, err; initial_thread_cb(openpty_cb, &pty); - if(pty.err){ - printk("openpty failed, errno = %d\n", -pty.err); + if (pty.err) { + printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", + -pty.err); return; } master = pty.master; slave = pty.slave; - if((master == -1) || (slave == -1)){ - printk("openpty failed to allocate a pty\n"); + if ((master == -1) || (slave == -1)) { + printk(UM_KERN_ERR "check_one_sigio failed to allocate a " + "pty\n"); return; } /* Not now, but complain so we now where we failed. */ err = raw(master); - if (err < 0) - panic("check_sigio : __raw failed, errno = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", + -err); + return; + } err = async_pty(master, slave); - if(err < 0) - panic("tty_fds : sigio_async failed, err = %d\n", -err); + if (err < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " + "err = %d\n", -err); + return; + } + + if (sigaction(SIGIO, NULL, &old) < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " + "errno = %d\n", errno); + return; + } - if(sigaction(SIGIO, NULL, &old) < 0) - panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); new = old; new.sa_handler = handler; - if(sigaction(SIGIO, &new, NULL) < 0) - panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); + if (sigaction(SIGIO, &new, NULL) < 0) { + printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " + "errno = %d\n", errno); + return; + } got_sigio = 0; (*proc)(master, slave); @@ -452,8 +480,9 @@ static void __init check_one_sigio(void (*proc)(int, int)) close(master); close(slave); - if(sigaction(SIGIO, &old, NULL) < 0) - panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); + if (sigaction(SIGIO, &old, NULL) < 0) + printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " + "errno = %d\n", errno); } static void tty_output(int master, int slave) @@ -461,42 +490,45 @@ static void tty_output(int master, int slave) int n; char buf[512]; - printk("Checking that host ptys support output SIGIO..."); + printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); memset(buf, 0, sizeof(buf)); - while(write(master, buf, sizeof(buf)) > 0) ; - if(errno != EAGAIN) - panic("tty_output : write failed, errno = %d\n", errno); - while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; + while (write(master, buf, sizeof(buf)) > 0) ; + if (errno != EAGAIN) + printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", + errno); + while (((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) + ; - if(got_sigio){ - printk("Yes\n"); + if (got_sigio) { + printk(UM_KERN_CONT "Yes\n"); pty_output_sigio = 1; - } - else if(n == -EAGAIN) - printk("No, enabling workaround\n"); - else panic("tty_output : read failed, err = %d\n", n); + } else if (n == -EAGAIN) + printk(UM_KERN_CONT "No, enabling workaround\n"); + else + printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); } static void tty_close(int master, int slave) { - printk("Checking that host ptys support SIGIO on close..."); + printk(UM_KERN_INFO "Checking that host ptys support SIGIO on " + "close..."); close(slave); - if(got_sigio){ - printk("Yes\n"); + if (got_sigio) { + printk(UM_KERN_CONT "Yes\n"); pty_close_sigio = 1; - } - else printk("No, enabling workaround\n"); + } else + printk(UM_KERN_CONT "No, enabling workaround\n"); } void __init check_sigio(void) { - if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && - (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ - printk("No pseudo-terminals available - skipping pty SIGIO " - "check\n"); + if ((access("/dev/ptmx", R_OK) < 0) && + (access("/dev/ptyp0", R_OK) < 0)) { + printk(UM_KERN_WARNING "No pseudo-terminals available - " + "skipping pty SIGIO check\n"); return; } check_one_sigio(tty_output); diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index e9800b0b568..0fb0cc8d475 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -9,11 +9,47 @@ #include <errno.h> #include <signal.h> #include <strings.h> +#include "as-layout.h" +#include "kern_util.h" #include "os.h" #include "sysdep/barrier.h" #include "sysdep/sigcontext.h" #include "user.h" +/* Copied from linux/compiler-gcc.h since we can't include it directly */ +#define barrier() __asm__ __volatile__("": : :"memory") + +void (*sig_info[NSIG])(int, struct uml_pt_regs *) = { + [SIGTRAP] = relay_signal, + [SIGFPE] = relay_signal, + [SIGILL] = relay_signal, + [SIGWINCH] = winch, + [SIGBUS] = bus_handler, + [SIGSEGV] = segv_handler, + [SIGIO] = sigio_handler, + [SIGVTALRM] = timer_handler }; + +static void sig_handler_common(int sig, struct sigcontext *sc) +{ + struct uml_pt_regs r; + int save_errno = errno; + + r.is_user = 0; + if (sig == SIGSEGV) { + /* For segfaults, we want the data from the sigcontext. */ + copy_sc(&r, sc); + GET_FAULTINFO_FROM_SC(r.faultinfo, sc); + } + + /* enable signals if sig isn't IRQ signal */ + if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) + unblock_signals(); + + (*sig_info[sig])(sig, &r); + + errno = save_errno; +} + /* * These are the asynchronous signals. SIGPROF is excluded because we want to * be able to profile all of UML, not just the non-critical sections. If @@ -26,13 +62,8 @@ #define SIGVTALRM_BIT 1 #define SIGVTALRM_MASK (1 << SIGVTALRM_BIT) -/* - * These are used by both the signal handlers and - * block/unblock_signals. I don't want modifications cached in a - * register - they must go straight to memory. - */ -static volatile int signals_enabled = 1; -static volatile int pending = 0; +static int signals_enabled; +static unsigned int signals_pending; void sig_handler(int sig, struct sigcontext *sc) { @@ -40,13 +71,13 @@ void sig_handler(int sig, struct sigcontext *sc) enabled = signals_enabled; if (!enabled && (sig == SIGIO)) { - pending |= SIGIO_MASK; + signals_pending |= SIGIO_MASK; return; } block_signals(); - sig_handler_common_skas(sig, sc); + sig_handler_common(sig, sc); set_signals(enabled); } @@ -68,7 +99,7 @@ void alarm_handler(int sig, struct sigcontext *sc) enabled = signals_enabled; if (!signals_enabled) { - pending |= SIGVTALRM_MASK; + signals_pending |= SIGVTALRM_MASK; return; } @@ -94,16 +125,6 @@ void set_sigstack(void *sig_stack, int size) panic("enabling signal stack failed, errno = %d\n", errno); } -void remove_sigstack(void) -{ - stack_t stack = ((stack_t) { .ss_flags = SS_DISABLE, - .ss_sp = NULL, - .ss_size = 0 }); - - if (sigaltstack(&stack, NULL) != 0) - panic("disabling signal stack failed, errno = %d\n", errno); -} - void (*handlers[_NSIG])(int sig, struct sigcontext *sc); void handle_signal(int sig, struct sigcontext *sc) @@ -166,6 +187,9 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) sigaddset(&action.sa_mask, mask); va_end(ap); + if (sig == SIGSEGV) + flags |= SA_NODEFER; + action.sa_flags = flags; action.sa_restorer = NULL; if (sigaction(sig, &action, NULL) < 0) @@ -179,12 +203,14 @@ void set_handler(int sig, void (*handler)(int), int flags, ...) int change_sig(int signal, int on) { - sigset_t sigset, old; + sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, signal); - sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); - return !sigismember(&old, signal); + if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) + return -errno; + + return 0; } void block_signals(void) @@ -196,7 +222,7 @@ void block_signals(void) * This might matter if gcc figures out how to inline this and * decides to shuffle this code into the caller. */ - mb(); + barrier(); } void unblock_signals(void) @@ -209,36 +235,26 @@ void unblock_signals(void) /* * We loop because the IRQ handler returns with interrupts off. So, * interrupts may have arrived and we need to re-enable them and - * recheck pending. + * recheck signals_pending. */ while(1) { /* * Save and reset save_pending after enabling signals. This - * way, pending won't be changed while we're reading it. + * way, signals_pending won't be changed while we're reading it. */ signals_enabled = 1; /* - * Setting signals_enabled and reading pending must + * Setting signals_enabled and reading signals_pending must * happen in this order. */ - mb(); - - save_pending = pending; - if (save_pending == 0) { - /* - * This must return with signals enabled, so - * this barrier ensures that writes are - * flushed out before the return. This might - * matter if gcc figures out how to inline - * this (unlikely, given its size) and decides - * to shuffle this code into the caller. - */ - mb(); + barrier(); + + save_pending = signals_pending; + if (save_pending == 0) return; - } - pending = 0; + signals_pending = 0; /* * We have pending interrupts, so disable signals, as the @@ -254,7 +270,7 @@ void unblock_signals(void) * back here. */ if (save_pending & SIGIO_MASK) - sig_handler_common_skas(SIGIO, NULL); + sig_handler_common(SIGIO, NULL); if (save_pending & SIGVTALRM_MASK) real_alarm_handler(NULL); diff --git a/arch/um/os-Linux/skas/Makefile b/arch/um/os-Linux/skas/Makefile index 5fd8d4dad66..d2ea3409e07 100644 --- a/arch/um/os-Linux/skas/Makefile +++ b/arch/um/os-Linux/skas/Makefile @@ -1,10 +1,10 @@ # -# Copyright (C) 2002 - 2004 Jeff Dike (jdike@addtoit.com) +# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) # Licensed under the GPL # -obj-y := mem.o process.o trap.o +obj-y := mem.o process.o -USER_OBJS := mem.o process.o trap.o +USER_OBJS := $(obj-y) include arch/um/scripts/Makefile.rules diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index e8b7a97e83d..d36c89c24a4 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -15,6 +15,7 @@ #include "as-layout.h" #include "chan_user.h" #include "kern_constants.h" +#include "kern_util.h" #include "mem.h" #include "os.h" #include "process.h" @@ -37,27 +38,27 @@ int is_skas_winch(int pid, int fd, void *data) static int ptrace_dump_regs(int pid) { - unsigned long regs[MAX_REG_NR]; - int i; + unsigned long regs[MAX_REG_NR]; + int i; - if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) - return -errno; + if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + return -errno; printk(UM_KERN_ERR "Stub registers -\n"); for (i = 0; i < ARRAY_SIZE(regs); i++) printk(UM_KERN_ERR "\t%d - %lx\n", i, regs[i]); - return 0; + return 0; } /* * Signals that are OK to receive in the stub - we'll just continue it. * SIGWINCH will happen when UML is inside a detached screen. */ -#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH)) +#define STUB_SIG_MASK (1 << SIGVTALRM) /* Signals that the stub will finish with - anything else is an error */ -#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP)) +#define STUB_DONE_MASK (1 << SIGTRAP) void wait_stub_done(int pid) { @@ -72,9 +73,11 @@ void wait_stub_done(int pid) break; err = ptrace(PTRACE_CONT, pid, 0, 0); - if (err) - panic("wait_stub_done : continue failed, errno = %d\n", - errno); + if (err) { + printk(UM_KERN_ERR "wait_stub_done : continue failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } } if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) @@ -85,8 +88,10 @@ bad_wait: if (err) printk(UM_KERN_ERR "Failed to get registers from stub, " "errno = %d\n", -err); - panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, " - "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status); + printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, " + "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno, + status); + fatal_sigsegv(); } extern unsigned long current_stub_stack(void); @@ -97,9 +102,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) if (ptrace_faultinfo) { err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); - if (err) - panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " - "errno = %d\n", errno); + if (err) { + printk(UM_KERN_ERR "get_skas_faultinfo - " + "PTRACE_FAULTINFO failed, errno = %d\n", errno); + fatal_sigsegv(); + } /* Special handling for i386, which has different structs */ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) @@ -109,9 +116,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi) } else { err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); - if (err) - panic("Failed to continue stub, pid = %d, errno = %d\n", - pid, errno); + if (err) { + printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " + "errno = %d\n", pid, errno); + fatal_sigsegv(); + } wait_stub_done(pid); /* @@ -137,6 +146,9 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, { int err, status; + if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) + fatal_sigsegv(); + /* Mark this as a syscall */ UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp); @@ -144,25 +156,31 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, { err = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); - if (err < 0) - panic("handle_trap - nullifying syscall failed, " - "errno = %d\n", errno); + if (err < 0) { + printk(UM_KERN_ERR "handle_trap - nullifying syscall " + "failed, errno = %d\n", errno); + fatal_sigsegv(); + } err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if (err < 0) - panic("handle_trap - continuing to end of syscall " - "failed, errno = %d\n", errno); + if (err < 0) { + printk(UM_KERN_ERR "handle_trap - continuing to end of " + "syscall failed, errno = %d\n", errno); + fatal_sigsegv(); + } CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); if ((err < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGTRAP + 0x80)) { - err = ptrace_dump_regs(pid); - if (err) - printk(UM_KERN_ERR "Failed to get registers " + (WSTOPSIG(status) != SIGTRAP + 0x80)) { + err = ptrace_dump_regs(pid); + if (err) + printk(UM_KERN_ERR "Failed to get registers " "from process, errno = %d\n", -err); - panic("handle_trap - failed to wait at end of syscall, " - "errno = %d, status = %d\n", errno, status); - } + printk(UM_KERN_ERR "handle_trap - failed to wait at " + "end of syscall, errno = %d, status = %d\n", + errno, status); + fatal_sigsegv(); + } } handle_syscall(regs); @@ -178,10 +196,13 @@ static int userspace_tramp(void *stack) ptrace(PTRACE_TRACEME, 0, 0, 0); signal(SIGTERM, SIG_DFL); + signal(SIGWINCH, SIG_IGN); err = set_interval(); - if (err) - panic("userspace_tramp - setting timer failed, errno = %d\n", - err); + if (err) { + printk(UM_KERN_ERR "userspace_tramp - setting timer failed, " + "errno = %d\n", err); + exit(1); + } if (!proc_mm) { /* @@ -221,16 +242,14 @@ static int userspace_tramp(void *stack) set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGIO); - sigaddset(&sa.sa_mask, SIGWINCH); - sigaddset(&sa.sa_mask, SIGVTALRM); - sigaddset(&sa.sa_mask, SIGUSR1); - sa.sa_flags = SA_ONSTACK; + sa.sa_flags = SA_ONSTACK | SA_NODEFER; sa.sa_handler = (void *) v; sa.sa_restorer = NULL; - if (sigaction(SIGSEGV, &sa, NULL) < 0) - panic("userspace_tramp - setting SIGSEGV handler " - "failed - errno = %d\n", errno); + if (sigaction(SIGSEGV, &sa, NULL) < 0) { + printk(UM_KERN_ERR "userspace_tramp - setting SIGSEGV " + "handler failed - errno = %d\n", errno); + exit(1); + } } kill(os_getpid(), SIGSTOP); @@ -246,13 +265,18 @@ int start_userspace(unsigned long stub_stack) { void *stack; unsigned long sp; - int pid, status, n, flags; + int pid, status, n, flags, err; stack = mmap(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (stack == MAP_FAILED) - panic("start_userspace : mmap failed, errno = %d", errno); + if (stack == MAP_FAILED) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : mmap failed, " + "errno = %d\n", errno); + return err; + } + sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); flags = CLONE_FILES; @@ -262,29 +286,50 @@ int start_userspace(unsigned long stub_stack) flags |= SIGCHLD; pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); - if (pid < 0) - panic("start_userspace : clone failed, errno = %d", errno); + if (pid < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : clone failed, " + "errno = %d\n", errno); + return err; + } do { CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); - if (n < 0) - panic("start_userspace : wait failed, errno = %d", - errno); + if (n < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : wait failed, " + "errno = %d\n", errno); + goto out_kill; + } } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); - if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) - panic("start_userspace : expected SIGSTOP, got status = %d", - status); + if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { + err = -EINVAL; + printk(UM_KERN_ERR "start_userspace : expected SIGSTOP, got " + "status = %d\n", status); + goto out_kill; + } if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, - (void *) PTRACE_O_TRACESYSGOOD) < 0) - panic("start_userspace : PTRACE_OLDSETOPTIONS failed, " - "errno = %d\n", errno); + (void *) PTRACE_O_TRACESYSGOOD) < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : PTRACE_OLDSETOPTIONS " + "failed, errno = %d\n", errno); + goto out_kill; + } - if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) - panic("start_userspace : munmap failed, errno = %d\n", errno); + if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) { + err = -errno; + printk(UM_KERN_ERR "start_userspace : munmap failed, " + "errno = %d\n", errno); + goto out_kill; + } return pid; + + out_kill: + os_kill_ptraced_process(pid, 1); + return err; } void userspace(struct uml_pt_regs *regs) @@ -302,7 +347,16 @@ void userspace(struct uml_pt_regs *regs) nsecs += os_nsecs(); while (1) { - restore_registers(pid, regs); + /* + * This can legitimately fail if the process loads a + * bogus value into a segment register. It will + * segfault and PTRACE_GETREGS will read that value + * out of the process. However, PTRACE_SETREGS will + * fail. In this case, there is nothing to do but + * just kill the process. + */ + if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) + fatal_sigsegv(); /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); @@ -310,19 +364,26 @@ void userspace(struct uml_pt_regs *regs) op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); - err = ptrace(op, pid, 0, 0); - if (err) - panic("userspace - could not resume userspace process, " - "pid=%d, ptrace operation = %d, errno = %d\n", - pid, op, errno); + if (ptrace(op, pid, 0, 0)) { + printk(UM_KERN_ERR "userspace - ptrace continue " + "failed, op = %d, errno = %d\n", op, errno); + fatal_sigsegv(); + } CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); - if (err < 0) - panic("userspace - waitpid failed, errno = %d\n", - errno); + if (err < 0) { + printk(UM_KERN_ERR "userspace - wait failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } regs->is_user = 1; - save_registers(pid, regs); + if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) { + printk(UM_KERN_ERR "userspace - PTRACE_GETREGS failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if (WIFSTOPPED(status)) { @@ -345,7 +406,7 @@ void userspace(struct uml_pt_regs *regs) break; case SIGVTALRM: now = os_nsecs(); - if(now < nsecs) + if (now < nsecs) break; block_signals(); (*sig_info[sig])(sig, regs); @@ -368,6 +429,7 @@ void userspace(struct uml_pt_regs *regs) default: printk(UM_KERN_ERR "userspace - child stopped " "with signal %d\n", sig); + fatal_sigsegv(); } pid = userspace_pid[0]; interrupt_end(); @@ -419,9 +481,12 @@ int copy_context_skas0(unsigned long new_stack, int pid) .it_interval = tv }) }); err = ptrace_setregs(pid, thread_regs); - if (err < 0) - panic("copy_context_skas0 : PTRACE_SETREGS failed, " - "pid = %d, errno = %d\n", pid, -err); + if (err < 0) { + err = -errno; + printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_SETREGS " + "failed, pid = %d, errno = %d\n", pid, -err); + return err; + } /* set a well known return code for detection of child write failure */ child_data->err = 12345678; @@ -431,31 +496,47 @@ int copy_context_skas0(unsigned long new_stack, int pid) * parent's stack, and check, if bad result. */ err = ptrace(PTRACE_CONT, pid, 0, 0); - if (err) - panic("Failed to continue new process, pid = %d, " - "errno = %d\n", pid, errno); + if (err) { + err = -errno; + printk(UM_KERN_ERR "Failed to continue new process, pid = %d, " + "errno = %d\n", pid, errno); + return err; + } + wait_stub_done(pid); pid = data->err; - if (pid < 0) - panic("copy_context_skas0 - stub-parent reports error %d\n", - -pid); + if (pid < 0) { + printk(UM_KERN_ERR "copy_context_skas0 - stub-parent reports " + "error %d\n", -pid); + return pid; + } /* * Wait, until child has finished too: read child's result from * child's stack and check it. */ wait_stub_done(pid); - if (child_data->err != STUB_DATA) - panic("copy_context_skas0 - stub-child reports error %ld\n", - child_data->err); + if (child_data->err != STUB_DATA) { + printk(UM_KERN_ERR "copy_context_skas0 - stub-child reports " + "error %ld\n", child_data->err); + err = child_data->err; + goto out_kill; + } if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, - (void *)PTRACE_O_TRACESYSGOOD) < 0) - panic("copy_context_skas0 : PTRACE_OLDSETOPTIONS failed, " - "errno = %d\n", errno); + (void *)PTRACE_O_TRACESYSGOOD) < 0) { + err = -errno; + printk(UM_KERN_ERR "copy_context_skas0 : PTRACE_OLDSETOPTIONS " + "failed, errno = %d\n", errno); + goto out_kill; + } return pid; + + out_kill: + os_kill_ptraced_process(pid, 1); + return err; } /* @@ -463,8 +544,8 @@ int copy_context_skas0(unsigned long new_stack, int pid) * available. Opening /proc/mm creates a new mm_context, which lacks * the stub-pages. Thus, we map them using /proc/mm-fd */ -void map_stub_pages(int fd, unsigned long code, - unsigned long data, unsigned long stack) +int map_stub_pages(int fd, unsigned long code, unsigned long data, + unsigned long stack) { struct proc_mm_op mmop; int n; @@ -488,8 +569,9 @@ void map_stub_pages(int fd, unsigned long code, printk(UM_KERN_ERR "mmap args - addr = 0x%lx, fd = %d, " "offset = %llx\n", code, code_fd, (unsigned long long) code_offset); - panic("map_stub_pages : /proc/mm map for code failed, " - "err = %d\n", n); + printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for code " + "failed, err = %d\n", n); + return -n; } if (stack) { @@ -507,10 +589,15 @@ void map_stub_pages(int fd, unsigned long code, .offset = map_offset } } }); CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop))); - if (n != sizeof(mmop)) - panic("map_stub_pages : /proc/mm map for data failed, " - "err = %d\n", errno); + if (n != sizeof(mmop)) { + n = errno; + printk(UM_KERN_ERR "map_stub_pages : /proc/mm map for " + "data failed, err = %d\n", n); + return -n; + } } + + return 0; } void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) @@ -571,7 +658,9 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) kmalloc_ok = 0; return 1; default: - panic("Bad sigsetjmp return in start_idle_thread - %d\n", n); + printk(UM_KERN_ERR "Bad sigsetjmp return in " + "start_idle_thread - %d\n", n); + fatal_sigsegv(); } longjmp(*switch_buf, 1); } @@ -614,9 +703,11 @@ void __switch_mm(struct mm_id *mm_idp) if (proc_mm) { err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_idp->u.mm_fd); - if (err) - panic("__switch_mm - PTRACE_SWITCH_MM failed, " - "errno = %d\n", errno); + if (err) { + printk(UM_KERN_ERR "__switch_mm - PTRACE_SWITCH_MM " + "failed, errno = %d\n", errno); + fatal_sigsegv(); + } } else userspace_pid[0] = mm_idp->u.pid; } diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c deleted file mode 100644 index 3b1b9244f46..00000000000 --- a/arch/um/os-Linux/skas/trap.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#if 0 -#include "kern_util.h" -#include "skas.h" -#include "ptrace_user.h" -#include "sysdep/ptrace_user.h" -#endif - -#include <errno.h> -#include <signal.h> -#include "sysdep/ptrace.h" -#include "kern_constants.h" -#include "as-layout.h" -#include "os.h" -#include "sigcontext.h" -#include "task.h" - -static struct uml_pt_regs ksig_regs[UM_NR_CPUS]; - -void sig_handler_common_skas(int sig, void *sc_ptr) -{ - struct sigcontext *sc = sc_ptr; - struct uml_pt_regs *r; - void (*handler)(int, struct uml_pt_regs *); - int save_user, save_errno = errno; - - /* - * This is done because to allow SIGSEGV to be delivered inside a SEGV - * handler. This can happen in copy_user, and if SEGV is disabled, - * the process will die. - * XXX Figure out why this is better than SA_NODEFER - */ - if (sig == SIGSEGV) { - change_sig(SIGSEGV, 1); - /* - * For segfaults, we want the data from the - * sigcontext. In this case, we don't want to mangle - * the process registers, so use a static set of - * registers. For other signals, the process - * registers are OK. - */ - r = &ksig_regs[cpu()]; - copy_sc(r, sc_ptr); - } - else r = TASK_REGS(get_current()); - - save_user = r->is_user; - r->is_user = 0; - if ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) || - (sig == SIGILL) || (sig == SIGTRAP)) - GET_FAULTINFO_FROM_SC(r->faultinfo, sc); - - change_sig(SIGUSR1, 1); - - handler = sig_info[sig]; - - /* unblock SIGVTALRM, SIGIO if sig isn't IRQ signal */ - if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM)) - unblock_signals(); - - handler(sig, r); - - errno = save_errno; - r->is_user = save_user; -} diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 7b81f6c08a5..b616e15638f 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -60,10 +60,11 @@ static int ptrace_child(void) * the UML code itself. */ ret = 2; - _exit(ret); + + exit(ret); } -static void fatal_perror(char *str) +static void fatal_perror(const char *str) { perror(str); exit(1); @@ -341,6 +342,8 @@ static void __init check_coredump_limit(void) void __init os_early_checks(void) { + int pid; + /* Print out the core dump limits early */ check_coredump_limit(); @@ -350,6 +353,11 @@ void __init os_early_checks(void) * kernel is running. */ check_tmpexec(); + + pid = start_ptraced_child(); + if (init_registers(pid)) + fatal("Failed to initialize default registers"); + stop_ptraced_child(pid, 1, 1); } static int __init noprocmm_cmd_param(char *str, int* add) @@ -411,7 +419,6 @@ static inline void check_skas3_ptrace_faultinfo(void) non_fatal("found\n"); } - init_registers(pid); stop_ptraced_child(pid, 1, 1); } @@ -466,7 +473,7 @@ static inline void check_skas3_proc_mm(void) else non_fatal("found\n"); } -int can_do_skas(void) +void can_do_skas(void) { non_fatal("Checking for the skas3 patch in the host:\n"); @@ -476,8 +483,6 @@ int can_do_skas(void) if (!proc_mm || !ptrace_faultinfo || !ptrace_ldt) skas_needs_stub = 1; - - return 1; } int __init parse_iomem(char *str, int *add) diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c deleted file mode 100644 index 2a1c9843e32..00000000000 --- a/arch/um/os-Linux/trap.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) - * Licensed under the GPL - */ - -#include <signal.h> -#include "os.h" -#include "sysdep/ptrace.h" - -/* Initialized from linux_main() */ -void (*sig_info[NSIG])(int, struct uml_pt_regs *); - -void os_fill_handlinfo(struct kern_handlers h) -{ - sig_info[SIGTRAP] = h.relay_signal; - sig_info[SIGFPE] = h.relay_signal; - sig_info[SIGILL] = h.relay_signal; - sig_info[SIGWINCH] = h.winch; - sig_info[SIGBUS] = h.bus_handler; - sig_info[SIGSEGV] = h.page_fault; - sig_info[SIGIO] = h.sigio_handler; - sig_info[SIGVTALRM] = h.timer_handler; -} diff --git a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c index 4cfdd18ea1e..b09ff66a77e 100644 --- a/arch/um/os-Linux/tty.c +++ b/arch/um/os-Linux/tty.c @@ -1,13 +1,16 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) +/* + * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ #include <stdlib.h> +#include <unistd.h> #include <errno.h> +#include <fcntl.h> +#include "kern_constants.h" +#include "kern_util.h" #include "os.h" #include "user.h" -#include "kern_util.h" struct grantpt_info { int fd; @@ -26,36 +29,34 @@ static void grantpt_cb(void *arg) int get_pty(void) { struct grantpt_info info; - int fd; - - fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); - if(fd < 0){ - printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); - return(fd); + int fd, err; + + fd = open("/dev/ptmx", O_RDWR); + if (fd < 0) { + err = -errno; + printk(UM_KERN_ERR "get_pty : Couldn't open /dev/ptmx - " + "err = %d\n", errno); + return err; } info.fd = fd; initial_thread_cb(grantpt_cb, &info); - if(info.res < 0){ - printk("get_pty : Couldn't grant pty - errno = %d\n", - -info.err); - return(-1); + if (info.res < 0) { + err = -info.err; + printk(UM_KERN_ERR "get_pty : Couldn't grant pty - " + "errno = %d\n", -info.err); + goto out; } - if(unlockpt(fd) < 0){ - printk("get_pty : Couldn't unlock pty - errno = %d\n", errno); - return(-1); + + if (unlockpt(fd) < 0) { + err = -errno; + printk(UM_KERN_ERR "get_pty : Couldn't unlock pty - " + "errno = %d\n", errno); + goto out; } - return(fd); + return fd; +out: + close(fd); + return err; } - -/* - * 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/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c index d11a55baa6b..cc648e6fd3a 100644 --- a/arch/um/os-Linux/tty_log.c +++ b/arch/um/os-Linux/tty_log.c @@ -12,7 +12,6 @@ #include <sys/time.h> #include "init.h" #include "user.h" -#include "kern_util.h" #include "os.h" #define TTY_LOG_DIR "./" diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 3e058ce9ffb..a6f31d47699 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -88,21 +88,6 @@ void setup_hostinfo(char *buf, int len) host.release, host.version, host.machine); } -int setjmp_wrapper(void (*proc)(void *, void *), ...) -{ - va_list args; - jmp_buf buf; - int n; - - n = UML_SETJMP(&buf); - if(n == 0){ - va_start(args, proc); - (*proc)(&buf, &args); - } - va_end(args); - return n; -} - void os_dump_core(void) { int pid; diff --git a/arch/um/sys-i386/bug.c b/arch/um/sys-i386/bug.c index a4360b5207d..8d4f273f121 100644 --- a/arch/um/sys-i386/bug.c +++ b/arch/um/sys-i386/bug.c @@ -4,6 +4,7 @@ */ #include <linux/uaccess.h> +#include <asm/errno.h> /* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because * that's not relevant in skas mode. diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index 806895d73bc..a74442d1376 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -3,171 +3,47 @@ * Licensed under the GPL */ -#include <errno.h> #include <signal.h> -#include <string.h> #include "kern_constants.h" -#include "os.h" +#include "kern_util.h" +#include "longjmp.h" #include "task.h" #include "user.h" - -#define MAXTOKEN 64 +#include "sysdep/ptrace.h" /* Set during early boot */ int host_has_cmov = 1; -int host_has_xmm = 0; +static jmp_buf cmov_test_return; -static char token(int fd, char *buf, int len, char stop) +static void cmov_sigill_test_handler(int sig) { - int n; - char *ptr, *end, c; - - ptr = buf; - end = &buf[len]; - do { - n = os_read_file(fd, ptr, sizeof(*ptr)); - c = *ptr++; - if (n != sizeof(*ptr)) { - if (n == 0) - return 0; - printk(UM_KERN_ERR "Reading /proc/cpuinfo failed, " - "err = %d\n", -n); - if (n < 0) - return n; - else return -EIO; - } - } while ((c != '\n') && (c != stop) && (ptr < end)); - - if (ptr == end) { - printk(UM_KERN_ERR "Failed to find '%c' in /proc/cpuinfo\n", - stop); - return -1; - } - *(ptr - 1) = '\0'; - return c; -} - -static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) -{ - int n; - char c; - - scratch[len - 1] = '\0'; - while (1) { - c = token(fd, scratch, len - 1, ':'); - if (c <= 0) - return 0; - else if (c != ':') { - printk(UM_KERN_ERR "Failed to find ':' in " - "/proc/cpuinfo\n"); - return 0; - } - - if (!strncmp(scratch, key, strlen(key))) - return 1; - - do { - n = os_read_file(fd, &c, sizeof(c)); - if (n != sizeof(c)) { - printk(UM_KERN_ERR "Failed to find newline in " - "/proc/cpuinfo, err = %d\n", -n); - return 0; - } - } while (c != '\n'); - } - return 0; + host_has_cmov = 0; + longjmp(cmov_test_return, 1); } -static int check_cpu_flag(char *feature, int *have_it) -{ - char buf[MAXTOKEN], c; - int fd, len = ARRAY_SIZE(buf); - - printk(UM_KERN_INFO "Checking for host processor %s support...", - feature); - fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); - if (fd < 0) { - printk(UM_KERN_ERR "Couldn't open /proc/cpuinfo, err = %d\n", - -fd); - return 0; - } - - *have_it = 0; - if (!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf))) - goto out; - - c = token(fd, buf, len - 1, ' '); - if (c < 0) - goto out; - else if (c != ' ') { - printk(UM_KERN_ERR "Failed to find ' ' in /proc/cpuinfo\n"); - goto out; - } - - while (1) { - c = token(fd, buf, len - 1, ' '); - if (c < 0) - goto out; - else if (c == '\n') - break; - - if (!strcmp(buf, feature)) { - *have_it = 1; - goto out; - } - } - out: - if (*have_it == 0) - printk("No\n"); - else if (*have_it == 1) - printk("Yes\n"); - os_close_file(fd); - return 1; -} - -#if 0 /* - * This doesn't work in tt mode, plus it's causing compilation problems - * for some people. - */ -static void disable_lcall(void) +void arch_check_bugs(void) { - struct modify_ldt_ldt_s ldt; - int err; + struct sigaction old, new; - bzero(&ldt, sizeof(ldt)); - ldt.entry_number = 7; - ldt.base_addr = 0; - ldt.limit = 0; - err = modify_ldt(1, &ldt, sizeof(ldt)); - if (err) - printk(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n", - errno); -} -#endif + printk(UM_KERN_INFO "Checking for host processor cmov support..."); + new.sa_handler = cmov_sigill_test_handler; -void arch_init_thread(void) -{ -#if 0 - disable_lcall(); -#endif -} + /* Make sure that SIGILL is enabled after the handler longjmps back */ + new.sa_flags = SA_NODEFER; + sigemptyset(&new.sa_mask); + sigaction(SIGILL, &new, &old); -void arch_check_bugs(void) -{ - int have_it; + if (setjmp(cmov_test_return) == 0) { + unsigned long foo = 0; + __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo)); + printk(UM_KERN_CONT "Yes\n"); + } else + printk(UM_KERN_CONT "No\n"); - if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) { - printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU " - "capability checks\n"); - return; - } - if (check_cpu_flag("cmov", &have_it)) - host_has_cmov = have_it; - if (check_cpu_flag("xmm", &have_it)) - host_has_xmm = have_it; + sigaction(SIGILL, &old, &new); } -int arch_handle_signal(int sig, struct uml_pt_regs *regs) +void arch_examine_signal(int sig, struct uml_pt_regs *regs) { unsigned char tmp[2]; @@ -176,24 +52,25 @@ int arch_handle_signal(int sig, struct uml_pt_regs *regs) * SIGILL in init. */ if ((sig != SIGILL) || (TASK_PID(get_current()) != 1)) - return 0; + return; + + if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) { + printk(UM_KERN_ERR "SIGILL in init, could not read " + "instructions!\n"); + return; + } - if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) - panic("SIGILL in init, could not read instructions!\n"); if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) - return 0; + return; if (host_has_cmov == 0) - panic("SIGILL caused by cmov, which this processor doesn't " - "implement, boot a filesystem compiled for older " - "processors"); + printk(UM_KERN_ERR "SIGILL caused by cmov, which this " + "processor doesn't implement. Boot a filesystem " + "compiled for older processors"); else if (host_has_cmov == 1) - panic("SIGILL caused by cmov, which this processor claims to " - "implement"); - else if (host_has_cmov == -1) - panic("SIGILL caused by cmov, couldn't tell if this processor " - "implements it, boot a filesystem compiled for older " - "processors"); - else panic("Bad value for host_has_cmov (%d)", host_has_cmov); - return 0; + printk(UM_KERN_ERR "SIGILL caused by cmov, which this " + "processor claims to implement"); + else + printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)", + host_has_cmov); } diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 67c0958eb98..a34263e6b08 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -3,8 +3,9 @@ * Licensed under the GPL */ -#include "linux/mm.h" -#include "asm/unistd.h" +#include <linux/mm.h> +#include <linux/sched.h> +#include <asm/unistd.h> #include "os.h" #include "proc_mm.h" #include "skas.h" @@ -146,7 +147,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) if (ptrace_ldt) return read_ldt_from_host(ptr, bytecount); - down(&ldt->semaphore); + mutex_lock(&ldt->lock); if (ldt->entry_count <= LDT_DIRECT_ENTRIES) { size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; if (size > bytecount) @@ -170,7 +171,7 @@ static int read_ldt(void __user * ptr, unsigned long bytecount) ptr += size; } } - up(&ldt->semaphore); + mutex_unlock(&ldt->lock); if (bytecount == 0 || err == -EFAULT) goto out; @@ -228,7 +229,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) } if (!ptrace_ldt) - down(&ldt->semaphore); + mutex_lock(&ldt->lock); err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); if (err) @@ -288,7 +289,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func) err = 0; out_unlock: - up(&ldt->semaphore); + mutex_unlock(&ldt->lock); out: return err; } @@ -395,7 +396,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) if (!ptrace_ldt) - init_MUTEX(&new_mm->ldt.semaphore); + mutex_init(&new_mm->ldt.lock); if (!from_mm) { memset(&desc, 0, sizeof(desc)); @@ -455,7 +456,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) * i.e., we have to use the stub for modify_ldt, which * can't handle the big read buffer of up to 64kB. */ - down(&from_mm->ldt.semaphore); + mutex_lock(&from_mm->ldt.lock); if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES) memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries, sizeof(new_mm->ldt.u.entries)); @@ -474,7 +475,7 @@ long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm) } } new_mm->ldt.entry_count = from_mm->ldt.entry_count; - up(&from_mm->ldt.semaphore); + mutex_unlock(&from_mm->ldt.lock); } out: diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index bd3da8a61f6..6b4499906a6 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -8,11 +8,11 @@ #include "asm/uaccess.h" #include "skas.h" -extern int arch_switch_tls(struct task_struct *from, struct task_struct *to); +extern int arch_switch_tls(struct task_struct *to); -void arch_switch_to(struct task_struct *from, struct task_struct *to) +void arch_switch_to(struct task_struct *to) { - int err = arch_switch_tls(from, to); + int err = arch_switch_tls(to); if (!err) return; diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 5cf97bc229b..0b10c3e7402 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -19,17 +19,3 @@ int ptrace_setregs(long pid, unsigned long *regs) return -errno; return 0; } - -int ptrace_getfpregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} - -int ptrace_setfpregs(long pid, unsigned long *regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) - return -errno; - return 0; -} diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 19053d46cb6..fd0c25ad6af 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -168,12 +168,13 @@ static int copy_sc_from_user(struct pt_regs *regs, struct sigcontext __user *from) { struct sigcontext sc; - int err; + int err, pid; err = copy_from_user(&sc, from, sizeof(sc)); if (err) return err; + pid = userspace_pid[current_thread_info()->cpu]; copy_sc(®s->regs, &sc); if (have_fpx_regs) { struct user_fxsr_struct fpx; @@ -187,8 +188,7 @@ static int copy_sc_from_user(struct pt_regs *regs, if (err) return 1; - err = restore_fpx_registers(userspace_pid[current_thread->cpu], - (unsigned long *) &fpx); + err = restore_fpx_registers(pid, (unsigned long *) &fpx); if (err < 0) { printk(KERN_ERR "copy_sc_from_user - " "restore_fpx_registers failed, errno = %d\n", @@ -204,8 +204,7 @@ static int copy_sc_from_user(struct pt_regs *regs, if (err) return 1; - err = restore_fp_registers(userspace_pid[current_thread->cpu], - (unsigned long *) &fp); + err = restore_fp_registers(pid, (unsigned long *) &fp); if (err < 0) { printk(KERN_ERR "copy_sc_from_user - " "restore_fp_registers failed, errno = %d\n", @@ -223,7 +222,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, { struct sigcontext sc; struct faultinfo * fi = ¤t->thread.arch.faultinfo; - int err; + int err, pid; sc.gs = REGS_GS(regs->regs.gp); sc.fs = REGS_FS(regs->regs.gp); @@ -249,11 +248,11 @@ static int copy_sc_to_user(struct sigcontext __user *to, to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); sc.fpstate = to_fp; + pid = userspace_pid[current_thread_info()->cpu]; if (have_fpx_regs) { struct user_fxsr_struct fpx; - err = save_fpx_registers(userspace_pid[current_thread->cpu], - (unsigned long *) &fpx); + err = save_fpx_registers(pid, (unsigned long *) &fpx); if (err < 0){ printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " "failed, errno = %d\n", err); @@ -276,8 +275,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, else { struct user_i387_struct fp; - err = save_fp_registers(userspace_pid[current_thread->cpu], - (unsigned long *) &fp); + err = save_fp_registers(pid, (unsigned long *) &fp); if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct))) return 1; } diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S index e730772c401..7699e89f660 100644 --- a/arch/um/sys-i386/stub.S +++ b/arch/um/sys-i386/stub.S @@ -7,7 +7,7 @@ .globl batch_syscall_stub batch_syscall_stub: /* load pointer to first operation */ - mov $(ASM_STUB_DATA+8), %esp + mov $(STUB_DATA+8), %esp again: /* load length of additional data */ @@ -15,12 +15,12 @@ again: /* if(length == 0) : end of list */ /* write possible 0 to header */ - mov %eax, ASM_STUB_DATA+4 + mov %eax, STUB_DATA+4 cmpl $0, %eax jz done /* save current pointer */ - mov %esp, ASM_STUB_DATA+4 + mov %esp, STUB_DATA+4 /* skip additional data */ add %eax, %esp @@ -46,7 +46,7 @@ again: done: /* save return value */ - mov %eax, ASM_STUB_DATA + mov %eax, STUB_DATA /* stop */ int3 diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c index b3999cb76bf..28ccf737a79 100644 --- a/arch/um/sys-i386/stub_segv.c +++ b/arch/um/sys-i386/stub_segv.c @@ -1,32 +1,17 @@ /* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <signal.h> -#include <sys/select.h> /* The only way I can see to get sigset_t */ -#include <asm/unistd.h> -#include "as-layout.h" -#include "uml-config.h" #include "sysdep/stub.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); - int pid; GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), sc); - pid = stub_syscall0(__NR_getpid); - stub_syscall2(__NR_kill, pid, SIGUSR1); - - /* Load pointer to sigcontext into esp, since we need to leave - * the stack in its original form when we do the sigreturn here, by - * hand. - */ - __asm__ __volatile__("mov %0,%%esp ; movl %1, %%eax ; " - "int $0x80" : : "a" (sc), "g" (__NR_sigreturn)); + trap_myself(); } diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index 12d4148dba3..00e5f5203ee 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -9,4 +9,9 @@ #define old_mmap old_mmap_i386 +.section .rodata,"a" + #include "../../x86/kernel/syscall_table_32.S" + +ENTRY(syscall_table_size) +.long .-sys_call_table diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c index fcaff86b000..c6c7131e563 100644 --- a/arch/um/sys-i386/tls.c +++ b/arch/um/sys-i386/tls.c @@ -26,6 +26,11 @@ int do_set_thread_area(struct user_desc *info) cpu = get_cpu(); ret = os_set_thread_area(info, userspace_pid[cpu]); put_cpu(); + + if (ret) + printk(KERN_ERR "PTRACE_SET_THREAD_AREA failed, err = %d, " + "index = %d\n", ret, info->entry_number); + return ret; } @@ -37,6 +42,11 @@ int do_get_thread_area(struct user_desc *info) cpu = get_cpu(); ret = os_get_thread_area(info, userspace_pid[cpu]); put_cpu(); + + if (ret) + printk(KERN_ERR "PTRACE_GET_THREAD_AREA failed, err = %d, " + "index = %d\n", ret, info->entry_number); + return ret; } @@ -172,7 +182,7 @@ void clear_flushed_tls(struct task_struct *task) * SKAS patch. */ -int arch_switch_tls(struct task_struct *from, struct task_struct *to) +int arch_switch_tls(struct task_struct *to) { if (!host_supports_tls) return 0; @@ -225,7 +235,8 @@ out: } /* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ -static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) +static int get_tls_entry(struct task_struct *task, struct user_desc *info, + int idx) { struct thread_struct *t = &task->thread; @@ -263,7 +274,7 @@ clear: goto out; } -asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) +int sys_set_thread_area(struct user_desc __user *user_desc) { struct user_desc info; int idx, ret; @@ -298,7 +309,7 @@ asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) * i386. However the only possible error are caused by bugs. */ int ptrace_set_thread_area(struct task_struct *child, int idx, - struct user_desc __user *user_desc) + struct user_desc __user *user_desc) { struct user_desc info; @@ -311,7 +322,7 @@ int ptrace_set_thread_area(struct task_struct *child, int idx, return set_tls_entry(child, &info, idx, 0); } -asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) +int sys_get_thread_area(struct user_desc __user *user_desc) { struct user_desc info; int idx, ret; @@ -355,10 +366,9 @@ out: return ret; } - /* - * XXX: This part is probably common to i386 and x86-64. Don't create a common - * file for now, do that when implementing x86-64 support. + * This code is really i386-only, but it detects and logs x86_64 GDT indexes + * if a 32-bit UML is running on a 64-bit host. */ static int __init __setup_host_supports_tls(void) { @@ -367,13 +377,16 @@ static int __init __setup_host_supports_tls(void) printk(KERN_INFO "Host TLS support detected\n"); printk(KERN_INFO "Detected host type: "); switch (host_gdt_entry_tls_min) { - case GDT_ENTRY_TLS_MIN_I386: - printk("i386\n"); - break; - case GDT_ENTRY_TLS_MIN_X86_64: - printk("x86_64\n"); - break; + case GDT_ENTRY_TLS_MIN_I386: + printk(KERN_CONT "i386"); + break; + case GDT_ENTRY_TLS_MIN_X86_64: + printk(KERN_CONT "x86_64"); + break; } + printk(KERN_CONT " (GDT indexes %d to %d)\n", + host_gdt_entry_tls_min, + host_gdt_entry_tls_min + GDT_ENTRY_TLS_ENTRIES); } else printk(KERN_ERR " Host TLS support NOT detected! " "TLS support inside UML will not work\n"); diff --git a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile index a9814a7ae60..08901526e89 100644 --- a/arch/um/sys-ppc/Makefile +++ b/arch/um/sys-ppc/Makefile @@ -6,7 +6,7 @@ OBJ = built-in.o OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o -EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel +EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(srctree)/arch/ppc/kernel all: $(OBJ) @@ -22,25 +22,25 @@ sigcontext.o: sigcontext.c semaphore.c: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + ln -s $(srctree)/arch/ppc/kernel/$@ $@ checksum.S: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/lib/$@ $@ + ln -s $(srctree)/arch/ppc/lib/$@ $@ mk_defs.c: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + ln -s $(srctree)/arch/ppc/kernel/$@ $@ ppc_defs.head: rm -f $@ - ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ + ln -s $(srctree)/arch/ppc/kernel/$@ $@ ppc_defs.h: mk_defs.c ppc_defs.head \ - $(TOPDIR)/include/asm-ppc/mmu.h \ - $(TOPDIR)/include/asm-ppc/processor.h \ - $(TOPDIR)/include/asm-ppc/pgtable.h \ - $(TOPDIR)/include/asm-ppc/ptrace.h + $(srctree)/include/asm-ppc/mmu.h \ + $(srctree)/include/asm-ppc/processor.h \ + $(srctree)/include/asm-ppc/pgtable.h \ + $(srctree)/include/asm-ppc/ptrace.h # $(CC) $(CFLAGS) -S mk_defs.c cp ppc_defs.head ppc_defs.h # for bk, this way we can write to the file even if it's not checked out @@ -56,13 +56,13 @@ ppc_defs.h: mk_defs.c ppc_defs.head \ checksum.o: checksum.S rm -f asm - ln -s $(TOPDIR)/include/asm-ppc asm + ln -s $(srctree)/include/asm-ppc asm $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm misc.o: misc.S ppc_defs.h rm -f asm - ln -s $(TOPDIR)/include/asm-ppc asm + ln -s $(srctree)/include/asm-ppc asm $(CC) $(EXTRA_AFLAGS) $(KBUILD_AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o rm -f asm diff --git a/arch/um/sys-x86_64/bug.c b/arch/um/sys-x86_64/bug.c index a4360b5207d..e8034e363d8 100644 --- a/arch/um/sys-x86_64/bug.c +++ b/arch/um/sys-x86_64/bug.c @@ -5,7 +5,8 @@ #include <linux/uaccess.h> -/* Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because +/* + * Mostly copied from i386/x86_86 - eliminated the eip < PAGE_OFFSET because * that's not relevant in skas mode. */ diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c index 506b6765bbc..44e02ba2a26 100644 --- a/arch/um/sys-x86_64/bugs.c +++ b/arch/um/sys-x86_64/bugs.c @@ -6,15 +6,10 @@ #include "sysdep/ptrace.h" -void arch_init_thread(void) -{ -} - void arch_check_bugs(void) { } -int arch_handle_signal(int sig, struct uml_pt_regs *regs) +void arch_examine_signal(int sig, struct uml_pt_regs *regs) { - return 0; } diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index b7631b0e9dd..f3458d7d1c5 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c @@ -5,13 +5,12 @@ * Licensed under the GPL */ -#define __FRAME_OFFSETS -#include <asm/ptrace.h> +#include <linux/mm.h> #include <linux/sched.h> #include <linux/errno.h> -#include <linux/mm.h> +#define __FRAME_OFFSETS +#include <asm/ptrace.h> #include <asm/uaccess.h> -#include <asm/elf.h> /* * determines which flags the user has access to. @@ -24,12 +23,14 @@ int putreg(struct task_struct *child, int regno, unsigned long value) unsigned long tmp; #ifdef TIF_IA32 - /* Some code in the 64bit emulation may not be 64bit clean. - Don't take any chances. */ + /* + * Some code in the 64bit emulation may not be 64bit clean. + * Don't take any chances. + */ if (test_tsk_thread_flag(child, TIF_IA32)) value &= 0xffffffff; #endif - switch (regno){ + switch (regno) { case FS: case GS: case DS: @@ -66,7 +67,7 @@ int poke_user(struct task_struct *child, long addr, long data) if (addr < MAX_REG_OFFSET) return putreg(child, addr, data); else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ + (addr <= offsetof(struct user, u_debugreg[7]))) { addr -= offsetof(struct user, u_debugreg[0]); addr = addr >> 2; if ((addr == 4) || (addr == 5)) @@ -108,11 +109,10 @@ int peek_user(struct task_struct *child, long addr, long data) return -EIO; tmp = 0; /* Default return condition */ - if (addr < MAX_REG_OFFSET){ + if (addr < MAX_REG_OFFSET) tmp = getreg(child, addr); - } else if ((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ + (addr <= offsetof(struct user, u_debugreg[7]))) { addr -= offsetof(struct user, u_debugreg[0]); addr = addr >> 2; tmp = child->thread.arch.debugregs[addr]; @@ -127,8 +127,9 @@ int is_syscall(unsigned long addr) int n; n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if (n){ - /* access_process_vm() grants access to vsyscall and stub, + if (n) { + /* + * access_process_vm() grants access to vsyscall and stub, * while copy_from_user doesn't. Maybe access_process_vm is * slow, but that doesn't matter, since it will be called only * in case of singlestepping, if copy_from_user failed. @@ -155,7 +156,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) return err; n = copy_to_user(buf, fpregs, sizeof(fpregs)); - if(n > 0) + if (n > 0) return -EFAULT; return n; diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c index b5f9c33e311..c57a496d3f5 100644 --- a/arch/um/sys-x86_64/ptrace_user.c +++ b/arch/um/sys-x86_64/ptrace_user.c @@ -4,55 +4,19 @@ * Licensed under the GPL */ -#include <stddef.h> #include <errno.h> #include "ptrace_user.h" -#include "user.h" -#include "kern_constants.h" int ptrace_getregs(long pid, unsigned long *regs_out) { - if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) - return(-errno); - return(0); -} - -int ptrace_setregs(long pid, unsigned long *regs) -{ - if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) - return(-errno); + if (ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) + return -errno; return(0); } -int ptrace_setfpregs(long pid, unsigned long *regs) +int ptrace_setregs(long pid, unsigned long *regs_out) { - if (ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) + if (ptrace(PTRACE_SETREGS, pid, 0, regs_out) < 0) return -errno; - return 0; -} - -void ptrace_pokeuser(unsigned long addr, unsigned long data) -{ - panic("ptrace_pokeuser"); -} - -#define DS 184 -#define ES 192 -#define __USER_DS 0x2b - -void arch_enter_kernel(void *task, int pid) -{ -} - -void arch_leave_kernel(void *task, int pid) -{ -#ifdef UM_USER_CS - if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0) - printk("POKEUSR CS failed"); -#endif - - if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0) - printk("POKEUSR DS failed"); - if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0) - printk("POKEUSR ES failed"); + return(0); } diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index 14070181407..1a899a7ed7a 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c @@ -81,7 +81,7 @@ static int copy_sc_from_user(struct pt_regs *regs, if (err) return 1; - err = restore_fp_registers(userspace_pid[current_thread->cpu], + err = restore_fp_registers(userspace_pid[current_thread_info()->cpu], (unsigned long *) &fp); if (err < 0) { printk(KERN_ERR "copy_sc_from_user - " @@ -143,7 +143,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, if (err) return 1; - err = save_fp_registers(userspace_pid[current_thread->cpu], + err = save_fp_registers(userspace_pid[current_thread_info()->cpu], (unsigned long *) &fp); if (err < 0) { printk(KERN_ERR "copy_sc_from_user - restore_fp_registers " diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S index 4afe204a6af..56876876315 100644 --- a/arch/um/sys-x86_64/stub.S +++ b/arch/um/sys-x86_64/stub.S @@ -8,18 +8,18 @@ syscall_stub: /* We don't have 64-bit constants, so this constructs the address * we need. */ - movq $(ASM_STUB_DATA >> 32), %rbx + movq $(STUB_DATA >> 32), %rbx salq $32, %rbx - movq $(ASM_STUB_DATA & 0xffffffff), %rcx + movq $(STUB_DATA & 0xffffffff), %rcx or %rcx, %rbx movq %rax, (%rbx) int3 .globl batch_syscall_stub batch_syscall_stub: - mov $(ASM_STUB_DATA >> 32), %rbx + mov $(STUB_DATA >> 32), %rbx sal $32, %rbx - mov $(ASM_STUB_DATA & 0xffffffff), %rax + mov $(STUB_DATA & 0xffffffff), %rax or %rax, %rbx /* load pointer to first operation */ mov %rbx, %rsp diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c index 3afb590f007..ced051afc70 100644 --- a/arch/um/sys-x86_64/stub_segv.c +++ b/arch/um/sys-x86_64/stub_segv.c @@ -1,51 +1,22 @@ /* - * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stddef.h> #include <signal.h> -#include <asm/unistd.h> #include "as-layout.h" -#include "uml-config.h" -#include "sysdep/sigcontext.h" -#include "sysdep/faultinfo.h" #include "sysdep/stub.h" - -/* Copied from sys-x86_64/signal.c - Can't find an equivalent definition - * in the libc headers anywhere. - */ -struct rt_sigframe -{ - char *pretcode; - struct ucontext uc; - struct siginfo info; -}; - -/* Copied here from <linux/kernel.h> - we're userspace. */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) +#include "sysdep/faultinfo.h" +#include "sysdep/sigcontext.h" void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig) { struct ucontext *uc; - int pid; __asm__ __volatile__("movq %%rdx, %0" : "=g" (uc) :); GET_FAULTINFO_FROM_SC(*((struct faultinfo *) STUB_DATA), &uc->uc_mcontext); - - pid = stub_syscall0(__NR_getpid); - stub_syscall2(__NR_kill, pid, SIGUSR1); - - /* sys_sigreturn expects that the stack pointer will be 8 bytes into - * the signal frame. So, we use the ucontext pointer, which we know - * already, to get the signal frame pointer, and add 8 to that. - */ - __asm__ __volatile__("movq %0, %%rsp; movq %1, %%rax ; syscall": : - "g" ((unsigned long) - container_of(uc, struct rt_sigframe, uc) + 8), - "g" (__NR_rt_sigreturn)); + trap_myself(); } + diff --git a/arch/um/sys-x86_64/syscall_table.c b/arch/um/sys-x86_64/syscall_table.c index 71b2ae4ad5d..c128eb89700 100644 --- a/arch/um/sys-x86_64/syscall_table.c +++ b/arch/um/sys-x86_64/syscall_table.c @@ -1,5 +1,7 @@ -/* System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c - * with some changes for UML. */ +/* + * System call table for UML/x86-64, copied from arch/x86_64/kernel/syscall.c + * with some changes for UML. + */ #include <linux/linkage.h> #include <linux/sys.h> @@ -8,22 +10,26 @@ #define __NO_STUBS -/* Below you can see, in terms of #define's, the differences between the x86-64 - * and the UML syscall table. */ +/* + * Below you can see, in terms of #define's, the differences between the x86-64 + * and the UML syscall table. + */ /* Not going to be implemented by UML, since we have no hardware. */ #define stub_iopl sys_ni_syscall #define sys_ioperm sys_ni_syscall -/* The UML TLS problem. Note that x86_64 does not implement this, so the below - * is needed only for the ia32 compatibility. */ -/*#define sys_set_thread_area sys_ni_syscall -#define sys_get_thread_area sys_ni_syscall*/ +/* + * The UML TLS problem. Note that x86_64 does not implement this, so the below + * is needed only for the ia32 compatibility. + */ /* On UML we call it this way ("old" means it's not mmap2) */ #define sys_mmap old_mmap -/* On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. - * See arch/x86_64/kernel/sys_x86_64.c */ +/* + * On x86-64 sys_uname is actually sys_newuname plus a compatibility trick. + * See arch/x86_64/kernel/sys_x86_64.c + */ #define sys_uname sys_uname64 #define stub_clone sys_clone @@ -46,8 +52,19 @@ typedef void (*sys_call_ptr_t)(void); extern void sys_ni_syscall(void); -sys_call_ptr_t sys_call_table[UM_NR_syscall_max+1] __cacheline_aligned = { - /* Smells like a like a compiler bug -- it doesn't work when the & below is removed. */ - [0 ... UM_NR_syscall_max] = &sys_ni_syscall, +/* + * We used to have a trick here which made sure that holes in the + * x86_64 table were filled in with sys_ni_syscall, but a comment in + * unistd_64.h says that holes aren't allowed, so the trick was + * removed. + * The trick looked like this + * [0 ... UM_NR_syscall_max] = &sys_ni_syscall + * before including unistd_64.h - the later initializations overwrote + * the sys_ni_syscall filler. + */ + +sys_call_ptr_t sys_call_table[] __cacheline_aligned = { #include <asm-x86/unistd_64.h> }; + +int syscall_table_size = sizeof(sys_call_table); diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 86f6b18410e..f1199fd34d3 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -48,7 +48,9 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) switch (code) { case ARCH_SET_FS: case ARCH_SET_GS: - restore_registers(pid, ¤t->thread.regs.regs); + ret = restore_registers(pid, ¤t->thread.regs.regs); + if (ret) + return ret; break; case ARCH_GET_FS: case ARCH_GET_GS: @@ -70,10 +72,10 @@ long arch_prctl(struct task_struct *task, int code, unsigned long __user *addr) switch (code) { case ARCH_SET_FS: current->thread.arch.fs = (unsigned long) ptr; - save_registers(pid, ¤t->thread.regs.regs); + ret = save_registers(pid, ¤t->thread.regs.regs); break; case ARCH_SET_GS: - save_registers(pid, ¤t->thread.regs.regs); + ret = save_registers(pid, ¤t->thread.regs.regs); break; case ARCH_GET_FS: ret = put_user(tmp, addr); @@ -105,7 +107,7 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp, return ret; } -void arch_switch_to(struct task_struct *from, struct task_struct *to) +void arch_switch_to(struct task_struct *to) { if ((to->thread.arch.fs == 0) || (to->mm == NULL)) return; diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c index 76544403181..f4f82beb350 100644 --- a/arch/um/sys-x86_64/sysrq.c +++ b/arch/um/sys-x86_64/sysrq.c @@ -4,32 +4,33 @@ * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/utsname.h" -#include "linux/module.h" -#include "asm/current.h" -#include "asm/ptrace.h" +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/utsname.h> +#include <asm/current.h> +#include <asm/ptrace.h> #include "sysrq.h" -void __show_regs(struct pt_regs * regs) +void __show_regs(struct pt_regs *regs) { printk("\n"); print_modules(); - printk("Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current), + printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current), current->comm, print_tainted(), init_utsname()->release); - printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, + printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff, PT_REGS_RIP(regs)); - printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), + printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), PT_REGS_EFLAGS(regs)); - printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", + printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n", PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs)); - printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", + printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n", PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs)); - printk("RBP: %016lx R08: %016lx R09: %016lx\n", + printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n", PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs)); - printk("R10: %016lx R11: %016lx R12: %016lx\n", + printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n", PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs)); - printk("R13: %016lx R14: %016lx R15: %016lx\n", + printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n", PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs)); } diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c index 8b8eff1bd97..3dead392a41 100644 --- a/arch/um/sys-x86_64/um_module.c +++ b/arch/um/sys-x86_64/um_module.c @@ -1,7 +1,7 @@ #include <linux/vmalloc.h> #include <linux/moduleloader.h> -/*Copied from i386 arch/i386/kernel/module.c */ +/* Copied from i386 arch/i386/kernel/module.c */ void *module_alloc(unsigned long size) { if (size == 0) @@ -13,7 +13,9 @@ void *module_alloc(unsigned long size) void module_free(struct module *mod, void *module_region) { vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ + /* + * FIXME: If module_region == mod->init_region, trim exception + * table entries. + */ } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 59eef1c7fda..434821187cf 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -465,6 +465,9 @@ config CALGARY_IOMMU_ENABLED_BY_DEFAULT Calgary anyway, pass 'iommu=calgary' on the kernel command line. If unsure, say Y. +config IOMMU_HELPER + def_bool (CALGARY_IOMMU || GART_IOMMU) + # need this always selected by IOMMU for the VIA workaround config SWIOTLB bool diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S index 0db0a6291bb..8022d3c695c 100644 --- a/arch/x86/ia32/ia32entry.S +++ b/arch/x86/ia32/ia32entry.S @@ -722,7 +722,9 @@ ia32_sys_call_table: .quad sys_epoll_pwait .quad compat_sys_utimensat /* 320 */ .quad compat_sys_signalfd - .quad compat_sys_timerfd + .quad sys_timerfd_create .quad sys_eventfd .quad sys32_fallocate + .quad compat_sys_timerfd_settime /* 325 */ + .quad compat_sys_timerfd_gettime ia32_syscall_end: diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c index 1fe7f043ebd..1b5464c2434 100644 --- a/arch/x86/kernel/pci-calgary_64.c +++ b/arch/x86/kernel/pci-calgary_64.c @@ -35,6 +35,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/scatterlist.h> +#include <linux/iommu-helper.h> #include <asm/gart.h> #include <asm/calgary.h> #include <asm/tce.h> @@ -260,22 +261,28 @@ static void iommu_range_reserve(struct iommu_table *tbl, spin_unlock_irqrestore(&tbl->it_lock, flags); } -static unsigned long iommu_range_alloc(struct iommu_table *tbl, - unsigned int npages) +static unsigned long iommu_range_alloc(struct device *dev, + struct iommu_table *tbl, + unsigned int npages) { unsigned long flags; unsigned long offset; + unsigned long boundary_size; + + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + PAGE_SIZE) >> PAGE_SHIFT; BUG_ON(npages == 0); spin_lock_irqsave(&tbl->it_lock, flags); - offset = find_next_zero_string(tbl->it_map, tbl->it_hint, - tbl->it_size, npages); + offset = iommu_area_alloc(tbl->it_map, tbl->it_size, tbl->it_hint, + npages, 0, boundary_size, 0); if (offset == ~0UL) { tbl->chip_ops->tce_cache_blast(tbl); - offset = find_next_zero_string(tbl->it_map, 0, - tbl->it_size, npages); + + offset = iommu_area_alloc(tbl->it_map, tbl->it_size, 0, + npages, 0, boundary_size, 0); if (offset == ~0UL) { printk(KERN_WARNING "Calgary: IOMMU full.\n"); spin_unlock_irqrestore(&tbl->it_lock, flags); @@ -286,7 +293,6 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, } } - set_bit_string(tbl->it_map, offset, npages); tbl->it_hint = offset + npages; BUG_ON(tbl->it_hint > tbl->it_size); @@ -295,13 +301,13 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl, return offset; } -static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr, - unsigned int npages, int direction) +static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl, + void *vaddr, unsigned int npages, int direction) { unsigned long entry; dma_addr_t ret = bad_dma_address; - entry = iommu_range_alloc(tbl, npages); + entry = iommu_range_alloc(dev, tbl, npages); if (unlikely(entry == bad_dma_address)) goto error; @@ -354,7 +360,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, badbit, tbl, dma_addr, entry, npages); } - __clear_bit_string(tbl->it_map, entry, npages); + iommu_area_free(tbl->it_map, entry, npages); spin_unlock_irqrestore(&tbl->it_lock, flags); } @@ -438,7 +444,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg, vaddr = (unsigned long) sg_virt(s); npages = num_dma_pages(vaddr, s->length); - entry = iommu_range_alloc(tbl, npages); + entry = iommu_range_alloc(dev, tbl, npages); if (entry == bad_dma_address) { /* makes sure unmap knows to stop */ s->dma_length = 0; @@ -476,7 +482,7 @@ static dma_addr_t calgary_map_single(struct device *dev, void *vaddr, npages = num_dma_pages(uaddr, size); if (translation_enabled(tbl)) - dma_handle = iommu_alloc(tbl, vaddr, npages, direction); + dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction); else dma_handle = virt_to_bus(vaddr); @@ -516,7 +522,7 @@ static void* calgary_alloc_coherent(struct device *dev, size_t size, if (translation_enabled(tbl)) { /* set up tces to cover the allocated range */ - mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL); + mapping = iommu_alloc(dev, tbl, ret, npages, DMA_BIDIRECTIONAL); if (mapping == bad_dma_address) goto free; diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 845cbecd68e..65f6acb025c 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -25,6 +25,7 @@ #include <linux/bitops.h> #include <linux/kdebug.h> #include <linux/scatterlist.h> +#include <linux/iommu-helper.h> #include <asm/atomic.h> #include <asm/io.h> #include <asm/mtrr.h> @@ -82,17 +83,24 @@ AGPEXTERN __u32 *agp_gatt_table; static unsigned long next_bit; /* protected by iommu_bitmap_lock */ static int need_flush; /* global flush state. set for each gart wrap */ -static unsigned long alloc_iommu(int size) +static unsigned long alloc_iommu(struct device *dev, int size) { unsigned long offset, flags; + unsigned long boundary_size; + unsigned long base_index; + + base_index = ALIGN(iommu_bus_base & dma_get_seg_boundary(dev), + PAGE_SIZE) >> PAGE_SHIFT; + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + PAGE_SIZE) >> PAGE_SHIFT; spin_lock_irqsave(&iommu_bitmap_lock, flags); - offset = find_next_zero_string(iommu_gart_bitmap, next_bit, - iommu_pages, size); + offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, next_bit, + size, base_index, boundary_size, 0); if (offset == -1) { need_flush = 1; - offset = find_next_zero_string(iommu_gart_bitmap, 0, - iommu_pages, size); + offset = iommu_area_alloc(iommu_gart_bitmap, iommu_pages, 0, + size, base_index, boundary_size, 0); } if (offset != -1) { set_bit_string(iommu_gart_bitmap, offset, size); @@ -114,7 +122,7 @@ static void free_iommu(unsigned long offset, int size) unsigned long flags; spin_lock_irqsave(&iommu_bitmap_lock, flags); - __clear_bit_string(iommu_gart_bitmap, offset, size); + iommu_area_free(iommu_gart_bitmap, offset, size); spin_unlock_irqrestore(&iommu_bitmap_lock, flags); } @@ -235,7 +243,7 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem, size_t size, int dir) { unsigned long npages = to_pages(phys_mem, size); - unsigned long iommu_page = alloc_iommu(npages); + unsigned long iommu_page = alloc_iommu(dev, npages); int i; if (iommu_page == -1) { @@ -355,10 +363,11 @@ static int dma_map_sg_nonforce(struct device *dev, struct scatterlist *sg, } /* Map multiple scatterlist entries continuous into the first. */ -static int __dma_map_cont(struct scatterlist *start, int nelems, - struct scatterlist *sout, unsigned long pages) +static int __dma_map_cont(struct device *dev, struct scatterlist *start, + int nelems, struct scatterlist *sout, + unsigned long pages) { - unsigned long iommu_start = alloc_iommu(pages); + unsigned long iommu_start = alloc_iommu(dev, pages); unsigned long iommu_page = iommu_start; struct scatterlist *s; int i; @@ -394,8 +403,8 @@ static int __dma_map_cont(struct scatterlist *start, int nelems, } static inline int -dma_map_cont(struct scatterlist *start, int nelems, struct scatterlist *sout, - unsigned long pages, int need) +dma_map_cont(struct device *dev, struct scatterlist *start, int nelems, + struct scatterlist *sout, unsigned long pages, int need) { if (!need) { BUG_ON(nelems != 1); @@ -403,7 +412,7 @@ dma_map_cont(struct scatterlist *start, int nelems, struct scatterlist *sout, sout->dma_length = start->length; return 0; } - return __dma_map_cont(start, nelems, sout, pages); + return __dma_map_cont(dev, start, nelems, sout, pages); } /* @@ -416,6 +425,8 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) struct scatterlist *s, *ps, *start_sg, *sgmap; int need = 0, nextneed, i, out, start; unsigned long pages = 0; + unsigned int seg_size; + unsigned int max_seg_size; if (nents == 0) return 0; @@ -426,6 +437,8 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) out = 0; start = 0; start_sg = sgmap = sg; + seg_size = 0; + max_seg_size = dma_get_max_seg_size(dev); ps = NULL; /* shut up gcc */ for_each_sg(sg, s, nents, i) { dma_addr_t addr = sg_phys(s); @@ -443,11 +456,13 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) * offset. */ if (!iommu_merge || !nextneed || !need || s->offset || + (s->length + seg_size > max_seg_size) || (ps->offset + ps->length) % PAGE_SIZE) { - if (dma_map_cont(start_sg, i - start, sgmap, - pages, need) < 0) + if (dma_map_cont(dev, start_sg, i - start, + sgmap, pages, need) < 0) goto error; out++; + seg_size = 0; sgmap = sg_next(sgmap); pages = 0; start = i; @@ -455,11 +470,12 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir) } } + seg_size += s->length; need = nextneed; pages += to_pages(s->offset, s->length); ps = s; } - if (dma_map_cont(start_sg, i - start, sgmap, pages, need) < 0) + if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0) goto error; out++; flush_gart(); diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S index 8344c70adf6..adff5562f5f 100644 --- a/arch/x86/kernel/syscall_table_32.S +++ b/arch/x86/kernel/syscall_table_32.S @@ -321,6 +321,8 @@ ENTRY(sys_call_table) .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_timerfd + .long sys_timerfd_create .long sys_eventfd .long sys_fallocate + .long sys_timerfd_settime /* 325 */ + .long sys_timerfd_gettime diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8f94a0b89df..cf530814868 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1739,7 +1739,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr, if (bytes == 8) { gpa_t gpa; struct page *page; - char *addr; + char *kaddr; u64 val; down_read(¤t->mm->mmap_sem); @@ -1754,9 +1754,9 @@ static int emulator_cmpxchg_emulated(unsigned long addr, val = *(u64 *)new; page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); - addr = kmap_atomic(page, KM_USER0); - set_64bit((u64 *)(addr + offset_in_page(gpa)), val); - kunmap_atomic(addr, KM_USER0); + kaddr = kmap_atomic(page, KM_USER0); + set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val); + kunmap_atomic(kaddr, KM_USER0); kvm_release_page_dirty(page); emul_write: up_read(¤t->mm->mmap_sem); diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 4876182daf8..25df1c1989f 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -21,7 +21,7 @@ else lib-y += csum-partial_64.o csum-copy_64.o csum-wrappers_64.o lib-y += thunk_64.o clear_page_64.o copy_page_64.o - lib-y += bitstr_64.o bitops_64.o + lib-y += bitops_64.o lib-y += memmove_64.o memset_64.o lib-y += copy_user_64.o rwlock_64.o copy_user_nocache_64.o endif diff --git a/arch/x86/lib/bitstr_64.c b/arch/x86/lib/bitstr_64.c deleted file mode 100644 index 7445caf1b5d..00000000000 --- a/arch/x86/lib/bitstr_64.c +++ /dev/null @@ -1,28 +0,0 @@ -#include <linux/module.h> -#include <linux/bitops.h> - -/* Find string of zero bits in a bitmap */ -unsigned long -find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len) -{ - unsigned long n, end, i; - - again: - n = find_next_zero_bit(bitmap, nbits, start); - if (n == -1) - return -1; - - /* could test bitsliced, but it's hardly worth it */ - end = n+len; - if (end > nbits) - return -1; - for (i = n+1; i < end; i++) { - if (test_bit(i, bitmap)) { - start = i+1; - goto again; - } - } - return n; -} - -EXPORT_SYMBOL(find_next_zero_string); diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c index c7db504be1e..6c1914622a8 100644 --- a/arch/x86/mm/pgtable_32.c +++ b/arch/x86/mm/pgtable_32.c @@ -272,7 +272,7 @@ static void pgd_dtor(void *pgd) * preallocate which never got a corresponding vma will need to be * freed manually. */ -static void pgd_mop_up_pmds(pgd_t *pgdp) +static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) { int i; @@ -285,7 +285,7 @@ static void pgd_mop_up_pmds(pgd_t *pgdp) pgdp[i] = native_make_pgd(0); paravirt_release_pd(pgd_val(pgd) >> PAGE_SHIFT); - pmd_free(pmd); + pmd_free(mm, pmd); } } } @@ -313,7 +313,7 @@ static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) pmd_t *pmd = pmd_alloc_one(mm, addr); if (!pmd) { - pgd_mop_up_pmds(pgd); + pgd_mop_up_pmds(mm, pgd); return 0; } @@ -333,7 +333,7 @@ static int pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd) return 1; } -static void pgd_mop_up_pmds(pgd_t *pgd) +static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp) { } #endif /* CONFIG_X86_PAE */ @@ -352,9 +352,9 @@ pgd_t *pgd_alloc(struct mm_struct *mm) return pgd; } -void pgd_free(pgd_t *pgd) +void pgd_free(struct mm_struct *mm, pgd_t *pgd) { - pgd_mop_up_pmds(pgd); + pgd_mop_up_pmds(mm, pgd); quicklist_free(0, pgd_dtor, pgd); } diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 42ba0e2da1a..103b9dff121 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -72,7 +72,7 @@ pcibios_align_resource(void *data, struct resource *res, } } } - +EXPORT_SYMBOL(pcibios_align_resource); /* * Handle resources of PCI devices. If the world were perfect, we could |