diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/Kconfig Sat Jun 19 00:13:43 2004 @@ -149,20 +149,6 @@ default "6" if ITANIUM # align cache-sensitive data to 64 bytes -config MCKINLEY_ASTEP_SPECIFIC - bool "McKinley A-step specific code" - depends on MCKINLEY - help - Select this option to build a kernel for an IA-64 McKinley prototype - system with any A-stepping CPU. - -config MCKINLEY_A0_SPECIFIC - bool "McKinley A0/A1-step specific code" - depends on MCKINLEY_ASTEP_SPECIFIC - help - Select this option to build a kernel for an IA-64 McKinley prototype - system with an A0 or A1 stepping CPU. - config NUMA bool "NUMA support" depends on !IA64_HP_SIM @@ -444,6 +430,33 @@ send a BREAK and then within 5 seconds a command keypress. The keys are documented in . Don't say Y unless you really know what this hack does. + +config IA64_EARLY_PRINTK + bool "Early printk support" + depends on DEBUG_KERNEL && !IA64_GENERIC + help + Selecting this option uses the VGA screen or serial console for + printk() output before the consoles are initialised. It is useful + for debugging problems early in the boot process, but only if you + have a suitable VGA/serial console attached. If you're unsure, + select N. + +config IA64_EARLY_PRINTK_UART + bool "Early printk on MMIO serial port" + depends on IA64_EARLY_PRINTK + +config IA64_EARLY_PRINTK_UART_BASE + hex "UART MMIO base address" + depends on IA64_EARLY_PRINTK_UART + default "ff5e0000" + +config IA64_EARLY_PRINTK_VGA + bool "Early printk on VGA" + depends on IA64_EARLY_PRINTK + +config IA64_EARLY_PRINTK_SGI_SN + bool "Early printk on SGI SN serial console" + depends on IA64_EARLY_PRINTK && (IA64_GENERIC || IA64_SGI_SN2) config DEBUG_SLAB bool "Debug memory allocations" diff -Nru a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig --- a/arch/ia64/configs/sn2_defconfig Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/configs/sn2_defconfig Sat Jun 19 00:13:42 2004 @@ -14,18 +14,22 @@ # CONFIG_SWAP=y CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=20 CONFIG_HOTPLUG=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -60,7 +64,6 @@ CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set CONFIG_IA64_L1_CACHE_SHIFT=7 -# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set CONFIG_NUMA=y CONFIG_VIRTUAL_MEM_MAP=y CONFIG_DISCONTIGMEM=y @@ -70,12 +73,17 @@ CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=512 +# CONFIG_HOTPLUG_CPU is not set # CONFIG_PREEMPT is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y CONFIG_COMPAT=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y + +# +# Firmware Drivers +# CONFIG_EFI_VARS=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set @@ -105,6 +113,7 @@ # CONFIG_PCI=y CONFIG_PCI_DOMAINS=y +# CONFIG_PCI_USE_VECTOR is not set CONFIG_PCI_LEGACY_PROC=y CONFIG_PCI_NAMES=y @@ -174,7 +183,6 @@ # CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=m CONFIG_BLK_DEV_IDETAPE=m CONFIG_BLK_DEV_IDEFLOPPY=y @@ -218,6 +226,7 @@ # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -243,7 +252,6 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -281,7 +289,9 @@ CONFIG_SCSI_SATA_SVW=m CONFIG_SCSI_ATA_PIIX=m CONFIG_SCSI_SATA_PROMISE=m +# CONFIG_SCSI_SATA_SX4 is not set # CONFIG_SCSI_SATA_SIL is not set +# CONFIG_SCSI_SATA_SIS is not set CONFIG_SCSI_SATA_VIA=m CONFIG_SCSI_SATA_VITESSE=y # CONFIG_SCSI_BUSLOGIC is not set @@ -298,6 +308,7 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set CONFIG_SCSI_QLOGIC_1280=y @@ -343,6 +354,7 @@ # # I2O device support # +# CONFIG_I2O is not set # # Networking support @@ -389,8 +401,6 @@ CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_IPV6_TUNNEL=m -# CONFIG_DECNET is not set -CONFIG_BRIDGE=m CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set CONFIG_BRIDGE_NETFILTER=y @@ -452,6 +462,7 @@ CONFIG_IP_NF_ARP_MANGLE=m # CONFIG_IP_NF_COMPAT_IPCHAINS is not set # CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IP_NF_RAW is not set # # IPv6: Netfilter Configuration @@ -471,7 +482,9 @@ # # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -516,12 +529,14 @@ # Network testing # # CONFIG_NET_PKTGEN is not set +CONFIG_NETPOLL=y +# CONFIG_NETPOLL_RX is not set +# CONFIG_NETPOLL_TRAP is not set +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set CONFIG_DUMMY=m CONFIG_BONDING=m CONFIG_EQUALIZER=m @@ -529,6 +544,11 @@ # CONFIG_ETHERTAP is not set # +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -582,7 +602,6 @@ CONFIG_HAMACHI=m CONFIG_YELLOWFIN=m CONFIG_R8169=m -CONFIG_SIS190=m CONFIG_SK98LIN=m CONFIG_TIGON3=y @@ -591,6 +610,22 @@ # CONFIG_IXGB=m # CONFIG_IXGB_NAPI is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=m @@ -602,45 +637,11 @@ # CONFIG_PPP_BSDCOMP is not set # CONFIG_PPPOE is not set # CONFIG_SLIP is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set CONFIG_NET_FC=y # CONFIG_SHAPER is not set CONFIG_NETCONSOLE=y # -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -CONFIG_NET_POLL_CONTROLLER=y - -# # ISDN subsystem # # CONFIG_ISDN is not set @@ -703,6 +704,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_NONSTANDARD=y # CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set # CONFIG_SYNCLINK is not set # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set @@ -713,18 +715,11 @@ # # Serial drivers # -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_HCDP=y -CONFIG_SERIAL_8250_ACPI=y -CONFIG_SERIAL_8250_NR_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250 is not set # # Non-8250 serial port support # -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -740,7 +735,6 @@ # # CONFIG_WATCHDOG is not set # CONFIG_HW_RANDOM is not set -# CONFIG_GEN_RTC is not set CONFIG_EFI_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -852,6 +846,7 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y @@ -897,7 +892,6 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -968,6 +962,7 @@ # Library routines # CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=m CONFIG_ZLIB_DEFLATE=m @@ -1019,4 +1014,5 @@ # CONFIG_CRYPTO_ARC4 is not set CONFIG_CRYPTO_DEFLATE=m # CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig --- a/arch/ia64/defconfig Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/defconfig Sat Jun 19 00:13:42 2004 @@ -26,6 +26,7 @@ CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -66,7 +67,6 @@ CONFIG_IA64_PAGE_SIZE_16KB=y # CONFIG_IA64_PAGE_SIZE_64KB is not set CONFIG_IA64_L1_CACHE_SHIFT=7 -# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set # CONFIG_NUMA is not set CONFIG_VIRTUAL_MEM_MAP=y # CONFIG_IA64_CYCLONE is not set @@ -74,6 +74,7 @@ CONFIG_FORCE_MAX_ZONEORDER=18 CONFIG_SMP=y CONFIG_NR_CPUS=16 +# CONFIG_HOTPLUG_CPU is not set # CONFIG_PREEMPT is not set CONFIG_HAVE_DEC_LOCK=y CONFIG_IA32_SUPPORT=y @@ -178,7 +179,6 @@ # CONFIG_BLK_DEV_IDEDISK=y CONFIG_IDEDISK_MULTI_MODE=y -# CONFIG_IDEDISK_STROKE is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set CONFIG_BLK_DEV_IDEFLOPPY=m @@ -220,6 +220,7 @@ # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -245,7 +246,6 @@ # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y -CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y @@ -282,6 +282,7 @@ CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_QLOGIC_ISP is not set @@ -328,6 +329,7 @@ # # I2O device support # +# CONFIG_I2O is not set # # Networking support @@ -573,7 +575,12 @@ # # IPMI # -# CONFIG_IPMI_HANDLER is not set +CONFIG_IPMI_HANDLER=m +CONFIG_IPMI_PANIC_EVENT=y +CONFIG_IPMI_PANIC_STRING=y +CONFIG_IPMI_DEVICE_INTERFACE=m +CONFIG_IPMI_SI=m +CONFIG_IPMI_WATCHDOG=m # # Watchdog Cards @@ -651,6 +658,7 @@ # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set @@ -662,6 +670,7 @@ # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -688,6 +697,7 @@ # CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_RIVA=m # CONFIG_FB_MATROX is not set @@ -852,6 +862,7 @@ # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set # CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -901,6 +912,7 @@ # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set # CONFIG_USB_TEST is not set # @@ -998,7 +1010,6 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -1083,7 +1094,7 @@ # CONFIG_IA64_GRANULE_64MB is not set CONFIG_DEBUG_KERNEL=y CONFIG_IA64_PRINT_HAZARDS=y -CONFIG_DISABLE_VHPT=y +# CONFIG_DISABLE_VHPT is not set CONFIG_MAGIC_SYSRQ=y # CONFIG_IA64_EARLY_PRINTK_VGA is not set # CONFIG_DEBUG_SLAB is not set diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c --- a/arch/ia64/ia32/binfmt_elf32.c Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/ia32/binfmt_elf32.c Sat Jun 19 00:13:43 2004 @@ -197,6 +197,10 @@ } up_write(¤t->mm->mmap_sem); + /* Can't do it in ia64_elf32_init(). Needs to be done before calls to + elf32_map() */ + current->thread.ppl = ia32_init_pp_list(); + return 0; } diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/ia32/ia32_entry.S Sat Jun 19 00:13:42 2004 @@ -371,7 +371,7 @@ data8 sys_sched_get_priority_min /* 160 */ data8 sys32_sched_rr_get_interval data8 compat_sys_nanosleep - data8 sys_mremap + data8 sys32_mremap data8 sys_setresuid /* 16-bit version */ data8 sys32_getresuid16 /* 16-bit version */ /* 165 */ data8 sys_ni_syscall /* vm86 */ diff -Nru a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c --- a/arch/ia64/ia32/ia32_support.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/ia32/ia32_support.c Sat Jun 19 00:13:42 2004 @@ -218,6 +218,18 @@ ia32_exec_domain.signal_map = default_exec_domain.signal_map; ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; register_exec_domain(&ia32_exec_domain); + +#if PAGE_SHIFT > IA32_PAGE_SHIFT + { + extern kmem_cache_t *partial_page_cachep; + + partial_page_cachep = kmem_cache_create("partial_page_cache", + sizeof(struct partial_page), 0, 0, + NULL, NULL); + if (!partial_page_cachep) + panic("Cannot create partial page SLAB cache"); + } +#endif return 0; } diff -Nru a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h --- a/arch/ia64/ia32/ia32priv.h Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/ia32/ia32priv.h Sat Jun 19 00:13:43 2004 @@ -1,5 +1,5 @@ -#ifndef _ASM_IA64_IA32_H -#define _ASM_IA64_IA32_H +#ifndef _ASM_IA64_IA32_PRIV_H +#define _ASM_IA64_IA32_PRIV_H #include @@ -9,6 +9,7 @@ #include #include +#include #include @@ -16,12 +17,39 @@ * 32 bit structures for IA32 support. */ -#define IA32_PAGE_SHIFT 12 /* 4KB pages */ #define IA32_PAGE_SIZE (1UL << IA32_PAGE_SHIFT) #define IA32_PAGE_MASK (~(IA32_PAGE_SIZE - 1)) #define IA32_PAGE_ALIGN(addr) (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK) #define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ +/* + * partially mapped pages provide precise accounting of which 4k sub pages + * are mapped and which ones are not, thereby improving IA-32 compatibility. + */ +struct partial_page { + struct partial_page *next; /* linked list, sorted by address */ + struct rb_node pp_rb; + /* 64K is the largest "normal" page supported by ia64 ABI. So 4K*32 + * should suffice.*/ + unsigned int bitmap; + unsigned int base; +}; + +struct partial_page_list { + struct partial_page *pp_head; /* list head, points to the lowest + * addressed partial page */ + struct rb_root ppl_rb; + struct partial_page *pp_hint; /* pp_hint->next is the last + * accessed partial page */ + atomic_t pp_count; /* reference count */ +}; + +#if PAGE_SHIFT > IA32_PAGE_SHIFT +struct partial_page_list* ia32_init_pp_list (void); +#else +# define ia32_init_pp_list() 0 +#endif + /* sigcontext.h */ /* * As documented in the iBCS2 standard.. @@ -528,4 +556,4 @@ #endif /* !CONFIG_IA32_SUPPORT */ -#endif /* _ASM_IA64_IA32_H */ +#endif /* _ASM_IA64_IA32_PRIV_H */ diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/ia32/sys_ia32.c Sat Jun 19 00:13:42 2004 @@ -8,6 +8,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 2000-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 2004 Gordon Jin * * These routines maintain argument size conversion between 32bit and 64bit * environment. @@ -48,6 +49,7 @@ #include #include #include +#include #include #include @@ -250,6 +252,508 @@ return ret; } +/* SLAB cache for partial_page structures */ +kmem_cache_t *partial_page_cachep; + +/* + * init partial_page_list. + * return 0 means kmalloc fail. + */ +struct partial_page_list* +ia32_init_pp_list(void) +{ + struct partial_page_list *p; + + if ((p = kmalloc(sizeof(*p), GFP_KERNEL)) == NULL) + return p; + p->pp_head = 0; + p->ppl_rb = RB_ROOT; + p->pp_hint = 0; + atomic_set(&p->pp_count, 1); + return p; +} + +/* + * Search for the partial page with @start in partial page list @ppl. + * If finds the partial page, return the found partial page. + * Else, return 0 and provide @pprev, @rb_link, @rb_parent to + * be used by later __ia32_insert_pp(). + */ +static struct partial_page * +__ia32_find_pp(struct partial_page_list *ppl, unsigned int start, + struct partial_page **pprev, struct rb_node ***rb_link, + struct rb_node **rb_parent) +{ + struct partial_page *pp; + struct rb_node **__rb_link, *__rb_parent, *rb_prev; + + pp = ppl->pp_hint; + if (pp && pp->base == start) + return pp; + + __rb_link = &ppl->ppl_rb.rb_node; + rb_prev = __rb_parent = NULL; + + while (*__rb_link) { + __rb_parent = *__rb_link; + pp = rb_entry(__rb_parent, struct partial_page, pp_rb); + + if (pp->base == start) { + ppl->pp_hint = pp; + return pp; + } else if (pp->base < start) { + rb_prev = __rb_parent; + __rb_link = &__rb_parent->rb_right; + } else { + __rb_link = &__rb_parent->rb_left; + } + } + + *rb_link = __rb_link; + *rb_parent = __rb_parent; + *pprev = NULL; + if (rb_prev) + *pprev = rb_entry(rb_prev, struct partial_page, pp_rb); + return NULL; +} + +/* + * insert @pp into @ppl. + */ +static void +__ia32_insert_pp(struct partial_page_list *ppl, struct partial_page *pp, + struct partial_page *prev, struct rb_node **rb_link, + struct rb_node *rb_parent) +{ + /* link list */ + if (prev) { + pp->next = prev->next; + prev->next = pp; + } else { + ppl->pp_head = pp; + if (rb_parent) + pp->next = rb_entry(rb_parent, + struct partial_page, pp_rb); + else + pp->next = NULL; + } + + /* link rb */ + rb_link_node(&pp->pp_rb, rb_parent, rb_link); + rb_insert_color(&pp->pp_rb, &ppl->ppl_rb); + + ppl->pp_hint = pp; +} + +/* + * delete @pp from partial page list @ppl. + */ +static void +__ia32_delete_pp(struct partial_page_list *ppl, struct partial_page *pp, + struct partial_page *prev) +{ + if (prev) { + prev->next = pp->next; + if (ppl->pp_hint == pp) + ppl->pp_hint = prev; + } else { + ppl->pp_head = pp->next; + if (ppl->pp_hint == pp) + ppl->pp_hint = pp->next; + } + rb_erase(&pp->pp_rb, &ppl->ppl_rb); + kmem_cache_free(partial_page_cachep, pp); +} + +static struct partial_page * +__pp_prev(struct partial_page *pp) +{ + struct rb_node *prev = rb_prev(&pp->pp_rb); + if (prev) + return rb_entry(prev, struct partial_page, pp_rb); + else + return NULL; +} + +/* + * Delete partial pages with address between @start and @end. + * @start and @end are page aligned. + */ +static void +__ia32_delete_pp_range(unsigned int start, unsigned int end) +{ + struct partial_page *pp, *prev; + struct rb_node **rb_link, *rb_parent; + + if (start >= end) + return; + + pp = __ia32_find_pp(current->thread.ppl, start, &prev, + &rb_link, &rb_parent); + if (pp) + prev = __pp_prev(pp); + else { + if (prev) + pp = prev->next; + else + pp = current->thread.ppl->pp_head; + } + + while (pp && pp->base < end) { + struct partial_page *tmp = pp->next; + __ia32_delete_pp(current->thread.ppl, pp, prev); + pp = tmp; + } +} + +/* + * Set the range between @start and @end in bitmap. + * @start and @end should be IA32 page aligned and in the same IA64 page. + */ +static int +__ia32_set_pp(unsigned int start, unsigned int end, int flags) +{ + struct partial_page *pp, *prev; + struct rb_node ** rb_link, *rb_parent; + unsigned int pstart, start_bit, end_bit, i; + + pstart = PAGE_START(start); + start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE; + end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE; + if (end_bit == 0) + end_bit = PAGE_SIZE / IA32_PAGE_SIZE; + pp = __ia32_find_pp(current->thread.ppl, pstart, &prev, + &rb_link, &rb_parent); + if (pp) { + for (i = start_bit; i < end_bit; i++) + set_bit(i, &pp->bitmap); + /* + * Check: if this partial page has been set to a full page, + * then delete it. + */ + if (find_first_zero_bit(&pp->bitmap, sizeof(pp->bitmap)*8) >= + PAGE_SIZE/IA32_PAGE_SIZE) { + __ia32_delete_pp(current->thread.ppl, pp, __pp_prev(pp)); + } + return 0; + } + + /* + * MAP_FIXED may lead to overlapping mmap. + * In this case, the requested mmap area may already mmaped as a full + * page. So check vma before adding a new partial page. + */ + if (flags & MAP_FIXED) { + struct vm_area_struct *vma = find_vma(current->mm, pstart); + if (vma && vma->vm_start <= pstart) + return 0; + } + + /* new a partial_page */ + pp = kmem_cache_alloc(partial_page_cachep, GFP_KERNEL); + if (!pp) + return -ENOMEM; + pp->base = pstart; + pp->bitmap = 0; + for (i=start_bit; ibitmap)); + pp->next = NULL; + __ia32_insert_pp(current->thread.ppl, pp, prev, rb_link, rb_parent); + return 0; +} + +/* + * @start and @end should be IA32 page aligned, but don't need to be in the + * same IA64 page. Split @start and @end to make sure they're in the same IA64 + * page, then call __ia32_set_pp(). + */ +static void +ia32_set_pp(unsigned int start, unsigned int end, int flags) +{ + down_write(¤t->mm->mmap_sem); + if (flags & MAP_FIXED) { + /* + * MAP_FIXED may lead to overlapping mmap. When this happens, + * a series of complete IA64 pages results in deletion of + * old partial pages in that range. + */ + __ia32_delete_pp_range(PAGE_ALIGN(start), PAGE_START(end)); + } + + if (end < PAGE_ALIGN(start)) { + __ia32_set_pp(start, end, flags); + } else { + if (offset_in_page(start)) + __ia32_set_pp(start, PAGE_ALIGN(start), flags); + if (offset_in_page(end)) + __ia32_set_pp(PAGE_START(end), end, flags); + } + up_write(¤t->mm->mmap_sem); +} + +/* + * Unset the range between @start and @end in bitmap. + * @start and @end should be IA32 page aligned and in the same IA64 page. + * After doing that, if the bitmap is 0, then free the page and return 1, + * else return 0; + * If not find the partial page in the list, then + * If the vma exists, then the full page is set to a partial page; + * Else return -ENOMEM. + */ +static int +__ia32_unset_pp(unsigned int start, unsigned int end) +{ + struct partial_page *pp, *prev; + struct rb_node ** rb_link, *rb_parent; + unsigned int pstart, start_bit, end_bit, i; + struct vm_area_struct *vma; + + pstart = PAGE_START(start); + start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE; + end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE; + if (end_bit == 0) + end_bit = PAGE_SIZE / IA32_PAGE_SIZE; + + pp = __ia32_find_pp(current->thread.ppl, pstart, &prev, + &rb_link, &rb_parent); + if (pp) { + for (i = start_bit; i < end_bit; i++) + clear_bit(i, &pp->bitmap); + if (pp->bitmap == 0) { + __ia32_delete_pp(current->thread.ppl, pp, __pp_prev(pp)); + return 1; + } + return 0; + } + + vma = find_vma(current->mm, pstart); + if (!vma || vma->vm_start > pstart) { + return -ENOMEM; + } + + /* new a partial_page */ + pp = kmem_cache_alloc(partial_page_cachep, GFP_KERNEL); + if (!pp) + return -ENOMEM; + pp->base = pstart; + pp->bitmap = 0; + for (i = 0; i < start_bit; i++) + set_bit(i, &(pp->bitmap)); + for (i = end_bit; i < PAGE_SIZE / IA32_PAGE_SIZE; i++) + set_bit(i, &(pp->bitmap)); + pp->next = NULL; + __ia32_insert_pp(current->thread.ppl, pp, prev, rb_link, rb_parent); + return 0; +} + +/* + * Delete pp between PAGE_ALIGN(start) and PAGE_START(end) by calling + * __ia32_delete_pp_range(). Unset possible partial pages by calling + * __ia32_unset_pp(). + * The returned value see __ia32_unset_pp(). + */ +static int +ia32_unset_pp(unsigned int *startp, unsigned int *endp) +{ + unsigned int start = *startp, end = *endp; + int ret = 0; + + down_write(¤t->mm->mmap_sem); + + __ia32_delete_pp_range(PAGE_ALIGN(start), PAGE_START(end)); + + if (end < PAGE_ALIGN(start)) { + ret = __ia32_unset_pp(start, end); + if (ret == 1) { + *startp = PAGE_START(start); + *endp = PAGE_ALIGN(end); + } + if (ret == 0) { + /* to shortcut sys_munmap() in sys32_munmap() */ + *startp = PAGE_START(start); + *endp = PAGE_START(end); + } + } else { + if (offset_in_page(start)) { + ret = __ia32_unset_pp(start, PAGE_ALIGN(start)); + if (ret == 1) + *startp = PAGE_START(start); + if (ret == 0) + *startp = PAGE_ALIGN(start); + if (ret < 0) + goto out; + } + if (offset_in_page(end)) { + ret = __ia32_unset_pp(PAGE_START(end), end); + if (ret == 1) + *endp = PAGE_ALIGN(end); + if (ret == 0) + *endp = PAGE_START(end); + } + } + + out: + up_write(¤t->mm->mmap_sem); + return ret; +} + +/* + * Compare the range between @start and @end with bitmap in partial page. + * @start and @end should be IA32 page aligned and in the same IA64 page. + */ +static int +__ia32_compare_pp(unsigned int start, unsigned int end) +{ + struct partial_page *pp, *prev; + struct rb_node ** rb_link, *rb_parent; + unsigned int pstart, start_bit, end_bit, size; + unsigned int first_bit, next_zero_bit; /* the first range in bitmap */ + + pstart = PAGE_START(start); + + pp = __ia32_find_pp(current->thread.ppl, pstart, &prev, + &rb_link, &rb_parent); + if (!pp) + return 1; + + start_bit = (start % PAGE_SIZE) / IA32_PAGE_SIZE; + end_bit = (end % PAGE_SIZE) / IA32_PAGE_SIZE; + size = sizeof(pp->bitmap) * 8; + first_bit = find_first_bit(&pp->bitmap, size); + next_zero_bit = find_next_zero_bit(&pp->bitmap, size, first_bit); + if ((start_bit < first_bit) || (end_bit > next_zero_bit)) { + /* exceeds the first range in bitmap */ + return -ENOMEM; + } else if ((start_bit == first_bit) && (end_bit == next_zero_bit)) { + first_bit = find_next_bit(&pp->bitmap, size, next_zero_bit); + if ((next_zero_bit < first_bit) && (first_bit < size)) + return 1; /* has next range */ + else + return 0; /* no next range */ + } else + return 1; +} + +/* + * @start and @end should be IA32 page aligned, but don't need to be in the + * same IA64 page. Split @start and @end to make sure they're in the same IA64 + * page, then call __ia32_compare_pp(). + * + * Take this as example: the range is the 1st and 2nd 4K page. + * Return 0 if they fit bitmap exactly, i.e. bitmap = 00000011; + * Return 1 if the range doesn't cover whole bitmap, e.g. bitmap = 00001111; + * Return -ENOMEM if the range exceeds the bitmap, e.g. bitmap = 00000001 or + * bitmap = 00000101. + */ +static int +ia32_compare_pp(unsigned int *startp, unsigned int *endp) +{ + unsigned int start = *startp, end = *endp; + int retval = 0; + + down_write(¤t->mm->mmap_sem); + + if (end < PAGE_ALIGN(start)) { + retval = __ia32_compare_pp(start, end); + if (retval == 0) { + *startp = PAGE_START(start); + *endp = PAGE_ALIGN(end); + } + } else { + if (offset_in_page(start)) { + retval = __ia32_compare_pp(start, + PAGE_ALIGN(start)); + if (retval == 0) + *startp = PAGE_START(start); + if (retval < 0) + goto out; + } + if (offset_in_page(end)) { + retval = __ia32_compare_pp(PAGE_START(end), end); + if (retval == 0) + *endp = PAGE_ALIGN(end); + } + } + + out: + up_write(¤t->mm->mmap_sem); + return retval; +} + +static void +__ia32_drop_pp_list(struct partial_page_list *ppl) +{ + struct partial_page *pp = ppl->pp_head; + + while (pp) { + struct partial_page *next = pp->next; + kmem_cache_free(partial_page_cachep, pp); + pp = next; + } + + kfree(ppl); +} + +void +ia32_drop_partial_page_list(struct task_struct *task) +{ + struct partial_page_list* ppl = task->thread.ppl; + + if (ppl && atomic_dec_and_test(&ppl->pp_count)) + __ia32_drop_pp_list(ppl); +} + +/* + * Copy current->thread.ppl to ppl (already initialized). + */ +static int +__ia32_copy_pp_list(struct partial_page_list *ppl) +{ + struct partial_page *pp, *tmp, *prev; + struct rb_node **rb_link, *rb_parent; + + ppl->pp_head = NULL; + ppl->pp_hint = NULL; + ppl->ppl_rb = RB_ROOT; + rb_link = &ppl->ppl_rb.rb_node; + rb_parent = NULL; + prev = NULL; + + for (pp = current->thread.ppl->pp_head; pp; pp = pp->next) { + tmp = kmem_cache_alloc(partial_page_cachep, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + *tmp = *pp; + __ia32_insert_pp(ppl, tmp, prev, rb_link, rb_parent); + prev = tmp; + rb_link = &tmp->pp_rb.rb_right; + rb_parent = &tmp->pp_rb; + } + return 0; +} + +int +ia32_copy_partial_page_list(struct task_struct *p, unsigned long clone_flags) +{ + int retval = 0; + + if (clone_flags & CLONE_VM) { + atomic_inc(¤t->thread.ppl->pp_count); + p->thread.ppl = current->thread.ppl; + } else { + p->thread.ppl = ia32_init_pp_list(); + if (!p->thread.ppl) + return -ENOMEM; + down_write(¤t->mm->mmap_sem); + { + retval = __ia32_copy_pp_list(p->thread.ppl); + } + up_write(¤t->mm->mmap_sem); + } + + return retval; +} + static unsigned long emulate_mmap (struct file *file, unsigned long start, unsigned long len, int prot, int flags, loff_t off) @@ -263,6 +767,7 @@ pend = PAGE_ALIGN(end); if (flags & MAP_FIXED) { + ia32_set_pp((unsigned int)start, (unsigned int)end, flags); if (start > pstart) { if (flags & MAP_SHARED) printk(KERN_INFO @@ -274,7 +779,7 @@ return ret; pstart += PAGE_SIZE; if (pstart >= pend) - return start; /* done */ + goto out; /* done */ } if (end < pend) { if (flags & MAP_SHARED) @@ -287,7 +792,7 @@ return ret; pend -= PAGE_SIZE; if (pstart >= pend) - return start; /* done */ + goto out; /* done */ } } else { /* @@ -341,6 +846,10 @@ if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0) return -EINVAL; } + + if (!(flags & MAP_FIXED)) + ia32_set_pp((unsigned int)start, (unsigned int)end, flags); +out: return start; } @@ -478,11 +987,16 @@ #if PAGE_SHIFT <= IA32_PAGE_SHIFT ret = sys_munmap(start, end - start); #else + if (OFFSET4K(start)) + return -EINVAL; + + end = IA32_PAGE_ALIGN(end); if (start >= end) return -EINVAL; - start = PAGE_ALIGN(start); - end = PAGE_START(end); + ret = ia32_unset_pp(&start, &end); + if (ret < 0) + return ret; if (start >= end) return 0; @@ -521,7 +1035,7 @@ asmlinkage long sys32_mprotect (unsigned int start, unsigned int len, int prot) { - unsigned long end = start + len; + unsigned int end = start + len; #if PAGE_SHIFT > IA32_PAGE_SHIFT long retval = 0; #endif @@ -538,6 +1052,11 @@ if (end < start) return -EINVAL; + retval = ia32_compare_pp(&start, &end); + + if (retval < 0) + return retval; + down(&ia32_mmap_sem); { if (offset_in_page(start)) { @@ -565,6 +1084,59 @@ up(&ia32_mmap_sem); return retval; #endif +} + +asmlinkage long +sys32_mremap (unsigned int addr, unsigned int old_len, unsigned int new_len, + unsigned int flags, unsigned int new_addr) +{ + long ret; + +#if PAGE_SHIFT <= IA32_PAGE_SHIFT + ret = sys_mremap(addr, old_len, new_len, flags, new_addr); +#else + unsigned int old_end, new_end; + + if (OFFSET4K(addr)) + return -EINVAL; + + old_len = IA32_PAGE_ALIGN(old_len); + new_len = IA32_PAGE_ALIGN(new_len); + old_end = addr + old_len; + new_end = addr + new_len; + + if (!new_len) + return -EINVAL; + + if ((flags & MREMAP_FIXED) && (OFFSET4K(new_addr))) + return -EINVAL; + + if (old_len >= new_len) { + ret = sys32_munmap(addr + new_len, old_len - new_len); + if (ret && old_len != new_len) + return ret; + ret = addr; + if (!(flags & MREMAP_FIXED) || (new_addr == addr)) + return ret; + old_len = new_len; + } + + addr = PAGE_START(addr); + old_len = PAGE_ALIGN(old_end) - addr; + new_len = PAGE_ALIGN(new_end) - addr; + + down(&ia32_mmap_sem); + { + ret = sys_mremap(addr, old_len, new_len, flags, new_addr); + } + up(&ia32_mmap_sem); + + if ((ret >= 0) && (old_len < new_len)) { + /* mremap expanded successfully */ + ia32_set_pp(old_end, new_end, flags); + } +#endif + return ret; } asmlinkage long diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/entry.S Sat Jun 19 00:13:42 2004 @@ -179,17 +179,19 @@ .body adds r22=IA64_TASK_THREAD_KSP_OFFSET,r13 + movl r25=init_task mov r27=IA64_KR(CURRENT_STACK) + adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task shr.u r26=r20,IA64_GRANULE_SHIFT - adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 + cmp.eq p7,p6=r25,in0 ;; /* * If we've already mapped this task's page, we can skip doing it again. */ - cmp.eq p7,p6=r26,r27 +(p6) cmp.eq p7,p6=r26,r27 (p6) br.cond.dpnt .map ;; .done: diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/head.S Sat Jun 19 00:13:42 2004 @@ -154,6 +154,10 @@ #endif ;; tpa r3=r2 // r3 == phys addr of task struct + ;; + shr.u r16=r3,IA64_GRANULE_SHIFT +(isBP) br.cond.dpnt .load_current // BP stack is on region 5 --- no need to map it + // load mapping for stack (virtaddr in r2, physaddr in r3) rsm psr.ic movl r17=PAGE_KERNEL @@ -165,7 +169,6 @@ dep r2=-1,r3,61,3 // IMVA of task ;; mov r17=rr[r2] - shr.u r16=r3,IA64_GRANULE_SHIFT ;; dep r17=0,r17,8,24 ;; @@ -180,6 +183,7 @@ srlz.d ;; +.load_current: // load the "current" pointer (r13) and ar.k6 with the current task mov IA64_KR(CURRENT)=r2 // virtual address mov IA64_KR(CURRENT_STACK)=r16 diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/iosapic.c Sat Jun 19 00:13:42 2004 @@ -100,7 +100,6 @@ #endif static spinlock_t iosapic_lock = SPIN_LOCK_UNLOCKED; -extern cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; /* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ @@ -333,21 +332,6 @@ } spin_unlock_irqrestore(&iosapic_lock, flags); #endif -} - -static inline void move_irq(int irq) -{ - /* note - we hold desc->lock */ - cpumask_t tmp; - irq_desc_t *desc = irq_descp(irq); - - if (!cpus_empty(pending_irq_cpumask[irq])) { - cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); - if (unlikely(!cpus_empty(tmp))) { - desc->handler->set_affinity(irq, pending_irq_cpumask[irq]); - } - cpus_clear(pending_irq_cpumask[irq]); - } } /* diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/kernel/irq.c Sat Jun 19 00:13:43 2004 @@ -1018,6 +1018,22 @@ return full_count; } +void move_irq(int irq) +{ + /* note - we hold desc->lock */ + cpumask_t tmp; + irq_desc_t *desc = irq_descp(irq); + + if (!cpus_empty(pending_irq_cpumask[irq])) { + cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); + if (unlikely(!cpus_empty(tmp))) { + desc->handler->set_affinity(irq, pending_irq_cpumask[irq]); + } + cpus_clear(pending_irq_cpumask[irq]); + } +} + + #endif /* CONFIG_SMP */ #ifdef CONFIG_HOTPLUG_CPU diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/mca.c Sat Jun 19 00:13:42 2004 @@ -108,6 +108,7 @@ #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ +#define CPE_HISTORY_LENGTH 5 #define CMC_HISTORY_LENGTH 5 static struct timer_list cpe_poll_timer; @@ -127,6 +128,8 @@ */ static int cpe_poll_enabled = 1; +static int cpe_vector = -1; + extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); /* @@ -267,20 +270,65 @@ */ #ifndef PLATFORM_MCA_HANDLERS +#ifdef CONFIG_ACPI + static irqreturn_t ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { - IA64_MCA_DEBUG("%s: received interrupt. CPU:%d vector = %#x\n", - __FUNCTION__, smp_processor_id(), cpe_irq); + static unsigned long cpe_history[CPE_HISTORY_LENGTH]; + static int index; + static spinlock_t cpe_history_lock = SPIN_LOCK_UNLOCKED; + + IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", + __FUNCTION__, cpe_irq, smp_processor_id()); /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); - /* Get the CMC error record and log it */ + /* Get the CPE error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); + + spin_lock(&cpe_history_lock); + if (!cpe_poll_enabled && cpe_vector >= 0) { + + int i, count = 1; /* we know 1 happened now */ + unsigned long now = jiffies; + + for (i = 0; i < CPE_HISTORY_LENGTH; i++) { + if (now - cpe_history[i] <= HZ) + count++; + } + + IA64_MCA_DEBUG(KERN_INFO "CPE threshold %d/%d\n", count, CPE_HISTORY_LENGTH); + if (count >= CPE_HISTORY_LENGTH) { + + cpe_poll_enabled = 1; + spin_unlock(&cpe_history_lock); + disable_irq_nosync(local_vector_to_irq(IA64_CPE_VECTOR)); + + /* + * Corrected errors will still be corrected, but + * make sure there's a log somewhere that indicates + * something is generating more than we can handle. + */ + printk(KERN_WARNING "WARNING: Switching to polling CPE handler; error records may be lost\n"); + + mod_timer(&cpe_poll_timer, jiffies + MIN_CPE_POLL_INTERVAL); + + /* lock already released, get out now */ + return IRQ_HANDLED; + } else { + cpe_history[index++] = now; + if (index == CPE_HISTORY_LENGTH) + index = 0; + } + } + spin_unlock(&cpe_history_lock); return IRQ_HANDLED; } +#endif /* CONFIG_ACPI */ + static void show_min_state (pal_min_state_area_t *minstate) { @@ -901,7 +949,7 @@ * handled */ static irqreturn_t -ia64_mca_cmc_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) +ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; unsigned int cpuid; @@ -912,7 +960,7 @@ if (start_count == -1) start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC); - ia64_mca_cmc_int_handler(cpe_irq, arg, ptregs); + ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs); for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -967,11 +1015,13 @@ * Outputs * handled */ +#ifdef CONFIG_ACPI + static irqreturn_t ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; - static int poll_time = MAX_CPE_POLL_INTERVAL; + static int poll_time = MIN_CPE_POLL_INTERVAL; unsigned int cpuid; cpuid = smp_processor_id(); @@ -989,20 +1039,30 @@ } else { /* * If a log was recorded, increase our polling frequency, - * otherwise, backoff. + * otherwise, backoff or return to interrupt mode. */ if (start_count != IA64_LOG_COUNT(SAL_INFO_TYPE_CPE)) { poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time / 2); - } else { + } else if (cpe_vector < 0) { poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2); + } else { + poll_time = MIN_CPE_POLL_INTERVAL; + + printk(KERN_WARNING "Returning to interrupt driven CPE handler\n"); + enable_irq(local_vector_to_irq(IA64_CPE_VECTOR)); + cpe_poll_enabled = 0; } + + if (cpe_poll_enabled) + mod_timer(&cpe_poll_timer, jiffies + poll_time); start_count = -1; - mod_timer(&cpe_poll_timer, jiffies + poll_time); } return IRQ_HANDLED; } +#endif /* CONFIG_ACPI */ + /* * ia64_mca_cpe_poll * @@ -1240,21 +1300,23 @@ register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); #ifdef CONFIG_ACPI - /* Setup the CPE interrupt vector */ + /* Setup the CPEI/P vector and handler */ { irq_desc_t *desc; unsigned int irq; - int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); - if (cpev >= 0) { + cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); + + if (cpe_vector >= 0) { for (irq = 0; irq < NR_IRQS; ++irq) - if (irq_to_vector(irq) == cpev) { + if (irq_to_vector(irq) == cpe_vector) { desc = irq_descp(irq); desc->status |= IRQ_PER_CPU; setup_irq(irq, &mca_cpe_irqaction); } - ia64_mca_register_cpev(cpev); + ia64_mca_register_cpev(cpe_vector); } + register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); } #endif @@ -1294,9 +1356,10 @@ #ifdef CONFIG_ACPI /* If platform doesn't support CPEI, get the timer going. */ - if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) { - register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); + if (cpe_vector < 0 && cpe_poll_enabled) { ia64_mca_cpe_poll(0UL); + } else { + cpe_poll_enabled = 0; } #endif diff -Nru a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c --- a/arch/ia64/kernel/palinfo.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/palinfo.c Sat Jun 19 00:13:42 2004 @@ -515,10 +515,10 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "Enable Cache Line Repl. Exclusive", "Enable Cache Line Repl. Shared", + "Enable Cache Line Repl. Exclusive", "Disable Transaction Queuing", - "Disable Reponse Error Checking", + "Disable Response Error Checking", "Disable Bus Error Checking", "Disable Bus Requester Internal Error Signalling", "Disable Bus Requester Error Signalling", diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/kernel/perfmon.c Sat Jun 19 00:13:43 2004 @@ -311,6 +311,7 @@ unsigned int ctx_cpu; /* cpu to which perfmon is applied (system wide) */ int ctx_fd; /* file descriptor used my this context */ + pfm_ovfl_arg_t ctx_ovfl_arg; /* argument to custom buffer format handler */ pfm_buffer_fmt_t *ctx_buf_fmt; /* buffer format callbacks */ void *ctx_smpl_hdr; /* points to sampling buffer header kernel vaddr */ @@ -4584,31 +4585,6 @@ return 0; } -static void -pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) -{ - struct task_struct *task = ctx->ctx_task; - - ia64_psr(regs)->up = 0; - ia64_psr(regs)->sp = 1; - - if (GET_PMU_OWNER() == task) { - DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); - SET_PMU_OWNER(NULL, NULL); - } - - /* - * disconnect the task from the context and vice-versa - */ - PFM_SET_WORK_PENDING(task, 0); - - task->thread.pfm_context = NULL; - task->thread.flags &= ~IA64_THREAD_PM_VALID; - - DPRINT(("force cleanupf for [%d]\n", task->pid)); -} - - /* * called only from exit_thread(): task == current @@ -5185,7 +5161,7 @@ static void pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { - pfm_ovfl_arg_t ovfl_arg; + pfm_ovfl_arg_t *ovfl_arg; unsigned long mask; unsigned long old_val, ovfl_val, new_val; unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL, reset_pmds; @@ -5272,7 +5248,8 @@ int j, k, ret = 0; int this_cpu = smp_processor_id(); - pmd_mask = ovfl_pmds >> PMU_FIRST_COUNTER; + pmd_mask = ovfl_pmds >> PMU_FIRST_COUNTER; + ovfl_arg = &ctx->ctx_ovfl_arg; prefetch(ctx->ctx_smpl_hdr); @@ -5282,15 +5259,15 @@ if ((pmd_mask & 0x1) == 0) continue; - ovfl_arg.ovfl_pmd = (unsigned char )i; - ovfl_arg.ovfl_notify = ovfl_notify & mask ? 1 : 0; - ovfl_arg.active_set = 0; - ovfl_arg.ovfl_ctrl.val = 0; /* module must fill in all fields */ - ovfl_arg.smpl_pmds[0] = smpl_pmds = ctx->ctx_pmds[i].smpl_pmds[0]; - - ovfl_arg.pmd_value = ctx->ctx_pmds[i].val; - ovfl_arg.pmd_last_reset = ctx->ctx_pmds[i].lval; - ovfl_arg.pmd_eventid = ctx->ctx_pmds[i].eventid; + ovfl_arg->ovfl_pmd = (unsigned char )i; + ovfl_arg->ovfl_notify = ovfl_notify & mask ? 1 : 0; + ovfl_arg->active_set = 0; + ovfl_arg->ovfl_ctrl.val = 0; /* module must fill in all fields */ + ovfl_arg->smpl_pmds[0] = smpl_pmds = ctx->ctx_pmds[i].smpl_pmds[0]; + + ovfl_arg->pmd_value = ctx->ctx_pmds[i].val; + ovfl_arg->pmd_last_reset = ctx->ctx_pmds[i].lval; + ovfl_arg->pmd_eventid = ctx->ctx_pmds[i].eventid; /* * copy values of pmds of interest. Sampling format may copy them @@ -5299,8 +5276,8 @@ if (smpl_pmds) { for(j=0, k=0; smpl_pmds; j++, smpl_pmds >>=1) { if ((smpl_pmds & 0x1) == 0) continue; - ovfl_arg.smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ? pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j); - DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg.smpl_pmds_values[k-1])); + ovfl_arg->smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ? pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j); + DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg->smpl_pmds_values[k-1])); } } @@ -5311,7 +5288,7 @@ /* * call custom buffer format record (handler) routine */ - ret = (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, &ovfl_arg, regs, tstamp); + ret = (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, ovfl_arg, regs, tstamp); end_cycles = ia64_get_itc(); @@ -5319,13 +5296,13 @@ * For those controls, we take the union because they have * an all or nothing behavior. */ - ovfl_ctrl.bits.notify_user |= ovfl_arg.ovfl_ctrl.bits.notify_user; - ovfl_ctrl.bits.block_task |= ovfl_arg.ovfl_ctrl.bits.block_task; - ovfl_ctrl.bits.mask_monitoring |= ovfl_arg.ovfl_ctrl.bits.mask_monitoring; + ovfl_ctrl.bits.notify_user |= ovfl_arg->ovfl_ctrl.bits.notify_user; + ovfl_ctrl.bits.block_task |= ovfl_arg->ovfl_ctrl.bits.block_task; + ovfl_ctrl.bits.mask_monitoring |= ovfl_arg->ovfl_ctrl.bits.mask_monitoring; /* * build the bitmask of pmds to reset now */ - if (ovfl_arg.ovfl_ctrl.bits.reset_ovfl_pmds) reset_pmds |= mask; + if (ovfl_arg->ovfl_ctrl.bits.reset_ovfl_pmds) reset_pmds |= mask; pfm_stats[this_cpu].pfm_smpl_handler_cycles += end_cycles - start_cycles; } @@ -5793,6 +5770,32 @@ } #ifdef CONFIG_SMP + +static void +pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + if (GET_PMU_OWNER() == task) { + DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); + SET_PMU_OWNER(NULL, NULL); + } + + /* + * disconnect the task from the context and vice-versa + */ + PFM_SET_WORK_PENDING(task, 0); + + task->thread.pfm_context = NULL; + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + DPRINT(("force cleanup for [%d]\n", task->pid)); +} + + /* * in 2.6, interrupts are masked when we come here and the runqueue lock is held */ diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/kernel/process.c Sat Jun 19 00:13:42 2004 @@ -439,6 +439,10 @@ ia32_save_state(p); if (clone_flags & CLONE_SETTLS) retval = ia32_clone_tls(p, child_ptregs); + + /* Copy partially mapped page list */ + if (!retval) + retval = ia32_copy_partial_page_list(p, clone_flags); } #endif @@ -672,6 +676,8 @@ /* drop floating-point and debug-register state if it exists: */ current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); ia64_drop_fpu(current); + if (IS_IA32_PROCESS(ia64_task_regs(current))) + ia32_drop_partial_page_list(current); } /* @@ -691,6 +697,8 @@ if (current->thread.flags & IA64_THREAD_DBG_VALID) pfm_release_debug_registers(current); #endif + if (IS_IA32_PROCESS(ia64_task_regs(current))) + ia32_drop_partial_page_list(current); } unsigned long diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c --- a/arch/ia64/kernel/unwind.c Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/kernel/unwind.c Sat Jun 19 00:13:43 2004 @@ -385,9 +385,10 @@ } if (write) { - if (read_only(addr)) - UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n"); - else { + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else { *addr = *val; if (*nat) *nat_addr |= nat_mask; @@ -432,9 +433,10 @@ return -1; } if (write) - if (read_only(addr)) - UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n"); - else + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else *addr = *val; else *val = *addr; @@ -480,9 +482,10 @@ } if (write) - if (read_only(addr)) - UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n"); - else + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else *addr = *val; else *val = *addr; @@ -576,9 +579,10 @@ } if (write) { - if (read_only(addr)) - UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n"); - else + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else *addr = *val; } else *val = *addr; @@ -596,9 +600,10 @@ addr = &info->sw->pr; if (write) { - if (read_only(addr)) - UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n"); - else + if (read_only(addr)) { + UNW_DPRINT(0, "unwind.%s: ignoring attempt to write read-only location\n", + __FUNCTION__); + } else *addr = *val; } else *val = *addr; diff -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c --- a/arch/ia64/mm/discontig.c Sat Jun 19 00:13:43 2004 +++ b/arch/ia64/mm/discontig.c Sat Jun 19 00:13:43 2004 @@ -154,6 +154,9 @@ memcpy(numa_slit, numa_slit_fix, sizeof (numa_slit)); + for (i = nnode; i < numnodes; i++) + node_set_offline(i); + numnodes = nnode; return; diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c --- a/arch/ia64/mm/hugetlbpage.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/mm/hugetlbpage.c Sat Jun 19 00:13:42 2004 @@ -297,7 +297,7 @@ unlock_page(page); } else { hugetlb_put_quota(mapping); - free_huge_page(page); + page_cache_release(page); goto out; } } diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/pci/pci.c Sat Jun 19 00:13:42 2004 @@ -358,8 +358,7 @@ for (ln = b->devices.next; ln != &b->devices; ln = ln->next) pcibios_fixup_device_resources(pci_dev_b(ln), b); - - return; + pci_read_bridge_bases(b); } void __devinit diff -Nru a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c --- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c Sat Jun 19 00:13:42 2004 @@ -741,7 +741,7 @@ /* Is this PCI bus associated with this moduleid? */ moduleid = NODE_MODULEID( nasid_to_cnodeid(pcibr_soft->bs_nasid)); - if (modules[i]->id == moduleid) { + if (sn_modules[i]->id == moduleid) { struct pcibr_list_s *new_element; new_element = kmalloc(sizeof (struct pcibr_soft_s), GFP_KERNEL); @@ -781,7 +781,7 @@ /* * We now have a list of all the pci bridges associated with - * the module_id, modules[i]. Call pci_bus_map_create() for + * the module_id, sn_modules[i]. Call pci_bus_map_create() for * each pci bridge */ softlistp = first_in_list; diff -Nru a/arch/ia64/sn/io/sn2/klgraph.c b/arch/ia64/sn/io/sn2/klgraph.c --- a/arch/ia64/sn/io/sn2/klgraph.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/io/sn2/klgraph.c Sat Jun 19 00:13:42 2004 @@ -527,7 +527,7 @@ /* Use module as module vertex fastinfo */ memset(buffer, 0, 16); - format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); + format_module_id(buffer, sn_modules[cm]->id, MODULE_FORMAT_BRIEF); sprintf(name, EDGE_LBL_MODULE "/%s", buffer); rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl); @@ -535,7 +535,7 @@ rc = rc; HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n"); - hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]); + hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) sn_modules[cm]); /* Add system controller */ sprintf(name, diff -Nru a/arch/ia64/sn/io/sn2/ml_iograph.c b/arch/ia64/sn/io/sn2/ml_iograph.c --- a/arch/ia64/sn/io/sn2/ml_iograph.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/io/sn2/ml_iograph.c Sat Jun 19 00:13:42 2004 @@ -518,6 +518,14 @@ ASSERT(hubv != GRAPH_VERTEX_NONE); /* + * attach our hub_provider information to hubv, + * so we can use it as a crosstalk provider "master" + * vertex. + */ + xtalk_provider_register(hubv, &hub_provider); + xtalk_provider_startup(hubv); + + /* * If nothing connected to this hub's xtalk port, we're done. */ early_probe_for_widget(hubv, &hwid); @@ -526,14 +534,6 @@ return; /* NOTREACHED */ } - - /* - * attach our hub_provider information to hubv, - * so we can use it as a crosstalk provider "master" - * vertex. - */ - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); /* * Create a vertex to represent the crosstalk bus diff -Nru a/arch/ia64/sn/io/sn2/module.c b/arch/ia64/sn/io/sn2/module.c --- a/arch/ia64/sn/io/sn2/module.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/io/sn2/module.c Sat Jun 19 00:13:42 2004 @@ -33,7 +33,7 @@ #define DPRINTF(x...) #endif -module_t *modules[MODULE_MAX]; +module_t *sn_modules[MODULE_MAX]; int nummodules; #define SN00_SERIAL_FUDGE 0x3b1af409d513c2 @@ -59,9 +59,9 @@ int i; for (i = 0; i < nummodules; i++) - if (modules[i]->id == id) { - DPRINTF("module_lookup: found m=0x%p\n", modules[i]); - return modules[i]; + if (sn_modules[i]->id == id) { + DPRINTF("module_lookup: found m=0x%p\n", sn_modules[i]); + return sn_modules[i]; } return NULL; @@ -104,10 +104,10 @@ /* Insert in sorted order by module number */ - for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--) - modules[i] = modules[i - 1]; + for (i = nummodules; i > 0 && sn_modules[i - 1]->id > moduleid; i--) + sn_modules[i] = sn_modules[i - 1]; - modules[i] = m; + sn_modules[i] = m; nummodules++; } diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c --- a/arch/ia64/sn/kernel/irq.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/kernel/irq.c Sat Jun 19 00:13:42 2004 @@ -41,6 +41,7 @@ extern void pcibr_force_interrupt(pcibr_intr_t intr); extern int sn_force_interrupt_flag; struct irq_desc * sn_irq_desc(unsigned int irq); +extern cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; struct sn_intr_list_t { struct sn_intr_list_t *next; @@ -71,6 +72,21 @@ { } +static inline void move_irq(int irq) +{ + /* note - we hold desc->lock */ + cpumask_t tmp; + irq_desc_t *desc = irq_descp(irq); + + if (!cpus_empty(pending_irq_cpumask[irq])) { + cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); + if (unlikely(!cpus_empty(tmp))) { + desc->handler->set_affinity(irq, pending_irq_cpumask[irq]); + } + cpus_clear(pending_irq_cpumask[irq]); + } +} + static void sn_ack_irq(unsigned int irq) { @@ -94,6 +110,7 @@ } HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_EVENT_OCCURRED_ALIAS), mask ); __set_bit(irq, (volatile void *)pda->sn_in_service_ivecs); + move_irq(irq); } static void diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c --- a/arch/ia64/sn/kernel/setup.c Sat Jun 19 00:13:42 2004 +++ b/arch/ia64/sn/kernel/setup.c Sat Jun 19 00:13:42 2004 @@ -226,7 +226,25 @@ shub_1_1_found = 1; } - +/** + * sn_set_error_handling_features - Tell the SN prom how to handle certain + * error types. + */ +static void __init +sn_set_error_handling_features(void) +{ + u64 ret; + u64 sn_ehf_bits[7]; /* see ia64_sn_set_error_handling_features */ + memset(sn_ehf_bits, 0, sizeof(sn_ehf_bits)); +#define EHF(x) __set_bit(SN_SAL_EHF_ ## x, sn_ehf_bits) + EHF(MCA_SLV_TO_OS_INIT_SLV); + EHF(NO_RZ_TLBC); + // Uncomment once Jesse's code goes in - EHF(NO_RZ_IO_READ); +#undef EHF + ret = ia64_sn_set_error_handling_features(sn_ehf_bits); + if (ret) + printk(KERN_ERR "%s: failed, return code %ld\n", __FUNCTION__, ret); +} /** * sn_setup - SN platform setup routine @@ -317,6 +335,9 @@ printk(KERN_DEBUG "sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } + + /* Tell the prom how to handle certain error types */ + sn_set_error_handling_features(); /* * we set the default root device to /dev/hda diff -Nru a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile --- a/drivers/media/radio/Makefile Sat Jun 19 00:13:42 2004 +++ b/drivers/media/radio/Makefile Sat Jun 19 00:13:42 2004 @@ -2,6 +2,8 @@ # Makefile for the kernel character device drivers. # +obj-y := dummy.o + miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o diff -Nru a/drivers/media/radio/dummy.c b/drivers/media/radio/dummy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/radio/dummy.c Sat Jun 19 00:13:43 2004 @@ -0,0 +1 @@ +/* just so the linker knows what kind of object files it's deadling with... */ diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile --- a/drivers/media/video/Makefile Sat Jun 19 00:13:42 2004 +++ b/drivers/media/video/Makefile Sat Jun 19 00:13:42 2004 @@ -7,6 +7,7 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o +obj-y := dummy.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o diff -Nru a/drivers/media/video/dummy.c b/drivers/media/video/dummy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/media/video/dummy.c Sat Jun 19 00:13:43 2004 @@ -0,0 +1 @@ +/* just so the linker knows what kind of object files it's deadling with... */ diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c Sat Jun 19 00:13:42 2004 +++ b/drivers/usb/serial/ipaq.c Sat Jun 19 00:13:42 2004 @@ -218,7 +218,7 @@ * discipline instead of queueing. */ - port->tty->low_latency = 1; + port->tty->low_latency = 0; port->tty->raw = 1; port->tty->real_raw = 1; diff -Nru a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h --- a/include/asm-ia64/gcc_intrin.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/gcc_intrin.h Sat Jun 19 00:13:42 2004 @@ -489,10 +489,16 @@ #define ia64_ptce(addr) asm volatile ("ptc.e %0" :: "r"(addr)) #define ia64_ptcga(addr, size) \ - asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory") - -#define ia64_ptcl(addr, size) \ - asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory") +do { \ + asm volatile ("ptc.ga %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ +} while (0) + +#define ia64_ptcl(addr, size) \ +do { \ + asm volatile ("ptc.l %0,%1" :: "r"(addr), "r"(size) : "memory"); \ + ia64_dv_serialize_data(); \ +} while (0) #define ia64_ptri(addr, size) \ asm volatile ("ptr.i %0,%1" :: "r"(addr), "r"(size) : "memory") @@ -581,7 +587,7 @@ #define ia64_intrin_local_irq_restore(x) \ do { \ - asm volatile (" cmp.ne p6,p7=%0,r0;;" \ + asm volatile (";; cmp.ne p6,p7=%0,r0;;" \ "(p6) ssm psr.i;" \ "(p7) rsm psr.i;;" \ "(p6) srlz.d" \ diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h --- a/include/asm-ia64/ia32.h Sat Jun 19 00:13:43 2004 +++ b/include/asm-ia64/ia32.h Sat Jun 19 00:13:43 2004 @@ -6,7 +6,8 @@ #include #include -#define IA32_NR_syscalls 283 /* length of syscall table */ +#define IA32_NR_syscalls 283 /* length of syscall table */ +#define IA32_PAGE_SHIFT 12 /* 4KB pages */ #ifndef __ASSEMBLY__ @@ -24,6 +25,13 @@ /* Declare this unconditionally, so we don't get warnings for unreachable code. */ extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs); +#if PAGE_SHIFT > IA32_PAGE_SHIFT +extern int ia32_copy_partial_page_list (struct task_struct *, unsigned long); +extern void ia32_drop_partial_page_list (struct task_struct *); +#else +# define ia32_copy_partial_page_list(a1, a2) 0 +# define ia32_drop_partial_page_list(a1) do { ; } while (0) +#endif #endif /* !__ASSEMBLY__ */ diff -Nru a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h --- a/include/asm-ia64/irq.h Sat Jun 19 00:13:43 2004 +++ b/include/asm-ia64/irq.h Sat Jun 19 00:13:43 2004 @@ -30,6 +30,12 @@ extern void enable_irq (unsigned int); extern void set_irq_affinity_info (unsigned int irq, int dest, int redir); +#ifdef CONFIG_SMP +extern void move_irq(int irq); +#else +#define move_irq(irq) +#endif + struct irqaction; struct pt_regs; int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h --- a/include/asm-ia64/pgtable.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/pgtable.h Sat Jun 19 00:13:42 2004 @@ -297,11 +297,7 @@ * works bypasses the caches, but does allow for consecutive writes to * be combined into single (but larger) write transactions. */ -#ifdef CONFIG_MCKINLEY_A0_SPECIFIC -# define pgprot_writecombine(prot) prot -#else -# define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) -#endif +#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC) static inline unsigned long pgd_index (unsigned long address) diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/processor.h Sat Jun 19 00:13:42 2004 @@ -230,6 +230,7 @@ #define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8) +struct partial_page_list; #endif struct thread_struct { @@ -251,6 +252,7 @@ __u64 fdr; /* IA32 fp except. data reg */ __u64 old_k1; /* old value of ar.k1 */ __u64 old_iob; /* old IOBase value */ + struct partial_page_list *ppl; /* partial page list for 4K page size issue */ /* cached TLS descriptors. */ struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES]; @@ -260,7 +262,8 @@ .fir = 0, \ .fdr = 0, \ .old_k1 = 0, \ - .old_iob = 0, + .old_iob = 0, \ + .ppl = 0, #else # define INIT_THREAD_IA32 #endif /* CONFIG_IA32_SUPPORT */ diff -Nru a/include/asm-ia64/sn/module.h b/include/asm-ia64/sn/module.h --- a/include/asm-ia64/sn/module.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/sn/module.h Sat Jun 19 00:13:42 2004 @@ -180,7 +180,7 @@ }; /* module.c */ -extern module_t *modules[MODULE_MAX]; /* Indexed by cmoduleid_t */ +extern module_t *sn_modules[MODULE_MAX]; /* Indexed by cmoduleid_t */ extern int nummodules; extern module_t *module_lookup(moduleid_t id); diff -Nru a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h --- a/include/asm-ia64/sn/sn_sal.h Sat Jun 19 00:13:43 2004 +++ b/include/asm-ia64/sn/sn_sal.h Sat Jun 19 00:13:43 2004 @@ -33,6 +33,7 @@ #define SN_SAL_NO_FAULT_ZONE_VIRTUAL 0x02000010 #define SN_SAL_NO_FAULT_ZONE_PHYSICAL 0x02000011 #define SN_SAL_PRINT_ERROR 0x02000012 +#define SN_SAL_SET_ERROR_HANDLING_FEATURES 0x0200001a // reentrant #define SN_SAL_CONSOLE_PUTC 0x02000021 #define SN_SAL_CONSOLE_GETC 0x02000022 #define SN_SAL_CONSOLE_PUTS 0x02000023 @@ -92,6 +93,19 @@ #define SALRET_INVALID_ARG -2 #define SALRET_ERROR -3 +/* + * SN_SAL_SET_ERROR_HANDLING_FEATURES bit settings + */ +enum +{ + /* if "rz always" is set, have the mca slaves call os_init_slave */ + SN_SAL_EHF_MCA_SLV_TO_OS_INIT_SLV=0, + /* do not rz on tlb checks, even if "rz always" is set */ + SN_SAL_EHF_NO_RZ_TLBC, + /* do not rz on PIO reads to I/O space, even if "rz always" is set */ + SN_SAL_EHF_NO_RZ_IO_READ, +}; + /** * sn_sal_rev_major - get the major SGI SAL revision number @@ -668,6 +682,26 @@ if (rv.status) return rv.v0; return 0; +} + +/* + * Tell the prom how the OS wants to handle specific error features. + * It takes an array of 7 u64. + */ +static inline u64 +ia64_sn_set_error_handling_features(const u64 *feature_bits) +{ + struct ia64_sal_retval rv = {0, 0, 0, 0}; + + SAL_CALL_REENTRANT(rv, SN_SAL_SET_ERROR_HANDLING_FEATURES, + feature_bits[0], + feature_bits[1], + feature_bits[2], + feature_bits[3], + feature_bits[4], + feature_bits[5], + feature_bits[6]); + return rv.status; } #endif /* _ASM_IA64_SN_SN_SAL_H */ diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h --- a/include/asm-ia64/system.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/system.h Sat Jun 19 00:13:42 2004 @@ -171,7 +171,7 @@ # define local_irq_restore(x) __local_irq_restore(x) #endif /* !CONFIG_IA64_DEBUG_IRQ */ -#define local_irq_enable() ({ ia64_ssm(IA64_PSR_I); ia64_srlz_d(); }) +#define local_irq_enable() ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); }) #define local_save_flags(flags) ({ ia64_stop(); (flags) = ia64_getreg(_IA64_REG_PSR); }) #define irqs_disabled() \ diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h Sat Jun 19 00:13:42 2004 +++ b/include/asm-ia64/unistd.h Sat Jun 19 00:13:42 2004 @@ -266,6 +266,8 @@ #define NR_syscalls 256 /* length of syscall table */ +#define __ARCH_WANT_SYS_RT_SIGACTION + #ifdef CONFIG_IA32_SUPPORT # define __ARCH_WANT_SYS_FADVISE64 # define __ARCH_WANT_SYS_GETPGRP @@ -275,7 +277,6 @@ # define __ARCH_WANT_SYS_OLDUMOUNT # define __ARCH_WANT_SYS_SIGPENDING # define __ARCH_WANT_SYS_SIGPROCMASK -# define __ARCH_WANT_SYS_RT_SIGACTION #endif #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -Nru a/kernel/printk.c b/kernel/printk.c --- a/kernel/printk.c Sat Jun 19 00:13:43 2004 +++ b/kernel/printk.c Sat Jun 19 00:13:43 2004 @@ -406,6 +406,12 @@ __call_console_drivers(start, end); } } +#ifdef CONFIG_IA64_EARLY_PRINTK + if (!console_drivers) { + void early_printk (const char *str, size_t len); + early_printk(&LOG_BUF(start), end - start); + } +#endif } /* @@ -752,7 +758,11 @@ * for us. */ spin_lock_irqsave(&logbuf_lock, flags); +#ifdef CONFIG_IA64_EARLY_PRINTK + con_start = log_end; +#else con_start = log_start; +#endif spin_unlock_irqrestore(&logbuf_lock, flags); } release_console_sem(); @@ -854,3 +864,117 @@ printk_ratelimit_burst); } EXPORT_SYMBOL(printk_ratelimit); + +#ifdef CONFIG_IA64_EARLY_PRINTK + +#include + +# ifdef CONFIG_IA64_EARLY_PRINTK_VGA + + +#define VGABASE ((char *)0xc0000000000b8000) +#define VGALINES 24 +#define VGACOLS 80 + +static int current_ypos = VGALINES, current_xpos = 0; + +static void +early_printk_vga (const char *str, size_t len) +{ + char c; + int i, k, j; + + while (len-- > 0) { + c = *str++; + if (current_ypos >= VGALINES) { + /* scroll 1 line up */ + for (k = 1, j = 0; k < VGALINES; k++, j++) { + for (i = 0; i < VGACOLS; i++) { + writew(readw(VGABASE + 2*(VGACOLS*k + i)), + VGABASE + 2*(VGACOLS*j + i)); + } + } + for (i = 0; i < VGACOLS; i++) { + writew(0x720, VGABASE + 2*(VGACOLS*j + i)); + } + current_ypos = VGALINES-1; + } + if (c == '\n') { + current_xpos = 0; + current_ypos++; + } else if (c != '\r') { + writew(((0x7 << 8) | (unsigned short) c), + VGABASE + 2*(VGACOLS*current_ypos + current_xpos++)); + if (current_xpos >= VGACOLS) { + current_xpos = 0; + current_ypos++; + } + } + } +} + +# endif /* CONFIG_IA64_EARLY_PRINTK_VGA */ + +# ifdef CONFIG_IA64_EARLY_PRINTK_UART + +#include +#include + +static void early_printk_uart(const char *str, size_t len) +{ + static char *uart = NULL; + unsigned long uart_base; + char c; + + if (!uart) { + uart_base = 0; +# ifdef CONFIG_SERIAL_8250_HCDP + { + extern unsigned long hcdp_early_uart(void); + uart_base = hcdp_early_uart(); + } +# endif +# if CONFIG_IA64_EARLY_PRINTK_UART_BASE + if (!uart_base) + uart_base = CONFIG_IA64_EARLY_PRINTK_UART_BASE; +# endif + if (!uart_base) + return; + + uart = ioremap(uart_base, 64); + if (!uart) + return; + } + + while (len-- > 0) { + c = *str++; + while ((readb(uart + UART_LSR) & UART_LSR_TEMT) == 0) + cpu_relax(); /* spin */ + + writeb(c, uart + UART_TX); + + if (c == '\n') + writeb('\r', uart + UART_TX); + } +} + +# endif /* CONFIG_IA64_EARLY_PRINTK_UART */ + +#ifdef CONFIG_IA64_EARLY_PRINTK_SGI_SN +extern int early_printk_sn_sal(const char *str, int len); +#endif + +void early_printk(const char *str, size_t len) +{ +#ifdef CONFIG_IA64_EARLY_PRINTK_UART + early_printk_uart(str, len); +#endif +#ifdef CONFIG_IA64_EARLY_PRINTK_VGA + early_printk_vga(str, len); +#endif +#ifdef CONFIG_IA64_EARLY_PRINTK_SGI_SN + early_printk_sn_sal(str, len); +#endif +} + +#endif /* CONFIG_IA64_EARLY_PRINTK */