Changes since 2.4.24: * MCA/INIT/CMC/CPE: - add recovery for TLB MCAs (Tony Luck). - fix salinfo deadlock (Keith Owens). - avoid double clear of CMC/CPE records (Keith Owens, Ben Woodard). - avoid deadlock when using printk (Keith Owens). - delete all MCA/INIT/etc record printing code (moved to user space) (Keith Owens). - cleanup and synchronize mca.c with 2.6 (Keith Owens). - calculate irq_safe once (Keith Owens, Ben Woodard). - fix and refactor "did we recover from MCA" (Keith Owens). - check every 5 minutes for new MCA/INIT records (Keith Owens). - remove boot-time check for MCA/INIT records (Keith Owens). * IA32 emulation: - sigaltstack fix (Arun Sharma). * HP ZX1: - separate iommu page size from PAGE_SIZE (Alex Williamson, Bjorn Helgaas). - fix AGP 8X bridge support (Bjorn Helgaas). * Misc bug-fixes: - workaround menuconfig "HP-simulator" vs. "HP" bug (Bjorn Helgaas). - silently ignore zero-length descriptors in _CRS (Bjorn Helgaas). - fix ia64_ctx.lock deadlock (Jack Steiner). - hugepage_free_pgtable fix (Ken Chen). - pick up unwinder patch I missed (makes backtraces work again) (Bob Montgomery). - fix 'make mrproper' to remove offsets.h (Keith Owens). * Misc cleanup: - update copyrights in many ia64 .h files (David Mosberger). diff -u -Nur linux-2.4.25/Documentation/Configure.help linux-ia64-2.4/Documentation/Configure.help --- linux-2.4.25/Documentation/Configure.help 2004-02-18 09:52:41.000000000 -0700 +++ linux-ia64-2.4/Documentation/Configure.help 2004-02-18 09:51:41.000000000 -0700 @@ -18532,6 +18532,11 @@ purpose port, say Y here. See . +Support for serial ports defined in ACPI namespace +CONFIG_SERIAL_ACPI + If you wish to enable serial port discovery via the ACPI + namespace, say Y here. If unsure, say N. + Support for PowerMac serial ports CONFIG_MAC_SERIAL If you have Macintosh style serial ports (8 pin mini-DIN), say Y diff -u -Nur linux-2.4.25/Documentation/vm/hugetlbpage.txt linux-ia64-2.4/Documentation/vm/hugetlbpage.txt --- linux-2.4.25/Documentation/vm/hugetlbpage.txt 1969-12-31 17:00:00.000000000 -0700 +++ linux-ia64-2.4/Documentation/vm/hugetlbpage.txt 2004-02-18 09:51:24.000000000 -0700 @@ -0,0 +1,217 @@ + +The intent of this file is to give a brief summary of hugetlbpage support in +the Linux kernel. This support is built on top of multiple page size support +that is provided by most of modern architectures. For example, IA-32 +architecture supports 4K and 4M (2M in PAE mode) page sizes, IA-64 +architecture supports multiple page sizes 4K, 8K, 64K, 256K, 1M, 4M, 16M, +256M. A TLB is a cache of virtual-to-physical translations. Typically this +is a very scarce resource on processor. Operating systems try to make best +use of limited number of TLB resources. This optimization is more critical +now as bigger and bigger physical memories (several GBs) are more readily +available. + +Users can use the huge page support in Linux kernel by either using the mmap +system call or standard SYSv shared memory system calls (shmget, shmat). + +First the Linux kernel needs to be built with CONFIG_HUGETLB_PAGE (present +under Processor types and feature) and CONFIG_HUGETLBFS (present under file +system option on config menu) config options. + +The kernel built with hugepage support should show the number of configured +hugepages in the system by running the "cat /proc/meminfo" command. + +/proc/meminfo also provides information about the total number of hugetlb +pages configured in the kernel. It also displays information about the +number of free hugetlb pages at any time. It also displays information about +the configured hugepage size - this is needed for generating the proper +alignment and size of the arguments to the above system calls. + +The output of "cat /proc/meminfo" will have output like: + +..... +HugePages_Total: xxx +HugePages_Free: yyy +Hugepagesize: zzz KB + +/proc/filesystems should also show a filesystem of type "hugetlbfs" configured +in the kernel. + +/proc/sys/vm/nr_hugepages indicates the current number of configured hugetlb +pages in the kernel. Super user can dynamically request more (or free some +pre-configured) hugepages. +The allocation( or deallocation) of hugetlb pages is posible only if there are +enough physically contiguous free pages in system (freeing of hugepages is +possible only if there are enough hugetlb pages free that can be transfered +back to regular memory pool). + +Pages that are used as hugetlb pages are reserved inside the kernel and can +not be used for other purposes. + +Once the kernel with Hugetlb page support is built and running, a user can +use either the mmap system call or shared memory system calls to start using +the huge pages. It is required that the system administrator preallocate +enough memory for huge page purposes. + +Use the following command to dynamically allocate/deallocate hugepages: + + echo 20 > /proc/sys/vm/nr_hugepages + +This command will try to configure 20 hugepages in the system. The success +or failure of allocation depends on the amount of physically contiguous +memory that is preset in system at this time. System administrators may want +to put this command in one of the local rc init file. This will enable the +kernel to request huge pages early in the boot process (when the possibility +of getting physical contiguous pages is still very high). + +If the user applications are going to request hugepages using mmap system +call, then it is required that system administrator mount a file system of +type hugetlbfs: + + mount none /mnt/huge -t hugetlbfs + + +This command mounts a (pseudo) filesystem of type hugetlbfs on the directory +/mnt/huge. Any files created on /mnt/huge use hugepages. The uid and gid +options set the owner and group of the root of the file system. By default +the uid and gid of the current process are taken. The mode option sets the +mode of root of file system to value & 0777. This value is given in octal. +By default the value 0755 is picked. The size option sets the maximum value of +memory (huge pages) allowed for that filesystem (/mnt/huge). The size is +rounded down to HPAGE_SIZE. The option nr_inode sets the maximum number of +inodes that /mnt/huge can use. If the size or nr_inode options are not +provided on command line then no limits are set. For option size and option +nr_inodes, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For +example, size=2K has the same meaning as size=2048. An example is given at +the end of this document. + +read and write system calls are not supported on files that reside on hugetlb +file systems. + +Regular chown, chgrp and chmod commands can be used to change the file +attributes on hugetlbfs. + +Also, it is important to note that no such mount command is required if the +applications are going to use only shmat/shmget system calls. It is possible +for same or different applications to use any combination of mmaps and shm* +calls. Though the mount of filesystem will be required for using mmaps. + +/* Example of using hugepage in user application using Sys V shared memory + * system calls. In this example, app is requesting memory of size 256MB that + * is backed by huge pages. Application uses the flag SHM_HUGETLB in shmget + * system call to informt the kernel that it is requesting hugepages. For + * IA-64 architecture, Linux kernel reserves Region number 4 for hugepages. + * That means the addresses starting with 0x800000....will need to be + * specified. + */ +#include +#include +#include +#include + +extern int errno; +#define SHM_HUGETLB 04000 +#define LPAGE_SIZE (256UL*1024UL*1024UL) +#define dprintf(x) printf(x) +#define ADDR (0x8000000000000000UL) +main() +{ + int shmid; + int i, j, k; + volatile char *shmaddr; + + if ((shmid =shmget(2, LPAGE_SIZE, SHM_HUGETLB|IPC_CREAT|SHM_R|SHM_W )) +< 0) { + perror("Failure:"); + exit(1); + } + printf("shmid: 0x%x\n", shmid); + shmaddr = shmat(shmid, (void *)ADDR, SHM_RND) ; + if (errno != 0) { + perror("Shared Memory Attach Failure:"); + exit(2); + } + printf("shmaddr: %p\n", shmaddr); + + dprintf("Starting the writes:\n"); + for (i=0;i +#include +#include +#include + +#define FILE_NAME "/mnt/hugepagefile" +#define LENGTH (256*1024*1024) +#define PROTECTION (PROT_READ | PROT_WRITE) +#define FLAGS MAP_SHARED |MAP_FIXED +#define ADDRESS (char *)(0x60000000UL + 0x8000000000000000UL) + +extern errno; + +check_bytes(char *addr) +{ + printf("First hex is %x\n", *((unsigned int *)addr)); +} + +write_bytes(char *addr) +{ + int i; + for (i=0;i extern acpi_status acpi_hp_csr_space(acpi_handle, u64 *, u64 *); EXPORT_SYMBOL(acpi_hp_csr_space); +#endif diff -u -Nur linux-2.4.25/arch/ia64/kernel/mca.c linux-ia64-2.4/arch/ia64/kernel/mca.c --- linux-2.4.25/arch/ia64/kernel/mca.c 2004-02-18 09:52:31.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/kernel/mca.c 2004-02-18 09:51:23.000000000 -0700 @@ -6,7 +6,7 @@ * Copyright (C) 2003 Hewlett-Packard Co * David Mosberger-Tang * - * Copyright (C) 2002 Dell Computer Corporation + * Copyright (C) 2002 Dell Inc. * Copyright (C) Matt Domsch (Matt_Domsch@dell.com) * * Copyright (C) 2002 Intel @@ -18,7 +18,7 @@ * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2004 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * * 03/04/15 D. Mosberger Added INIT backtrace support. @@ -40,6 +40,14 @@ * 2003-12-08 Keith Owens * smp_call_function() must not be called from interrupt context (can * deadlock on tasklist_lock). Use keventd to call smp_call_function(). + * + * 2004-02-01 Keith Owens + * Avoid deadlock when using printk() for MCA and INIT records. + * Delete all record printing code, moved to salinfo_decode in user space. + * Mark variables and functions static where possible. + * Delete dead variables and functions. + * Reorder to remove the need for forward declarations and to consolidate + * related code. */ #include #include @@ -67,9 +75,12 @@ #include #include -#undef MCA_PRT_XTRA_DATA +#if defined(IA64_MCA_DEBUG_INFO) +# define IA64_MCA_DEBUG(fmt...) printk(fmt) +#else +# define IA64_MCA_DEBUG(fmt...) +#endif -#define print_symbol(fmt, addr) printk(fmt, "(no symbol)"); extern void show_stack(struct task_struct *); typedef struct ia64_fptr { @@ -77,7 +88,7 @@ unsigned long gp; } ia64_fptr_t; -ia64_mc_info_t ia64_mc_info; +/* Used by mca_asm.S */ ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state; ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state; u64 ia64_mca_proc_state_dump[512]; @@ -85,54 +96,17 @@ u64 ia64_mca_stackframe[32]; u64 ia64_mca_bspstore[1024]; u64 ia64_init_stack[INIT_TASK_SIZE/8] __attribute__((aligned(16))); -u64 ia64_os_mca_recovery_successful; u64 ia64_mca_serialize; -static void ia64_mca_wakeup_ipi_wait(void); -static void ia64_mca_wakeup(int cpu); -static void ia64_mca_wakeup_all(void); -static void ia64_log_init(int); + +/* In mca_asm.S */ extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); -static u64 ia64_log_get(int sal_info_type, u8 **buffer); -extern struct hw_interrupt_type irq_type_iosapic_level; - -struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; - -static struct irqaction cmci_irqaction = { - .handler = ia64_mca_cmc_int_handler, - .flags = SA_INTERRUPT, - .name = "cmc_hndlr" -}; - -static struct irqaction cmcp_irqaction = { - .handler = ia64_mca_cmc_int_caller, - .flags = SA_INTERRUPT, - .name = "cmc_poll" -}; - -static struct irqaction mca_rdzv_irqaction = { - .handler = ia64_mca_rendez_int_handler, - .flags = SA_INTERRUPT, - .name = "mca_rdzv" -}; -static struct irqaction mca_wkup_irqaction = { - .handler = ia64_mca_wakeup_int_handler, - .flags = SA_INTERRUPT, - .name = "mca_wkup" -}; +static ia64_mc_info_t ia64_mc_info; -static struct irqaction mca_cpe_irqaction = { - .handler = ia64_mca_cpe_int_handler, - .flags = SA_INTERRUPT, - .name = "cpe_hndlr" -}; +extern struct hw_interrupt_type irq_type_iosapic_level; -static struct irqaction mca_cpep_irqaction = { - .handler = ia64_mca_cpe_int_caller, - .flags = SA_INTERRUPT, - .name = "cpe_poll" -}; +struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ @@ -156,69 +130,163 @@ */ static int cpe_poll_enabled = 1; -extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size); +extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); static struct tq_struct cmc_disable_tq, cmc_enable_tq; /* + * IA64_MCA log support + */ +#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ +#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ + +typedef struct ia64_state_log_s +{ + spinlock_t isl_lock; + int isl_index; + unsigned long isl_count; + ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ +} ia64_state_log_t; + +static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; + +#define IA64_LOG_ALLOCATE(it, size) \ + {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size); \ + ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_bootmem(size);} +#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) +#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) +#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) +#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index +#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index +#define IA64_LOG_INDEX_INC(it) \ + {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \ + ia64_state_log[it].isl_count++;} +#define IA64_LOG_INDEX_DEC(it) \ + ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index +#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) +#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) +#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count + +/* + * ia64_log_init + * Reset the OS ia64 log buffer + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * Outputs : None + */ +static void +ia64_log_init(int sal_info_type) +{ + u64 max_size = 0; + + IA64_LOG_NEXT_INDEX(sal_info_type) = 0; + IA64_LOG_LOCK_INIT(sal_info_type); + + // SAL will tell us the maximum size of any error record of this type + max_size = ia64_sal_get_state_info_size(sal_info_type); + if (!max_size) + /* alloc_bootmem() doesn't like zero-sized allocations! */ + return; + + // set up OS data structures to hold error info + IA64_LOG_ALLOCATE(sal_info_type, max_size); + memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); + memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); +} + +/* + * ia64_log_get + * + * Get the current MCA log from SAL and copy it into the OS log buffer. + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * irq_safe whether you can use printk at this point + * Outputs : size (total record length) + * *buffer (ptr to error record) + * + */ +static u64 +ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe) +{ + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + + IA64_LOG_LOCK(sal_info_type); + + /* Get the process state information */ + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); + + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + + if (total_len) { + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + if (irq_safe) { + IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. " + "Record length = %ld\n", __FUNCTION__, sal_info_type, total_len); + } + *buffer = (u8 *) log_buffer; + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + return 0; + } +} + +/* * ia64_mca_log_sal_error_record * - * This function retrieves a specified error record type from SAL, - * wakes up any processes waiting for error records, and sends it to - * the system log. + * This function retrieves a specified error record type from SAL + * and wakes up any processes waiting for error records. * * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) - * Outputs : platform error status */ -int -ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init) +static void +ia64_mca_log_sal_error_record(int sal_info_type) { u8 *buffer; u64 size; - int platform_err; + int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT; + static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; - size = ia64_log_get(sal_info_type, &buffer); + size = ia64_log_get(sal_info_type, &buffer, irq_safe); if (!size) - return 0; + return; - /* TODO: - * 1. analyze error logs to determine recoverability - * 2. perform error recovery procedures, if applicable - * 3. set ia64_os_mca_recovery_successful flag, if applicable - */ + salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe); + + if (irq_safe) + printk(KERN_INFO "CPU %d: SAL log contains %s error record\n", + smp_processor_id(), + sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN"); - salinfo_log_wakeup(sal_info_type, buffer, size); - platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk); /* Clear logs from corrected errors in case there's no user-level logger */ if (sal_info_type == SAL_INFO_TYPE_CPE || sal_info_type == SAL_INFO_TYPE_CMC) ia64_sal_clear_state_info(sal_info_type); - - return platform_err; } /* * platform dependent error handling */ #ifndef PLATFORM_MCA_HANDLERS -void -mca_handler_platform (void) -{ - -} -void +static void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) { - IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n", - smp_processor_id(), cpe_irq); + IA64_MCA_DEBUG("%s: received interrupt. CPU:%d vector = %#x\n", + __FUNCTION__, smp_processor_id(), cpe_irq); /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); } +#define print_symbol(fmt, addr) printk(fmt, "(no symbol)"); + static void show_min_state (pal_min_state_area_t *minstate) { @@ -357,7 +425,7 @@ PUT_NAT_BIT(sw->caller_unat, &pt->r30); PUT_NAT_BIT(sw->caller_unat, &pt->r31); } -void +static void init_handler_platform (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) { @@ -404,45 +472,7 @@ while (1); /* hang city if no debugger */ } -/* - * ia64_mca_init_platform - * - * External entry for platform specific MCA initialization. - * - * Inputs - * None - * - * Outputs - * None - */ -void -ia64_mca_init_platform (void) -{ - -} - -/* - * ia64_mca_check_errors - * - * External entry to check for error records which may have been posted by SAL - * for a prior failure. - * - * Inputs : None - * - * Outputs : None - */ -int -ia64_mca_check_errors (void) -{ - /* - * If there is an MCA error record pending, get it and log it. - */ - printk("CPU %d: checking for saved MCA error records\n", smp_processor_id()); - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1); - - return 0; -} - +#ifdef CONFIG_ACPI /* * ia64_mca_register_cpev * @@ -462,14 +492,15 @@ isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0); if (isrv.status) { - printk(KERN_ERR "ia64_mca_platform_init: failed to register Corrected " - "Platform Error interrupt vector with SAL.\n"); + printk(KERN_ERR "Failed to register Corrected Platform " + "Error interrupt vector with SAL (status %ld)\n", isrv.status); return; } - IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error " - "vector %#x setup and enabled\n", cpev); + IA64_MCA_DEBUG("%s: corrected platform error " + "vector %#x setup and enabled\n", __FUNCTION__, cpev); } +#endif /* CONFIG_ACPI */ #endif /* PLATFORM_MCA_HANDLERS */ @@ -495,12 +526,12 @@ cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x setup and enabled.\n", - smp_processor_id(), IA64_CMC_VECTOR); + __FUNCTION__, smp_processor_id(), IA64_CMC_VECTOR); - IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n", - smp_processor_id(), ia64_get_cmcv()); + IA64_MCA_DEBUG("%s: CPU %d CMCV = %#016lx\n", + __FUNCTION__, smp_processor_id(), ia64_get_cmcv()); } /* @@ -515,7 +546,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_vector_disable (void *dummy) { cmcv_reg_t cmcv; @@ -525,9 +556,9 @@ cmcv.cmcv_mask = 1; /* Mask/disable interrupt */ ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_cmc_vector_disable: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x disabled.\n", - smp_processor_id(), cmcv.cmcv_vector); + __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } /* @@ -542,7 +573,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_vector_enable (void *dummy) { cmcv_reg_t cmcv; @@ -552,63 +583,9 @@ cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ ia64_set_cmcv(cmcv.cmcv_regval); - IA64_MCA_DEBUG("ia64_mca_cmc_vector_enable: CPU %d corrected " + IA64_MCA_DEBUG("%s: CPU %d corrected " "machine check vector %#x enabled.\n", - smp_processor_id(), cmcv.cmcv_vector); -} - - -#if defined(MCA_TEST) - -sal_log_processor_info_t slpi_buf; - -void -mca_test(void) -{ - slpi_buf.valid.psi_static_struct = 1; - slpi_buf.valid.num_cache_check = 1; - slpi_buf.valid.num_tlb_check = 1; - slpi_buf.valid.num_bus_check = 1; - slpi_buf.valid.processor_static_info.minstate = 1; - slpi_buf.valid.processor_static_info.br = 1; - slpi_buf.valid.processor_static_info.cr = 1; - slpi_buf.valid.processor_static_info.ar = 1; - slpi_buf.valid.processor_static_info.rr = 1; - slpi_buf.valid.processor_static_info.fr = 1; - - ia64_os_mca_dispatch(); -} - -#endif /* #if defined(MCA_TEST) */ - - -/* - * verify_guid - * - * Compares a test guid to a target guid and returns result. - * - * Inputs - * test_guid * (ptr to guid to be verified) - * target_guid * (ptr to standard guid to be verified against) - * - * Outputs - * 0 (test verifies against target) - * non-zero (test guid does not verify) - */ -static int -verify_guid (efi_guid_t *test, efi_guid_t *target) -{ - int rc; -#ifdef IA64_MCA_DEBUG_INFO - char out[40]; -#endif - - if ((rc = efi_guidcmp(*test, *target))) { - IA64_MCA_DEBUG(KERN_DEBUG - "verify_guid: invalid GUID = %s\n", - efi_guid_unparse(test, out)); - } - return rc; + __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } /* @@ -642,225 +619,39 @@ } /* - * ia64_mca_init - * - * Do all the system level mca specific initialization. - * - * 1. Register spinloop and wakeup request interrupt vectors - * - * 2. Register OS_MCA handler entry point - * - * 3. Register OS_INIT handler entry point - * - * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. + * ia64_mca_wakeup_ipi_wait * - * Note that this initialization is done very early before some kernel - * services are available. + * Wait for the inter-cpu interrupt to be sent by the + * monarch processor once it is done with handling the + * MCA. * * Inputs : None - * * Outputs : None */ -void __init -ia64_mca_init(void) +static void +ia64_mca_wakeup_ipi_wait(void) { - ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; - ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; - ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; - int i; - s64 rc; - struct ia64_sal_retval isrv; - u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ + int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); + int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); + u64 irr = 0; - IA64_MCA_DEBUG("ia64_mca_init: begin\n"); - - INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL); - INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL); - - /* initialize recovery success indicator */ - ia64_os_mca_recovery_successful = 0; - - /* Clear the Rendez checkin flag for all cpus */ - for(i = 0 ; i < NR_CPUS; i++) - ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - - /* - * Register the rendezvous spinloop and wakeup mechanism with SAL - */ - - /* Register the rendezvous interrupt vector with SAL */ - while (1) { - isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_RENDEZ_VECTOR, - timeout, - SAL_MC_PARAM_RZ_ALWAYS); - rc = isrv.status; - if (rc == 0) - break; - if (rc == -2) { - printk(KERN_INFO "ia64_mca_init: increasing MCA rendezvous timeout from " - "%ld to %ld\n", timeout, isrv.v0); - timeout = isrv.v0; - continue; - } - printk(KERN_ERR "ia64_mca_init: Failed to register rendezvous interrupt " - "with SAL. rc = %ld\n", rc); - return; - } - - /* Register the wakeup interrupt vector with SAL */ - isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, - SAL_MC_PARAM_MECHANISM_INT, - IA64_MCA_WAKEUP_VECTOR, - 0, 0); - rc = isrv.status; - if (rc) { - printk(KERN_ERR "ia64_mca_init: Failed to register wakeup interrupt with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - - ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); - /* - * XXX - disable SAL checksum by setting size to 0; should be - * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); - */ - ia64_mc_info.imi_mca_handler_size = 0; - - /* Register the os mca handler with SAL */ - if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, - ia64_mc_info.imi_mca_handler, - ia64_tpa(mca_hldlr_ptr->gp), - ia64_mc_info.imi_mca_handler_size, - 0, 0, 0))) - { - printk(KERN_ERR "ia64_mca_init: Failed to register os mca handler with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", - ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); - - /* - * XXX - disable SAL checksum by setting size to 0, should be - * IA64_INIT_HANDLER_SIZE - */ - ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); - ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); - ia64_mc_info.imi_slave_init_handler_size = 0; - - IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", - ia64_mc_info.imi_monarch_init_handler); - - /* Register the os init handler with SAL */ - if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, - ia64_mc_info.imi_monarch_init_handler, - ia64_tpa(ia64_get_gp()), - ia64_mc_info.imi_monarch_init_handler_size, - ia64_mc_info.imi_slave_init_handler, - ia64_tpa(ia64_get_gp()), - ia64_mc_info.imi_slave_init_handler_size))) - { - printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. " - "rc = %ld\n", rc); - return; - } - - IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n"); - - /* - * Configure the CMCI/P vector and handler. Interrupts for CMC are - * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). - */ - register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); - register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction); - ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ - - /* Setup the MCA rendezvous interrupt vector */ - register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); - - /* Setup the MCA wakeup interrupt vector */ - register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); - - /* Setup the CPE interrupt vector */ - { - irq_desc_t *desc; - unsigned int irq; - int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); - - if (cpev >= 0) { - for (irq = 0; irq < NR_IRQS; ++irq) - if (irq_to_vector(irq) == cpev) { - desc = irq_desc(irq); - desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_iosapic_level; - setup_irq(irq, &mca_cpe_irqaction); - } - ia64_mca_register_cpev(cpev); - } - } - - /* Initialize the areas set aside by the OS to buffer the - * platform/processor error states for MCA/INIT/CMC - * handling. - */ - ia64_log_init(SAL_INFO_TYPE_MCA); - ia64_log_init(SAL_INFO_TYPE_INIT); - ia64_log_init(SAL_INFO_TYPE_CMC); - ia64_log_init(SAL_INFO_TYPE_CPE); - -#if defined(MCA_TEST) - mca_test(); -#endif /* #if defined(MCA_TEST) */ - - printk(KERN_INFO "Mca related initialization done\n"); - - /* commented out because this is done elsewhere */ -#if 0 - /* Do post-failure MCA error logging */ - ia64_mca_check_errors(); -#endif -} - -/* - * ia64_mca_wakeup_ipi_wait - * - * Wait for the inter-cpu interrupt to be sent by the - * monarch processor once it is done with handling the - * MCA. - * - * Inputs : None - * Outputs : None - */ -void -ia64_mca_wakeup_ipi_wait(void) -{ - int irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6); - int irr_bit = (IA64_MCA_WAKEUP_VECTOR & 0x3f); - u64 irr = 0; - - do { - switch(irr_num) { - case 0: - irr = ia64_get_irr0(); - break; - case 1: - irr = ia64_get_irr1(); - break; - case 2: - irr = ia64_get_irr2(); - break; - case 3: - irr = ia64_get_irr3(); - break; - } - } while (!(irr & (1UL << irr_bit))) ; -} + do { + switch(irr_num) { + case 0: + irr = ia64_get_irr0(); + break; + case 1: + irr = ia64_get_irr1(); + break; + case 2: + irr = ia64_get_irr2(); + break; + case 3: + irr = ia64_get_irr3(); + break; + } + } while (!(irr & (1UL << irr_bit))) ; +} /* * ia64_mca_wakeup @@ -871,7 +662,7 @@ * Inputs : cpuid * Outputs : None */ -void +static void ia64_mca_wakeup(int cpu) { platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0); @@ -887,7 +678,7 @@ * Inputs : None * Outputs : None */ -void +static void ia64_mca_wakeup_all(void) { int cpu; @@ -912,7 +703,7 @@ * Inputs : None * Outputs : None */ -void +static void ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs) { unsigned long flags; @@ -937,7 +728,6 @@ local_irq_restore(flags); } - /* * ia64_mca_wakeup_int_handler * @@ -953,7 +743,7 @@ * Outputs : None * */ -void +static void ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) { } @@ -972,11 +762,9 @@ * Outputs : None */ -void -ia64_return_to_sal_check(void) +static void +ia64_return_to_sal_check(int recover) { - pal_processor_state_info_t *psp = (pal_processor_state_info_t *) - &ia64_sal_to_os_handoff_state.proc_state_param; /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff @@ -987,15 +775,10 @@ ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - /* - * Did we correct the error? At the moment the only error that - * we fix is a TLB error, if any other kind of error occurred - * we must reboot. - */ - if (psp->cc == 1 && psp->bc == 1 && psp->rc == 1 && psp->uc == 1) - ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; - else + if (recover) ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; + else + ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; /* Default = tell SAL to return to same context */ ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; @@ -1024,16 +807,12 @@ void ia64_mca_ucmc_handler(void) { - int platform_err = 0; + pal_processor_state_info_t *psp = (pal_processor_state_info_t *) + &ia64_sal_to_os_handoff_state.proc_state_param; + int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc); /* Get the MCA error record and log it */ - platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0); - - /* - * Do Platform-specific mca error handling if required. - */ - if (platform_err) - mca_handler_platform(); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); /* * Wakeup all the processors which are spinning in the rendezvous @@ -1042,7 +821,7 @@ ia64_mca_wakeup_all(); /* Return to SAL */ - ia64_return_to_sal_check(); + ia64_return_to_sal_check(recover); } /* @@ -1060,21 +839,21 @@ * Outputs * None */ -void +static void ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) { static unsigned long cmc_history[CMC_HISTORY_LENGTH]; static int index; static spinlock_t cmc_history_lock = SPIN_LOCK_UNLOCKED; - IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n", - cmc_irq, smp_processor_id()); + IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n", + __FUNCTION__, cmc_irq, smp_processor_id()); /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); /* Get the CMC error record and log it */ - ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0); + ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); spin_lock(&cmc_history_lock); if (!cmc_polling_enabled) { @@ -1098,7 +877,7 @@ * make sure there's a log somewhere that indicates * something is generating more than we can handle. */ - printk(KERN_WARNING "%s: WARNING: Switching to polling CMC handler, error records may be lost\n", __FUNCTION__); + printk(KERN_WARNING "WARNING: Switching to polling CMC handler; error records may be lost\n"); mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL); @@ -1114,41 +893,6 @@ } /* - * IA64_MCA log support - */ -#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */ -#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */ - -typedef struct ia64_state_log_s -{ - spinlock_t isl_lock; - int isl_index; - unsigned long isl_count; - ia64_err_rec_t *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */ -} ia64_state_log_t; - -static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; - -#define IA64_LOG_ALLOCATE(it, size) \ - {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ - (ia64_err_rec_t *)alloc_bootmem(size); \ - ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ - (ia64_err_rec_t *)alloc_bootmem(size);} -#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) -#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) -#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) -#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index -#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index -#define IA64_LOG_INDEX_INC(it) \ - {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \ - ia64_state_log[it].isl_count++;} -#define IA64_LOG_INDEX_DEC(it) \ - ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index -#define IA64_LOG_NEXT_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)])) -#define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) -#define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count - -/* * ia64_mca_cmc_int_caller * * Triggered by sw interrupt from CMC polling routine. Calls @@ -1162,7 +906,7 @@ * Outputs * None */ -void +static void ia64_mca_cmc_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; @@ -1177,14 +921,14 @@ ia64_mca_cmc_int_handler(cpe_irq, arg, ptregs); for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); - + if (cpuid < NR_CPUS) { platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); } else { - /* If no log recored, switch out of polling mode */ + /* If no log record, switch out of polling mode */ if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { - printk(KERN_WARNING "%s: Returning to interrupt driven CMC handler\n", __FUNCTION__); + printk(KERN_WARNING "Returning to interrupt driven CMC handler\n"); schedule_task(&cmc_enable_tq); cmc_polling_enabled = 0; @@ -1227,7 +971,7 @@ * Outputs * None */ -void +static void ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; @@ -1279,57 +1023,26 @@ } /* - * ia64_mca_late_init + * C portion of the OS INIT handler * - * Opportunity to setup things that require initialization later - * than ia64_mca_init. Setup a timer to poll for CPEs if the - * platform doesn't support an interrupt driven mechanism. + * Called from ia64_monarch_init_handler + * + * Inputs: pointer to pt_regs where processor info was saved. + * + * Returns: + * 0 if SAL must warm boot the System + * 1 if SAL must return to interrupted context using PAL_MC_RESUME * - * Inputs : None - * Outputs : Status */ -static int __init -ia64_mca_late_init(void) +void +ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) { - init_timer(&cmc_poll_timer); - cmc_poll_timer.function = ia64_mca_cmc_poll; + pal_min_state_area_t *ms; - /* Reset to the correct state */ - cmc_polling_enabled = 0; + oops_in_progress = 1; /* avoid deadlock in printk, but it makes recovery dodgy */ - init_timer(&cpe_poll_timer); - cpe_poll_timer.function = ia64_mca_cpe_poll; - - /* 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); - ia64_mca_cpe_poll(0UL); - } - - return 0; -} - -module_init(ia64_mca_late_init); - -/* - * C portion of the OS INIT handler - * - * Called from ia64_monarch_init_handler - * - * Inputs: pointer to pt_regs where processor info was saved. - * - * Returns: - * 0 if SAL must warm boot the System - * 1 if SAL must return to interrupted context using PAL_MC_RESUME - * - */ -void -ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) -{ - pal_min_state_area_t *ms; - - printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", - ia64_sal_to_os_handoff_state.proc_state_param); + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", + ia64_sal_to_os_handoff_state.proc_state_param); /* * Address of minstate area provided by PAL is physical, @@ -1341,1080 +1054,259 @@ init_handler_platform(ms, pt, sw); /* call platform specific routines */ } -/* - * ia64_log_prt_guid - * - * Print a formatted GUID. - * - * Inputs : p_guid (ptr to the GUID) - * prfunc (print function) - * Outputs : None - * - */ -void -ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc) -{ - char out[40]; - printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out)); -} - -static void -ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc) +static int __init +ia64_mca_disable_cpe_polling(char *str) { - unsigned long i; - int j; - - if (!p) - return; - - for (i = 0; i < n_ch;) { - prfunc("%p ", (void *)p); - for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) { - prfunc("%02x ", *p); - } - prfunc("\n"); - } + cpe_poll_enabled = 0; + return 1; } -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL +__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); -static void -ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc) -{ - prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n", - (void *)rh, sizeof(sal_log_record_header_t)); - ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t), - (prfunc_t)prfunc); - prfunc("Total record length = %d\n", rh->len); - ia64_log_prt_guid(&rh->platform_guid, prfunc); - prfunc("End of SAL RECORD HEADER\n"); -} +static struct irqaction cmci_irqaction = { + .handler = ia64_mca_cmc_int_handler, + .flags = SA_INTERRUPT, + .name = "cmc_hndlr" +}; -static void -ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc) -{ - prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n", - (void *)sh, sizeof(sal_log_section_hdr_t)); - ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t), - (prfunc_t)prfunc); - prfunc("Length of section & header = %d\n", sh->len); - ia64_log_prt_guid(&sh->guid, prfunc); - prfunc("End of SAL SECTION HEADER\n"); -} -#endif // MCA_PRT_XTRA_DATA for test only @FVL +static struct irqaction cmcp_irqaction = { + .handler = ia64_mca_cmc_int_caller, + .flags = SA_INTERRUPT, + .name = "cmc_poll" +}; -/* - * ia64_log_init - * Reset the OS ia64 log buffer - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * Outputs : None - */ -void -ia64_log_init(int sal_info_type) -{ - u64 max_size = 0; +static struct irqaction mca_rdzv_irqaction = { + .handler = ia64_mca_rendez_int_handler, + .flags = SA_INTERRUPT, + .name = "mca_rdzv" +}; - IA64_LOG_NEXT_INDEX(sal_info_type) = 0; - IA64_LOG_LOCK_INIT(sal_info_type); +static struct irqaction mca_wkup_irqaction = { + .handler = ia64_mca_wakeup_int_handler, + .flags = SA_INTERRUPT, + .name = "mca_wkup" +}; - // SAL will tell us the maximum size of any error record of this type - max_size = ia64_sal_get_state_info_size(sal_info_type); +#ifdef CONFIG_ACPI +static struct irqaction mca_cpe_irqaction = { + .handler = ia64_mca_cpe_int_handler, + .flags = SA_INTERRUPT, + .name = "cpe_hndlr" +}; - // set up OS data structures to hold error info - IA64_LOG_ALLOCATE(sal_info_type, max_size); - memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); - memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); -} +static struct irqaction mca_cpep_irqaction = { + .handler = ia64_mca_cpe_int_caller, + .flags = SA_INTERRUPT, + .name = "cpe_poll" +}; +#endif /* CONFIG_ACPI */ /* - * ia64_log_get + * ia64_mca_init * - * Get the current MCA log from SAL and copy it into the OS log buffer. + * Do all the system level mca specific initialization. * - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * Outputs : size (total record length) - * *buffer (ptr to error record) + * 1. Register spinloop and wakeup request interrupt vectors * - */ -u64 -ia64_log_get(int sal_info_type, u8 **buffer) -{ - sal_log_record_header_t *log_buffer; - u64 total_len = 0; - int s; - - IA64_LOG_LOCK(sal_info_type); - - /* Get the process state information */ - log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); - - total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); - - if (total_len) { - IA64_LOG_INDEX_INC(sal_info_type); - IA64_LOG_UNLOCK(sal_info_type); - IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. " - "Record length = %ld\n", sal_info_type, total_len); - *buffer = (u8 *) log_buffer; - return total_len; - } else { - IA64_LOG_UNLOCK(sal_info_type); - return 0; - } -} - -/* - * ia64_log_prt_oem_data + * 2. Register OS_MCA handler entry point * - * Print OEM specific data if included. + * 3. Register OS_INIT handler entry point * - * Inputs : header_len (length passed in section header) - * sect_len (default length of section type) - * p_data (ptr to data) - * prfunc (print function) - * Outputs : None + * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * - */ -void -ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) -{ - int oem_data_len, i; - - if ((oem_data_len = header_len - sect_len) > 0) { - prfunc(" OEM Specific Data:"); - for (i = 0; i < oem_data_len; i++, p_data++) - prfunc(" %02x", *p_data); - } - prfunc("\n"); -} - -/* - * ia64_log_rec_header_print + * Note that this initialization is done very early before some kernel + * services are available. * - * Log info from the SAL error record header. + * Inputs : None * - * Inputs : lh * (ptr to SAL log error record header) - * prfunc (fn ptr of log output function to use) * Outputs : None */ -void -ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc) -{ - prfunc("+Err Record ID: %ld SAL Rev: %2x.%02x\n", lh->id, - lh->revision.major, lh->revision.minor); - prfunc("+Time: %02x/%02x/%02x%02x %02x:%02x:%02x Severity %d\n", - lh->timestamp.slh_month, lh->timestamp.slh_day, - lh->timestamp.slh_century, lh->timestamp.slh_year, - lh->timestamp.slh_hour, lh->timestamp.slh_minute, - lh->timestamp.slh_second, lh->severity); -} - -/* - * ia64_log_processor_regs_print - * Print the contents of the saved processor register(s) in the format - * [] - * - * Inputs : regs (Register save buffer) - * reg_num (# of registers) - * reg_class (application/banked/control/bank1_general) - * reg_prefix (ar/br/cr/b1_gr) - * Outputs : None - * - */ -void -ia64_log_processor_regs_print(u64 *regs, - int reg_num, - char *reg_class, - char *reg_prefix, - prfunc_t prfunc) -{ - int i; - - prfunc("+%s Registers\n", reg_class); - for (i = 0; i < reg_num; i++) - prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]); -} - -/* - * ia64_log_processor_fp_regs_print - * Print the contents of the saved floating page register(s) in the format - * [] - * - * Inputs: ia64_fpreg (Register save buffer) - * reg_num (# of registers) - * reg_class (application/banked/control/bank1_general) - * reg_prefix (ar/br/cr/b1_gr) - * Outputs: None - * - */ -void -ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs, - int reg_num, - char *reg_class, - char *reg_prefix, - prfunc_t prfunc) +void __init +ia64_mca_init(void) { + ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; + ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; + ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; + s64 rc; + struct ia64_sal_retval isrv; + u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ - prfunc("+%s Registers\n", reg_class); - for (i = 0; i < reg_num; i++) - prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1], - regs[i].u.bits[0]); -} - -static char *pal_mesi_state[] = { - "Invalid", - "Shared", - "Exclusive", - "Modified", - "Reserved1", - "Reserved2", - "Reserved3", - "Reserved4" -}; - -static char *pal_cache_op[] = { - "Unknown", - "Move in", - "Cast out", - "Coherency check", - "Internal", - "Instruction fetch", - "Implicit Writeback", - "Reserved" -}; - -/* - * ia64_log_cache_check_info_print - * Display the machine check information related to cache error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * cc_info * (Ptr to cache check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_cache_check_info_print (int i, - sal_log_mod_error_info_t *cache_check_info, - prfunc_t prfunc) -{ - pal_cache_check_info_t *info; - u64 target_addr; - - if (!cache_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i); - return; /* If check info data not valid, skip it */ - } - - info = (pal_cache_check_info_t *)&cache_check_info->check_info; - target_addr = cache_check_info->target_identifier; - - prfunc("+ Cache check info[%d]\n+", i); - prfunc(" Level: L%d,",info->level); - if (info->mv) - prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]); - prfunc(" Index: %d,", info->index); - if (info->ic) - prfunc(" Cache: Instruction,"); - if (info->dc) - prfunc(" Cache: Data,"); - if (info->tl) - prfunc(" Line: Tag,"); - if (info->dl) - prfunc(" Line: Data,"); - prfunc(" Operation: %s,", pal_cache_op[info->op]); - if (info->wiv) - prfunc(" Way: %d,", info->way); - if (cache_check_info->valid.target_identifier) - /* Hope target address is saved in target_identifier */ - if (info->tv) - prfunc(" Target Addr: 0x%lx,", target_addr); - if (info->mcc) - prfunc(" MC: Corrected"); - prfunc("\n"); -} - -/* - * ia64_log_tlb_check_info_print - * Display the machine check information related to tlb error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * tlb_info * (Ptr to machine check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_tlb_check_info_print (int i, - sal_log_mod_error_info_t *tlb_check_info, - prfunc_t prfunc) - -{ - pal_tlb_check_info_t *info; - - if (!tlb_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i); - return; /* If check info data not valid, skip it */ - } - - info = (pal_tlb_check_info_t *)&tlb_check_info->check_info; - - prfunc("+ TLB Check Info [%d]\n+", i); - if (info->itc) - prfunc(" Failure: Instruction Translation Cache"); - if (info->dtc) - prfunc(" Failure: Data Translation Cache"); - if (info->itr) { - prfunc(" Failure: Instruction Translation Register"); - prfunc(" ,Slot: %ld", info->tr_slot); - } - if (info->dtr) { - prfunc(" Failure: Data Translation Register"); - prfunc(" ,Slot: %ld", info->tr_slot); - } - if (info->mcc) - prfunc(" ,MC: Corrected"); - prfunc("\n"); -} - -/* - * ia64_log_bus_check_info_print - * Display the machine check information related to bus error(s). - * Inputs: i (Multiple errors are logged, i - index of logged error) - * bus_info * (Ptr to machine check info logged by the PAL and later - * captured by the SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_bus_check_info_print (int i, - sal_log_mod_error_info_t *bus_check_info, - prfunc_t prfunc) -{ - pal_bus_check_info_t *info; - u64 req_addr; /* Address of the requestor of the transaction */ - u64 resp_addr; /* Address of the responder of the transaction */ - u64 targ_addr; /* Address where the data was to be delivered to */ - /* or obtained from */ - - if (!bus_check_info->valid.check_info) { - IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i); - return; /* If check info data not valid, skip it */ - } + IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); - info = (pal_bus_check_info_t *)&bus_check_info->check_info; - req_addr = bus_check_info->requestor_identifier; - resp_addr = bus_check_info->responder_identifier; - targ_addr = bus_check_info->target_identifier; - - prfunc("+ BUS Check Info [%d]\n+", i); - prfunc(" Status Info: %d", info->bsi); - prfunc(" ,Severity: %d", info->sev); - prfunc(" ,Transaction Type: %d", info->type); - prfunc(" ,Transaction Size: %d", info->size); - if (info->cc) - prfunc(" ,Cache-cache-transfer"); - if (info->ib) - prfunc(" ,Error: Internal"); - if (info->eb) - prfunc(" ,Error: External"); - if (info->mcc) - prfunc(" ,MC: Corrected"); - if (info->tv) - prfunc(" ,Target Address: 0x%lx", targ_addr); - if (info->rq) - prfunc(" ,Requestor Address: 0x%lx", req_addr); - if (info->tv) - prfunc(" ,Responder Address: 0x%lx", resp_addr); - prfunc("\n"); -} + INIT_TQUEUE(&cmc_disable_tq, ia64_mca_cmc_vector_disable_keventd, NULL); + INIT_TQUEUE(&cmc_enable_tq, ia64_mca_cmc_vector_enable_keventd, NULL); -/* - * ia64_log_mem_dev_err_info_print - * - * Format and log the platform memory device error record section data. - * - * Inputs: mem_dev_err_info * (Ptr to memory device error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei, - prfunc_t prfunc) -{ - prfunc("+ Mem Error Detail: "); + /* Clear the Rendez checkin flag for all cpus */ + for(i = 0 ; i < NR_CPUS; i++) + ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; - if (mdei->valid.error_status) - prfunc(" Error Status: %#lx,", mdei->error_status); - if (mdei->valid.physical_addr) - prfunc(" Physical Address: %#lx,", mdei->physical_addr); - if (mdei->valid.addr_mask) - prfunc(" Address Mask: %#lx,", mdei->addr_mask); - if (mdei->valid.node) - prfunc(" Node: %d,", mdei->node); - if (mdei->valid.card) - prfunc(" Card: %d,", mdei->card); - if (mdei->valid.module) - prfunc(" Module: %d,", mdei->module); - if (mdei->valid.bank) - prfunc(" Bank: %d,", mdei->bank); - if (mdei->valid.device) - prfunc(" Device: %d,", mdei->device); - if (mdei->valid.row) - prfunc(" Row: %d,", mdei->row); - if (mdei->valid.column) - prfunc(" Column: %d,", mdei->column); - if (mdei->valid.bit_position) - prfunc(" Bit Position: %d,", mdei->bit_position); - if (mdei->valid.target_id) - prfunc(" ,Target Address: %#lx,", mdei->target_id); - if (mdei->valid.requestor_id) - prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id); - if (mdei->valid.responder_id) - prfunc(" ,Responder Address: %#lx,", mdei->responder_id); - if (mdei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data); - prfunc("\n"); - - if (mdei->valid.oem_id) { - u8 *p_data = &(mdei->oem_id[0]); - int i; - - prfunc(" OEM Memory Controller ID:"); - for (i = 0; i < 16; i++, p_data++) - prfunc(" %02x", *p_data); - prfunc("\n"); - } + /* + * Register the rendezvous spinloop and wakeup mechanism with SAL + */ - if (mdei->valid.oem_data) { - platform_mem_dev_err_print((int)mdei->header.len, - (int)sizeof(sal_log_mem_dev_err_info_t) - 1, - &(mdei->oem_data[0]), prfunc); + /* Register the rendezvous interrupt vector with SAL */ + while (1) { + isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_RENDEZ_VECTOR, + timeout, + SAL_MC_PARAM_RZ_ALWAYS); + rc = isrv.status; + if (rc == 0) + break; + if (rc == -2) { + printk(KERN_INFO "Increasing MCA rendezvous timeout from " + "%ld to %ld milliseconds\n", timeout, isrv.v0); + timeout = isrv.v0; + continue; + } + printk(KERN_ERR "Failed to register rendezvous interrupt " + "with SAL (status %ld)\n", rc); + return; } -} -/* - * ia64_log_sel_dev_err_info_print - * - * Format and log the platform SEL device error record section data. - * - * Inputs: sel_dev_err_info * (Ptr to the SEL device error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei, - prfunc_t prfunc) -{ - int i; - - prfunc("+ SEL Device Error Detail: "); - - if (sdei->valid.record_id) - prfunc(" Record ID: %#x", sdei->record_id); - if (sdei->valid.record_type) - prfunc(" Record Type: %#x", sdei->record_type); - prfunc(" Time Stamp: "); - for (i = 0; i < 4; i++) - prfunc("%1d", sdei->timestamp[i]); - if (sdei->valid.generator_id) - prfunc(" Generator ID: %#x", sdei->generator_id); - if (sdei->valid.evm_rev) - prfunc(" Message Format Version: %#x", sdei->evm_rev); - if (sdei->valid.sensor_type) - prfunc(" Sensor Type: %#x", sdei->sensor_type); - if (sdei->valid.sensor_num) - prfunc(" Sensor Number: %#x", sdei->sensor_num); - if (sdei->valid.event_dir) - prfunc(" Event Direction Type: %#x", sdei->event_dir); - if (sdei->valid.event_data1) - prfunc(" Data1: %#x", sdei->event_data1); - if (sdei->valid.event_data2) - prfunc(" Data2: %#x", sdei->event_data2); - if (sdei->valid.event_data3) - prfunc(" Data3: %#x", sdei->event_data3); - prfunc("\n"); - -} - -/* - * ia64_log_pci_bus_err_info_print - * - * Format and log the platform PCI bus error record section data. - * - * Inputs: pci_bus_err_info * (Ptr to the PCI bus error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei, - prfunc_t prfunc) -{ - prfunc("+ PCI Bus Error Detail: "); - - if (pbei->valid.err_status) - prfunc(" Error Status: %#lx", pbei->err_status); - if (pbei->valid.err_type) - prfunc(" Error Type: %#x", pbei->err_type); - if (pbei->valid.bus_id) - prfunc(" Bus ID: %#x", pbei->bus_id); - if (pbei->valid.bus_address) - prfunc(" Bus Address: %#lx", pbei->bus_address); - if (pbei->valid.bus_data) - prfunc(" Bus Data: %#lx", pbei->bus_data); - if (pbei->valid.bus_cmd) - prfunc(" Bus Command: %#lx", pbei->bus_cmd); - if (pbei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", pbei->requestor_id); - if (pbei->valid.responder_id) - prfunc(" Responder ID: %#lx", pbei->responder_id); - if (pbei->valid.target_id) - prfunc(" Target ID: %#lx", pbei->target_id); - if (pbei->valid.oem_data) - prfunc("\n"); - - if (pbei->valid.oem_data) { - platform_pci_bus_err_print((int)pbei->header.len, - (int)sizeof(sal_log_pci_bus_err_info_t) - 1, - &(pbei->oem_data[0]), prfunc); + /* Register the wakeup interrupt vector with SAL */ + isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, + SAL_MC_PARAM_MECHANISM_INT, + IA64_MCA_WAKEUP_VECTOR, + 0, 0); + rc = isrv.status; + if (rc) { + printk(KERN_ERR "Failed to register wakeup interrupt with SAL " + "(status %ld)\n", rc); + return; } -} -/* - * ia64_log_smbios_dev_err_info_print - * - * Format and log the platform SMBIOS device error record section data. - * - * Inputs: smbios_dev_err_info * (Ptr to the SMBIOS device error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei, - prfunc_t prfunc) -{ - u8 i; + IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__); - prfunc("+ SMBIOS Device Error Detail: "); - - if (sdei->valid.event_type) - prfunc(" Event Type: %#x", sdei->event_type); - if (sdei->valid.time_stamp) { - prfunc(" Time Stamp: "); - for (i = 0; i < 6; i++) - prfunc("%d", sdei->time_stamp[i]); - } - if ((sdei->valid.data) && (sdei->valid.length)) { - prfunc(" Data: "); - for (i = 0; i < sdei->length; i++) - prfunc(" %02x", sdei->data[i]); - } - prfunc("\n"); -} + ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); + /* + * XXX - disable SAL checksum by setting size to 0; should be + * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); + */ + ia64_mc_info.imi_mca_handler_size = 0; -/* - * ia64_log_pci_comp_err_info_print - * - * Format and log the platform PCI component error record section data. - * - * Inputs: pci_comp_err_info * (Ptr to the PCI component error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei, - prfunc_t prfunc) -{ - u32 n_mem_regs, n_io_regs; - u64 i, n_pci_data; - u64 *p_reg_data; - u8 *p_oem_data; - - prfunc("+ PCI Component Error Detail: "); - - if (pcei->valid.err_status) - prfunc(" Error Status: %#lx\n", pcei->err_status); - if (pcei->valid.comp_info) - prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x," - " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n", - pcei->comp_info.vendor_id, pcei->comp_info.device_id, - pcei->comp_info.class_code, pcei->comp_info.seg_num, - pcei->comp_info.bus_num, pcei->comp_info.dev_num, - pcei->comp_info.func_num); - - n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0; - n_io_regs = (pcei->valid.num_io_regs) ? pcei->num_io_regs : 0; - p_reg_data = &(pcei->reg_data_pairs[0]); - p_oem_data = (u8 *)p_reg_data + - (n_mem_regs + n_io_regs) * 2 * sizeof(u64); - n_pci_data = p_oem_data - (u8 *)pcei; - - if (n_pci_data > pcei->header.len) { - prfunc(" Invalid PCI Component Error Record format: length = %ld, " - " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n", - pcei->header.len, n_pci_data, n_mem_regs, n_io_regs); + /* Register the os mca handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, + ia64_mc_info.imi_mca_handler, + ia64_tpa(mca_hldlr_ptr->gp), + ia64_mc_info.imi_mca_handler_size, + 0, 0, 0))) + { + printk(KERN_ERR "Failed to register OS MCA handler with SAL " + "(status %ld)\n", rc); return; } - if (n_mem_regs) { - prfunc(" Memory Mapped Registers\n Address \tValue\n"); - for (i = 0; i < pcei->num_mem_regs; i++) { - prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); - p_reg_data += 2; - } - } - if (n_io_regs) { - prfunc(" I/O Mapped Registers\n Address \tValue\n"); - for (i = 0; i < pcei->num_io_regs; i++) { - prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]); - p_reg_data += 2; - } - } - if (pcei->valid.oem_data) { - platform_pci_comp_err_print((int)pcei->header.len, n_pci_data, - p_oem_data, prfunc); - prfunc("\n"); - } -} - -/* - * ia64_log_plat_specific_err_info_print - * - * Format and log the platform specifie error record section data. - * - * Inputs: sel_dev_err_info * (Ptr to the platform specific error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei, - prfunc_t prfunc) -{ - prfunc("+ Platform Specific Error Detail: "); + IA64_MCA_DEBUG("%s: registered OS MCA handler with SAL at 0x%lx, gp = 0x%lx\n", __FUNCTION__, + ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); - if (psei->valid.err_status) - prfunc(" Error Status: %#lx", psei->err_status); - if (psei->valid.guid) { - prfunc(" GUID: "); - ia64_log_prt_guid(&psei->guid, prfunc); - } - if (psei->valid.oem_data) { - platform_plat_specific_err_print((int) psei->header.len, - (char *) psei->oem_data - (char *) psei, - &psei->oem_data[0], prfunc); - } - prfunc("\n"); -} + /* + * XXX - disable SAL checksum by setting size to 0, should be + * size of the actual init handler in mca_asm.S. + */ + ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler_size = 0; + ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler_size = 0; -/* - * ia64_log_host_ctlr_err_info_print - * - * Format and log the platform host controller error record section data. - * - * Inputs: host_ctlr_err_info * (Ptr to the host controller error record - * section returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei, - prfunc_t prfunc) -{ - prfunc("+ Host Controller Error Detail: "); + IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__, + ia64_mc_info.imi_monarch_init_handler); - if (hcei->valid.err_status) - prfunc(" Error Status: %#lx", hcei->err_status); - if (hcei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", hcei->requestor_id); - if (hcei->valid.responder_id) - prfunc(" Responder ID: %#lx", hcei->responder_id); - if (hcei->valid.target_id) - prfunc(" Target ID: %#lx", hcei->target_id); - if (hcei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data); - if (hcei->valid.oem_data) { - platform_host_ctlr_err_print((int)hcei->header.len, - (int)sizeof(sal_log_host_ctlr_err_info_t) - 1, - &(hcei->oem_data[0]), prfunc); + /* Register the os init handler with SAL */ + if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, + ia64_mc_info.imi_monarch_init_handler, + ia64_tpa(ia64_get_gp()), + ia64_mc_info.imi_monarch_init_handler_size, + ia64_mc_info.imi_slave_init_handler, + ia64_tpa(ia64_get_gp()), + ia64_mc_info.imi_slave_init_handler_size))) + { + printk(KERN_ERR "Failed to register m/s INIT handlers with SAL " + "(status %ld)\n", rc); + return; } - prfunc("\n"); -} -/* - * ia64_log_plat_bus_err_info_print - * - * Format and log the platform bus error record section data. - * - * Inputs: plat_bus_err_info * (Ptr to the platform bus error record section - * returned by SAL) - * prfunc (fn ptr of print function to be used for output) - * Outputs: None - */ -void -ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei, - prfunc_t prfunc) -{ - prfunc("+ Platform Bus Error Detail: "); + IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); - if (pbei->valid.err_status) - prfunc(" Error Status: %#lx", pbei->err_status); - if (pbei->valid.requestor_id) - prfunc(" Requestor ID: %#lx", pbei->requestor_id); - if (pbei->valid.responder_id) - prfunc(" Responder ID: %#lx", pbei->responder_id); - if (pbei->valid.target_id) - prfunc(" Target ID: %#lx", pbei->target_id); - if (pbei->valid.bus_spec_data) - prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data); - if (pbei->valid.oem_data) { - platform_plat_bus_err_print((int)pbei->header.len, - (int)sizeof(sal_log_plat_bus_err_info_t) - 1, - &(pbei->oem_data[0]), prfunc); - } - prfunc("\n"); -} + /* + * Configure the CMCI/P vector and handler. Interrupts for CMC are + * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). + */ + register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); + register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction); + ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ -/* - * ia64_log_proc_dev_err_info_print - * - * Display the processor device error record. - * - * Inputs: sal_log_processor_info_t * (Ptr to processor device error record - * section body). - * prfunc (fn ptr of print function to be used - * for output). - * Outputs: None - */ -void -ia64_log_proc_dev_err_info_print (sal_log_processor_info_t *slpi, - prfunc_t prfunc) -{ -#ifdef MCA_PRT_XTRA_DATA - size_t d_len = slpi->header.len - sizeof(sal_log_section_hdr_t); -#endif - sal_processor_static_info_t *spsi; - int i; - sal_log_mod_error_info_t *p_data; + /* Setup the MCA rendezvous interrupt vector */ + register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); - prfunc("+Processor Device Error Info Section\n"); + /* Setup the MCA wakeup interrupt vector */ + register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL +#ifdef CONFIG_ACPI + /* Setup the CPE interrupt vector */ { - char *p_data = (char *)&slpi->valid; + irq_desc_t *desc; + unsigned int irq; + int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI); - prfunc("SAL_PROC_DEV_ERR SECTION DATA: Data buffer = %p, " - "Data size = %ld\n", (void *)p_data, d_len); - ia64_log_hexdump(p_data, d_len, prfunc); - prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n"); + if (cpev >= 0) { + for (irq = 0; irq < NR_IRQS; ++irq) + if (irq_to_vector(irq) == cpev) { + desc = irq_desc(irq); + desc->status |= IRQ_PER_CPU; + desc->handler = &irq_type_iosapic_level; + setup_irq(irq, &mca_cpe_irqaction); + } + ia64_mca_register_cpev(cpev); + } } -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if (slpi->valid.proc_error_map) - prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map); - - if (slpi->valid.proc_state_param) - prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter); - - if (slpi->valid.proc_cr_lid) - prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid); +#endif - /* - * Note: March 2001 SAL spec states that if the number of elements in any - * of the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is - * absent. Also, current implementations only allocate space for number of - * elements used. So we walk the data pointer from here on. + /* Initialize the areas set aside by the OS to buffer the + * platform/processor error states for MCA/INIT/CMC + * handling. */ - p_data = &slpi->info[0]; - - /* Print the cache check information if any*/ - for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++) - ia64_log_cache_check_info_print(i, p_data, prfunc); - - /* Print the tlb check information if any*/ - for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++) - ia64_log_tlb_check_info_print(i, p_data, prfunc); - - /* Print the bus check information if any*/ - for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++) - ia64_log_bus_check_info_print(i, p_data, prfunc); - - /* Print the reg file check information if any*/ - for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++) - ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), - prfunc); /* Just hex dump for now */ - - /* Print the ms check information if any*/ - for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++) - ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t), - prfunc); /* Just hex dump for now */ - - /* Print CPUID registers if any*/ - if (slpi->valid.cpuid_info) { - u64 *p = (u64 *)p_data; - - prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]); - p_data++; - } + ia64_log_init(SAL_INFO_TYPE_MCA); + ia64_log_init(SAL_INFO_TYPE_INIT); + ia64_log_init(SAL_INFO_TYPE_CMC); + ia64_log_init(SAL_INFO_TYPE_CPE); - /* Print processor static info if any */ - if (slpi->valid.psi_static_struct) { - spsi = (sal_processor_static_info_t *)p_data; - - /* Print branch register contents if valid */ - if (spsi->valid.br) - ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br", - prfunc); - - /* Print control register contents if valid */ - if (spsi->valid.cr) - ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr", - prfunc); - - /* Print application register contents if valid */ - if (spsi->valid.ar) - ia64_log_processor_regs_print(spsi->ar, 128, "Application", - "ar", prfunc); - - /* Print region register contents if valid */ - if (spsi->valid.rr) - ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr", - prfunc); - - /* Print floating-point register contents if valid */ - if (spsi->valid.fr) - ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr", - prfunc); - } + printk(KERN_INFO "MCA related initialization done\n"); } /* - * ia64_log_processor_info_print + * ia64_mca_late_init * - * Display the processor-specific information logged by PAL as a part - * of MCA or INIT or CMC. + * Opportunity to setup things that require initialization later + * than ia64_mca_init. Setup a timer to poll for CPEs if the + * platform doesn't support an interrupt driven mechanism. * - * Inputs : lh (Pointer of the sal log header which specifies the - * format of SAL state info as specified by the SAL spec). - * prfunc (fn ptr of print function to be used for output). - * Outputs : None + * Inputs : None + * Outputs : Status */ -void -ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc) +static int __init +ia64_mca_late_init(void) { - sal_log_section_hdr_t *slsh; - int n_sects; - u32 ercd_pos; - - if (!lh) - return; - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_record_header(lh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { - IA64_MCA_DEBUG("ia64_mca_log_print: " - "truncated SAL CMC error record. len = %d\n", - lh->len); - return; - } - - /* Print record header info */ - ia64_log_rec_header_print(lh, prfunc); - - for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { - /* point to next section header */ - slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_section_header(slsh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) { - IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); - continue; - } - - /* - * Now process processor device error record section - */ - ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, printk); - } - - IA64_MCA_DEBUG("ia64_mca_log_print: " - "found %d sections in SAL CMC error record. len = %d\n", - n_sects, lh->len); - if (!n_sects) { - prfunc("No Processor Device Error Info Section found\n"); - return; - } -} - -/* - * ia64_log_platform_info_print - * - * Format and Log the SAL Platform Error Record. - * - * Inputs : lh (Pointer to the sal error record header with format - * specified by the SAL spec). - * prfunc (fn ptr of log output function to use) - * Outputs : platform error status - */ -int -ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc) -{ - sal_log_section_hdr_t *slsh; - int n_sects; - u32 ercd_pos; - int platform_err = 0; - - if (!lh) - return platform_err; - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_record_header(lh, prfunc); -#endif // MCA_PRT_XTRA_DATA for test only @FVL - - if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) { - IA64_MCA_DEBUG("ia64_mca_log_print: " - "truncated SAL error record. len = %d\n", - lh->len); - return platform_err; - } - - /* Print record header info */ - ia64_log_rec_header_print(lh, prfunc); - - for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) { - /* point to next section header */ - slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos); - -#ifdef MCA_PRT_XTRA_DATA // for test only @FVL - ia64_log_prt_section_header(slsh, prfunc); - - if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) { - size_t d_len = slsh->len - sizeof(sal_log_section_hdr_t); - char *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid; - - prfunc("Start of Platform Err Data Section: Data buffer = %p, " - "Data size = %ld\n", (void *)p_data, d_len); - ia64_log_hexdump(p_data, d_len, prfunc); - prfunc("End of Platform Err Data Section\n"); - } -#endif // MCA_PRT_XTRA_DATA for test only @FVL + init_timer(&cmc_poll_timer); + cmc_poll_timer.function = ia64_mca_cmc_poll; - /* - * Now process CPE error record section - */ - if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) { - ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Memory Device Error Info Section\n"); - ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform SEL Device Error Info Section\n"); - ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform PCI Bus Error Info Section\n"); - ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform SMBIOS Device Error Info Section\n"); - ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform PCI Component Error Info Section\n"); - ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Specific Error Info Section\n"); - ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *) - slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Host Controller Error Info Section\n"); - ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh, - prfunc); - } else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) { - platform_err = 1; - prfunc("+Platform Bus Error Info Section\n"); - ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh, - prfunc); - } else { - IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n"); - continue; - } - } + /* Reset to the correct state */ + cmc_polling_enabled = 0; - IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n", - n_sects, lh->len); - if (!n_sects) { - prfunc("No Platform Error Info Sections found\n"); - return platform_err; - } - return platform_err; -} + init_timer(&cpe_poll_timer); + cpe_poll_timer.function = ia64_mca_cpe_poll; -/* - * ia64_log_print - * - * Displays the contents of the OS error log information - * - * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) - * prfunc (fn ptr of log output function to use) - * Outputs : platform error status - */ -int -ia64_log_print(int sal_info_type, prfunc_t prfunc) -{ - int platform_err = 0; - - switch(sal_info_type) { - case SAL_INFO_TYPE_MCA: - prfunc("+CPU %d: SAL log contains MCA error record\n", smp_processor_id()); - ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - break; - case SAL_INFO_TYPE_INIT: - prfunc("+CPU %d: SAL log contains INIT error record\n", smp_processor_id()); - ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - break; - case SAL_INFO_TYPE_CMC: - prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n"); - ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - prfunc("+END HARDWARE ERROR STATE AT CMC\n"); - break; - case SAL_INFO_TYPE_CPE: - prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n"); - ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); - prfunc("+END HARDWARE ERROR STATE AT CPE\n"); - break; - default: - prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n"); - break; +#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); + ia64_mca_cpe_poll(0UL); } - return platform_err; -} +#endif -static int __init -ia64_mca_disable_cpe_polling(char *str) -{ - cpe_poll_enabled = 0; - return 1; + return 0; } -__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); +module_init(ia64_mca_late_init); diff -u -Nur linux-2.4.25/arch/ia64/kernel/pci.c linux-ia64-2.4/arch/ia64/kernel/pci.c --- linux-2.4.25/arch/ia64/kernel/pci.c 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/kernel/pci.c 2004-02-18 09:51:23.000000000 -0700 @@ -386,10 +386,6 @@ void __init pcibios_init (void) { -#ifdef CONFIG_IA64_MCA - ia64_mca_check_errors(); /* For post-failure MCA error logging */ -#endif - pcibios_config_init(); platform_pci_fixup(0); /* phase 0 fixups (before buses scanned) */ diff -u -Nur linux-2.4.25/arch/ia64/kernel/salinfo.c linux-ia64-2.4/arch/ia64/kernel/salinfo.c --- linux-2.4.25/arch/ia64/kernel/salinfo.c 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/kernel/salinfo.c 2004-02-18 09:51:23.000000000 -0700 @@ -16,6 +16,9 @@ * Cache the record across multi-block reads from user space. * Support > 64 cpus. * Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module. + * + * Jan 28 2004 kaos@sgi.com + * Periodically check for outstanding MCA or INIT records. */ #include @@ -23,6 +26,7 @@ #include #include #include +#include #include #include @@ -187,6 +191,8 @@ /* This routine is invoked in interrupt context. Note: mca.c enables * interrupts before calling this code for CMC/CPE. MCA and INIT events are * not irq safe, do not call any routines that use spinlocks, they may deadlock. + * MCA and INIT records are recorded, a timer event will look for any + * outstanding events and wake up the user space code. * * The buffer passed from mca.c points to the output from ia64_log_get. This is * a persistent buffer but its contents can change between the interrupt and @@ -194,12 +200,12 @@ * changes. */ void -salinfo_log_wakeup(int type, u8 *buffer, u64 size) +salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) { struct salinfo_data *data = salinfo_data + type; struct salinfo_data_saved *data_saved; unsigned long flags = 0; - int i, irqsafe = type != SAL_INFO_TYPE_MCA && type != SAL_INFO_TYPE_INIT; + int i; int saved_size = ARRAY_SIZE(data->data_saved); BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); @@ -232,6 +238,35 @@ } } +/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */ +#define SALINFO_TIMER_DELAY (5*60*HZ) +static struct timer_list salinfo_timer; + +static void +salinfo_timeout_check(struct salinfo_data *data) +{ + int i; + if (!data->open) + return; + for (i = 0; i < NR_CPUS; ++i) { + if (test_bit(i, &data->cpu_event)) { + /* double up() is not a problem, user space will see no + * records for the additional "events". + */ + up(&data->sem); + } + } +} + +static void +salinfo_timeout (unsigned long arg) +{ + salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA); + salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT); + salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; + add_timer(&salinfo_timer); +} + static int salinfo_event_open(struct inode *inode, struct file *file) { @@ -571,6 +606,11 @@ *sdir++ = salinfo_dir; + init_timer(&salinfo_timer); + salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; + salinfo_timer.function = &salinfo_timeout; + add_timer(&salinfo_timer); + return 0; } diff -u -Nur linux-2.4.25/arch/ia64/kernel/smpboot.c linux-ia64-2.4/arch/ia64/kernel/smpboot.c --- linux-2.4.25/arch/ia64/kernel/smpboot.c 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/kernel/smpboot.c 2004-02-18 09:51:18.000000000 -0700 @@ -349,7 +349,6 @@ #ifdef CONFIG_IA64_MCA ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */ - ia64_mca_check_errors(); /* For post-failure MCA error logging */ #endif #ifdef CONFIG_PERFMON diff -u -Nur linux-2.4.25/arch/ia64/kernel/unwind.c linux-ia64-2.4/arch/ia64/kernel/unwind.c --- linux-2.4.25/arch/ia64/kernel/unwind.c 2004-02-18 09:52:55.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/kernel/unwind.c 2004-02-18 09:51:42.000000000 -0700 @@ -826,7 +826,7 @@ static inline void desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) { - if (abi == 0 && context == 'i') { + if (abi == 3 && context == 'i') { sr->flags |= UNW_FLAG_INTERRUPT_FRAME; UNW_DPRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__); } diff -u -Nur linux-2.4.25/arch/ia64/sn/kernel/mca.c linux-ia64-2.4/arch/ia64/sn/kernel/mca.c --- linux-2.4.25/arch/ia64/sn/kernel/mca.c 2004-02-18 09:52:27.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/sn/kernel/mca.c 2004-02-18 09:51:19.000000000 -0700 @@ -91,20 +91,6 @@ } - -/* - * ia64_sn2_platform_plat_specific_err_print - * - * Called by the MCA handler to log platform-specific errors. - */ -void -ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) -{ - ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); -} - - - static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) { diff -u -Nur linux-2.4.25/arch/ia64/tools/Makefile linux-ia64-2.4/arch/ia64/tools/Makefile --- linux-2.4.25/arch/ia64/tools/Makefile 2004-02-18 09:52:36.000000000 -0700 +++ linux-ia64-2.4/arch/ia64/tools/Makefile 2004-02-18 09:51:24.000000000 -0700 @@ -5,6 +5,7 @@ all: mrproper: clean + rm -f $(TARGET) clean: rm -f print_offsets.s print_offsets offsets.h diff -u -Nur linux-2.4.25/drivers/acpi/bus.c linux-ia64-2.4/drivers/acpi/bus.c --- linux-2.4.25/drivers/acpi/bus.c 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/drivers/acpi/bus.c 2004-02-18 09:51:24.000000000 -0700 @@ -1407,17 +1407,15 @@ switch (type) { case ACPI_BUS_TYPE_DEVICE: result = acpi_bus_get_status(device); - if (result) - goto end; - break; + if (!result) + break; + if (!device->status.present) + result = -ENOENT; + goto end; default: STRUCT_TO_INT(device->status) = 0x0F; break; } - if (!device->status.present) { - result = -ENOENT; - goto end; - } /* * Initialize Device diff -u -Nur linux-2.4.25/drivers/acpi/pci_root.c linux-ia64-2.4/drivers/acpi/pci_root.c --- linux-2.4.25/drivers/acpi/pci_root.c 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/drivers/acpi/pci_root.c 2004-02-18 09:51:04.000000000 -0700 @@ -152,8 +152,6 @@ switch (status) { case AE_OK: root->id.segment = (u16) value; - printk("_SEG exists! Unsupported. Abort.\n"); - BUG(); break; case AE_NOT_FOUND: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -213,7 +211,12 @@ * PCI namespace does not get created until this call is made (and * thus the root bridge's pci_dev does not exist). */ +#ifdef CONFIG_X86 root->bus = pcibios_scan_root(root->id.bus); +#else + root->bus = pcibios_scan_root(root->handle, + root->id.segment, root->id.bus); +#endif if (!root->bus) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Bus %02x:%02x not present in PCI namespace\n", diff -u -Nur linux-2.4.25/drivers/char/Config.in linux-ia64-2.4/drivers/char/Config.in --- linux-2.4.25/drivers/char/Config.in 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/drivers/char/Config.in 2004-02-18 09:51:08.000000000 -0700 @@ -24,6 +24,9 @@ tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi + if [ "$CONFIG_ACPI" = "y" ]; then + bool ' Support for serial ports defined in ACPI namespace' CONFIG_SERIAL_ACPI + fi fi dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then diff -u -Nur linux-2.4.25/drivers/char/agp/agp.h linux-ia64-2.4/drivers/char/agp/agp.h --- linux-2.4.25/drivers/char/agp/agp.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/drivers/char/agp/agp.h 2004-02-18 09:51:22.000000000 -0700 @@ -535,10 +535,6 @@ #define HP_ZX1_TCNFG 0x318 #define HP_ZX1_PDIR_BASE 0x320 -/* HP ZX1 LBA registers */ -#define HP_ZX1_AGP_STATUS 0x64 -#define HP_ZX1_AGP_COMMAND 0x68 - /* ATI register */ #define ATI_APBASE 0x10 #define ATI_GART_MMBASE_ADDR 0x14 diff -u -Nur linux-2.4.25/drivers/char/agp/agpgart_be.c linux-ia64-2.4/drivers/char/agp/agpgart_be.c --- linux-2.4.25/drivers/char/agp/agpgart_be.c 2004-02-18 09:52:08.000000000 -0700 +++ linux-ia64-2.4/drivers/char/agp/agpgart_be.c 2004-02-18 09:51:06.000000000 -0700 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -217,10 +218,14 @@ agp_bridge.free_by_type(curr); return; } - if (curr->page_count != 0) { - for (i = 0; i < curr->page_count; i++) { - agp_bridge.agp_destroy_page((unsigned long) - phys_to_virt(curr->memory[i])); + if (agp_bridge.cant_use_aperture) { + vfree(curr->vmptr); + } else { + if (curr->page_count != 0) { + for (i = 0; i < curr->page_count; i++) { + agp_bridge.agp_destroy_page((unsigned long) + phys_to_virt(curr->memory[i])); + } } } agp_free_key(curr->key); @@ -229,6 +234,8 @@ MOD_DEC_USE_COUNT; } +#define IN_VMALLOC(_x) (((_x) >= VMALLOC_START) && ((_x) < VMALLOC_END)) + #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(unsigned long)) agp_memory *agp_allocate_memory(size_t page_count, u32 type) @@ -263,18 +270,43 @@ MOD_DEC_USE_COUNT; return NULL; } - for (i = 0; i < page_count; i++) { - new->memory[i] = agp_bridge.agp_alloc_page(); - if (new->memory[i] == 0) { - /* Free this structure */ - agp_free_memory(new); + if (agp_bridge.cant_use_aperture) { + void *vmblock; + unsigned long vaddr; + struct page *page; + + vmblock = __vmalloc(page_count << PAGE_SHIFT, GFP_KERNEL, PAGE_KERNEL); + if (vmblock == NULL) { + MOD_DEC_USE_COUNT; return NULL; } - new->memory[i] = virt_to_phys((void *) new->memory[i]); - new->page_count++; - } + new->vmptr = vmblock; + vaddr = (unsigned long) vmblock; + + for (i = 0; i < page_count; i++, vaddr += PAGE_SIZE) { + page = vmalloc_to_page((void *) vaddr); + if (!page) { + MOD_DEC_USE_COUNT; + return NULL; + } + new->memory[i] = virt_to_phys(page_address(page)); + } + + new->page_count = page_count; + } else { + for (i = 0; i < page_count; i++) { + new->memory[i] = agp_bridge.agp_alloc_page(); + if (new->memory[i] == 0) { + /* Free this structure */ + agp_free_memory(new); + return NULL; + } + new->memory[i] = virt_to_phys((void *) new->memory[i]); + new->page_count++; + } + } return new; } @@ -287,26 +319,18 @@ temp = agp_bridge.current_size; - switch (agp_bridge.size_type) { - case U8_APER_SIZE: + if (agp_bridge.size_type == U8_APER_SIZE) current_size = A_SIZE_8(temp)->size; - break; - case U16_APER_SIZE: + else if (agp_bridge.size_type == U16_APER_SIZE) current_size = A_SIZE_16(temp)->size; - break; - case U32_APER_SIZE: + else if (agp_bridge.size_type == U32_APER_SIZE) current_size = A_SIZE_32(temp)->size; - break; - case LVL2_APER_SIZE: + else if (agp_bridge.size_type == LVL2_APER_SIZE) current_size = A_SIZE_LVL2(temp)->size; - break; - case FIXED_APER_SIZE: + else if (agp_bridge.size_type == FIXED_APER_SIZE) current_size = A_SIZE_FIX(temp)->size; - break; - default: + else current_size = 0; - break; - } current_size -= (agp_memory_reserved / (1024*1024)); @@ -315,6 +339,9 @@ /* Routine to copy over information structure */ +/* AGP bridge need not be PCI device, but DRM thinks it is. */ +static struct pci_dev fake_bridge_dev; + int agp_copy_info(agp_kern_info * info) { memset(info, 0, sizeof(agp_kern_info)); @@ -324,7 +351,7 @@ } info->version.major = agp_bridge.version->major; info->version.minor = agp_bridge.version->minor; - info->device = agp_bridge.dev; + info->device = agp_bridge.dev ? agp_bridge.dev : &fake_bridge_dev; info->chipset = agp_bridge.type; info->mode = agp_bridge.mode; info->aper_base = agp_bridge.gart_bus_addr; @@ -398,97 +425,104 @@ /* Generic Agp routines - Start */ -static void agp_generic_agp_enable(u32 mode) +static u32 agp_collect_device_status(u32 mode, u32 command) { - struct pci_dev *device = NULL; - u32 command, scratch; - u8 cap_ptr; + struct pci_dev *device; + u8 agp; + u32 scratch; - pci_read_config_dword(agp_bridge.dev, - agp_bridge.capndx + 4, - &command); + pci_for_each_dev(device) { + agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; - /* - * PASS1: go throu all devices that claim to be - * AGP devices and collect their data. - */ + /* + * Ok, here we have a AGP device. Disable impossible + * settings, and adjust the readqueue to the minimum. + */ + pci_read_config_dword(device, agp + PCI_AGP_STATUS, &scratch); + /* adjust RQ depth */ + command = + ((command & ~0xff000000) | + min_t(u32, (mode & 0xff000000), + min_t(u32, (command & 0xff000000), + (scratch & 0xff000000)))); + + /* disable SBA if it's not supported */ + if (!((command & 0x00000200) && + (scratch & 0x00000200) && + (mode & 0x00000200))) + command &= ~0x00000200; + + /* disable FW if it's not supported */ + if (!((command & 0x00000010) && + (scratch & 0x00000010) && + (mode & 0x00000010))) + command &= ~0x00000010; - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - pci_read_config_dword(device, cap_ptr + 4, &scratch); - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; - - /* disable FW if it's not supported */ - if (!((command & 0x00000010) && - (scratch & 0x00000010) && - (mode & 0x00000010))) - command &= ~0x00000010; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; - } + if (!((command & 4) && + (scratch & 4) && + (mode & 4))) + command &= ~0x00000004; + + if (!((command & 2) && + (scratch & 2) && + (mode & 2))) + command &= ~0x00000002; + + if (!((command & 1) && + (scratch & 1) && + (mode & 1))) + command &= ~0x00000001; } - /* - * PASS2: Figure out the 4X/2X/1X setting and enable the - * target (our motherboard chipset). - */ - if (command & 4) { + if (command & 4) command &= ~3; /* 4X */ + if (command & 2) + command &= ~5; /* 2X (8X for AGP3.0) */ + if (command & 1) + command &= ~6; /* 1X (4X for AGP3.0) */ + + return command; +} + +static void agp_device_command(u32 command, int agp_v3) +{ + struct pci_dev *device; + int mode; + + mode = command & 0x7; + if (agp_v3) + mode *= 4; + + pci_for_each_dev(device) { + u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); + if (!agp) + continue; + + printk(KERN_INFO PFX "Putting AGP V%d device at %s into %dx mode\n", + agp_v3 ? 3 : 2, device->slot_name, mode); + pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); } - if (command & 2) { - command &= ~5; /* 2X */ - } - if (command & 1) { - command &= ~6; /* 1X */ - } +} + +static void agp_generic_agp_enable(u32 mode) +{ + u32 command; + + pci_read_config_dword(agp_bridge.dev, + agp_bridge.capndx + PCI_AGP_STATUS, + &command); + + command = agp_collect_device_status(mode, command); command |= 0x00000100; pci_write_config_dword(agp_bridge.dev, - agp_bridge.capndx + 8, + agp_bridge.capndx + PCI_AGP_COMMAND, command); - /* - * PASS3: Go throu all AGP devices and update the - * command registers. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 0); } static int agp_generic_create_gatt_table(void) @@ -3641,7 +3675,6 @@ struct pci_dev *device = NULL; u32 command, scratch; u8 cap_ptr; - u8 agp_v3; u8 v3_devs=0; /* FIXME: If 'mode' is x1/x2/x4 should we call the AGPv2 routines directly ? @@ -3674,77 +3707,14 @@ } - pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command); - - /* - * PASS2: go through all devices that claim to be - * AGP devices and collect their data. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - printk (KERN_INFO "AGP: Setting up AGPv3 capable device at %d:%d:%d\n", - device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn)); - pci_read_config_dword(device, cap_ptr + 4, &scratch); - agp_v3 = (scratch & (1<<3) ) >>3; - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x200) && (scratch & 0x200) && (mode & 0x200))) - command &= ~0x200; - - /* disable FW if it's not supported */ - if (!((command & 0x10) && (scratch & 0x10) && (mode & 0x10))) - command &= ~0x10; - - if (!((command & 2) && (scratch & 2) && (mode & 2))) { - command &= ~2; /* 8x */ - printk (KERN_INFO "AGP: Putting device into 8x mode\n"); - } - - if (!((command & 1) && (scratch & 1) && (mode & 1))) { - command &= ~1; /* 4x */ - printk (KERN_INFO "AGP: Putting device into 4x mode\n"); - } - } - } - /* - * PASS3: Figure out the 8X/4X setting and enable the - * target (our motherboard chipset). - */ - - if (command & 2) - command &= ~5; /* 8X */ - - if (command & 1) - command &= ~6; /* 4X */ + pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + PCI_AGP_STATUS, &command); + command = agp_collect_device_status(mode, command); command |= 0x100; - pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + 8, command); - - /* - * PASS4: Go through all AGP devices and update the - * command registers. - */ + pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + PCI_AGP_COMMAND, command); - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 1); } @@ -4457,7 +4427,7 @@ /* Fill in the mode register */ pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); pci_read_config_byte(agp_bridge.dev, @@ -4607,104 +4577,23 @@ static void serverworks_agp_enable(u32 mode) { - struct pci_dev *device = NULL; - u32 command, scratch, cap_id; - u8 cap_ptr; + u32 command; pci_read_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &command); - /* - * PASS1: go throu all devices that claim to be - * AGP devices and collect their data. - */ - - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) { - do { - pci_read_config_dword(device, - cap_ptr, &cap_id); - - if ((cap_id & 0xff) != 0x02) - cap_ptr = (cap_id >> 8) & 0xff; - } - while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00)); - } - if (cap_ptr != 0x00) { - /* - * Ok, here we have a AGP device. Disable impossible - * settings, and adjust the readqueue to the minimum. - */ - - pci_read_config_dword(device, cap_ptr + 4, &scratch); - - /* adjust RQ depth */ - command = - ((command & ~0xff000000) | - min_t(u32, (mode & 0xff000000), - min_t(u32, (command & 0xff000000), - (scratch & 0xff000000)))); - - /* disable SBA if it's not supported */ - if (!((command & 0x00000200) && - (scratch & 0x00000200) && - (mode & 0x00000200))) - command &= ~0x00000200; - - /* disable FW */ - command &= ~0x00000010; - - command &= ~0x00000008; - - if (!((command & 4) && - (scratch & 4) && - (mode & 4))) - command &= ~0x00000004; - - if (!((command & 2) && - (scratch & 2) && - (mode & 2))) - command &= ~0x00000002; - - if (!((command & 1) && - (scratch & 1) && - (mode & 1))) - command &= ~0x00000001; - } - } - /* - * PASS2: Figure out the 4X/2X/1X setting and enable the - * target (our motherboard chipset). - */ + command = agp_collect_device_status(mode, command); - if (command & 4) { - command &= ~3; /* 4X */ - } - if (command & 2) { - command &= ~5; /* 2X */ - } - if (command & 1) { - command &= ~6; /* 1X */ - } + command &= ~0x00000010; /* disable FW */ + command &= ~0x00000008; command |= 0x00000100; pci_write_config_dword(serverworks_private.svrwrks_dev, - agp_bridge.capndx + 8, + agp_bridge.capndx + PCI_AGP_COMMAND, command); - /* - * PASS3: Go throu all AGP devices and update the - * command registers. - */ - - pci_for_each_dev(device) { - cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); - if (cap_ptr != 0x00) - pci_write_config_dword(device, cap_ptr + 8, command); - } + agp_device_command(command, 0); } static int __init serverworks_setup (struct pci_dev *pdev) @@ -5131,6 +5020,7 @@ static struct _hp_private { volatile u8 *ioc_regs; volatile u8 *lba_regs; + int lba_cap_offset; u64 *io_pdir; // PDIR for entire IOVA u64 *gatt; // PDIR just for GART (subset of above) u64 gatt_entries; @@ -5183,6 +5073,7 @@ hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { + /* Normal case when no AGP device in system */ hp->gatt = 0; hp->gatt_entries = 0; printk(KERN_ERR PFX "No reserved IO PDIR entry found; " @@ -5228,12 +5119,13 @@ return 0; } -static int __init hp_zx1_ioc_init(u64 ioc_hpa, u64 lba_hpa) +static int __init hp_zx1_ioc_init(u64 hpa) { struct _hp_private *hp = &hp_private; - hp->ioc_regs = ioremap(ioc_hpa, 1024); - hp->lba_regs = ioremap(lba_hpa, 256); + hp->ioc_regs = ioremap(hpa, 1024); + if (!hp->ioc_regs) + return -ENOMEM; /* * If the IOTLB is currently disabled, we can take it over. @@ -5247,6 +5139,50 @@ return hp_zx1_ioc_shared(); } +static int +hp_zx1_lba_find_capability(volatile u8 *hpa, int cap) +{ + u16 status; + u8 pos, id; + int ttl = 48; + + status = INREG16(hpa, PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + pos = INREG8(hpa, PCI_CAPABILITY_LIST); + while (ttl-- && pos >= 0x40) { + pos &= ~3; + id = INREG8(hpa, pos + PCI_CAP_LIST_ID); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos = INREG8(hpa, pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +static int __init hp_zx1_lba_init(u64 hpa) +{ + struct _hp_private *hp = &hp_private; + int cap; + + hp->lba_regs = ioremap(hpa, 256); + if (!hp->lba_regs) + return -ENOMEM; + + hp->lba_cap_offset = hp_zx1_lba_find_capability(hp->lba_regs, PCI_CAP_ID_AGP); + + cap = INREG32(hp->lba_regs, hp->lba_cap_offset) & 0xff; + if (cap != PCI_CAP_ID_AGP) { + printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n", + cap, hp->lba_cap_offset); + return -ENODEV; + } + + return 0; +} + static int hp_zx1_fetch_size(void) { int size; @@ -5262,7 +5198,7 @@ struct _hp_private *hp = &hp_private; agp_bridge.gart_bus_addr = hp->gart_base; - agp_bridge.mode = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS); + agp_bridge.mode = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS); if (hp->io_pdir_owner) { OUTREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE, @@ -5282,10 +5218,13 @@ { struct _hp_private *hp = &hp_private; - if (hp->io_pdir_owner) - OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); - iounmap((void *) hp->ioc_regs); - iounmap((void *) hp->lba_regs); + if (hp->ioc_regs) { + if (hp->io_pdir_owner) + OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0); + iounmap((void *) hp->ioc_regs); + } + if (hp->lba_regs) + iounmap((void *) hp->lba_regs); } static void hp_zx1_tlbflush(agp_memory * mem) @@ -5405,18 +5344,23 @@ struct _hp_private *hp = &hp_private; u32 command; - command = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS); + command = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS); command = agp_collect_device_status(mode, command); command |= 0x00000100; - OUTREG32(hp->lba_regs, HP_ZX1_AGP_COMMAND, command); + OUTREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_COMMAND, command); agp_device_command(command, 0); } static int __init hp_zx1_setup(u64 ioc_hpa, u64 lba_hpa) { + struct _hp_private *hp = &hp_private; + int error; + + memset(hp, 0, sizeof(*hp)); + agp_bridge.dev_private_data = NULL; agp_bridge.size_type = FIXED_APER_SIZE; agp_bridge.needs_scratch_page = FALSE; @@ -5441,7 +5385,16 @@ fake_bridge_dev.vendor = PCI_VENDOR_ID_HP; fake_bridge_dev.device = PCI_DEVICE_ID_HP_PCIX_LBA; - return hp_zx1_ioc_init(ioc_hpa, lba_hpa); + error = hp_zx1_ioc_init(ioc_hpa); + if (error) + goto fail; + + error = hp_zx1_lba_init(lba_hpa); + +fail: + if (error) + hp_zx1_cleanup(); + return error; } static acpi_status __init hp_zx1_gart_probe(acpi_handle obj, u32 depth, void *context, void **ret) @@ -5455,7 +5408,7 @@ status = acpi_hp_csr_space(obj, &lba_hpa, &length); if (ACPI_FAILURE(status)) - return AE_OK; + return AE_OK; /* keep looking for another bridge */ /* Look for an enclosing IOC scope and find its CSR space */ handle = obj; @@ -5491,7 +5444,7 @@ (char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa); hp_zx1_gart_found = 1; - return AE_CTRL_TERMINATE; + return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */ } static int __init @@ -6469,7 +6422,6 @@ "IGP9100/M", ati_generic_setup }, #endif /* CONFIG_AGP_ATI */ - { 0, }, /* dummy final entry, always present */ }; @@ -6552,7 +6504,6 @@ return -ENODEV; } - /* Supported Device Scanning routine */ static int __init agp_find_supported_device(void) @@ -6880,7 +6831,7 @@ /* Fill in the mode register */ pci_read_config_dword(agp_bridge.dev, - agp_bridge.capndx + 4, + agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode); /* probe for known chipsets */ @@ -7098,7 +7049,8 @@ inter_module_register("drm_agp", THIS_MODULE, &drm_agp); - pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power); + if (agp_bridge.dev) + pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power); return 0; } diff -u -Nur linux-2.4.25/drivers/char/drm/drm_bufs.h linux-ia64-2.4/drivers/char/drm/drm_bufs.h --- linux-2.4.25/drivers/char/drm/drm_bufs.h 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm/drm_bufs.h 2004-02-18 09:51:08.000000000 -0700 @@ -106,7 +106,7 @@ switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if !defined(__sparc__) && !defined(__alpha__) +#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) if ( map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory) ) { DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); diff -u -Nur linux-2.4.25/drivers/char/drm/drm_memory.h linux-ia64-2.4/drivers/char/drm/drm_memory.h --- linux-2.4.25/drivers/char/drm/drm_memory.h 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm/drm_memory.h 2004-02-18 09:51:06.000000000 -0700 @@ -293,6 +293,11 @@ void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev) { void *pt; +#if __REALLY_HAVE_AGP + drm_map_t *map = NULL; + drm_map_list_t *r_list; + struct list_head *list; +#endif if (!size) { DRM_MEM_ERROR(DRM_MEM_MAPPINGS, @@ -300,12 +305,50 @@ return NULL; } +#if __REALLY_HAVE_AGP + if (!dev->agp || dev->agp->cant_use_aperture == 0) + goto standard_ioremap; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if (!map) continue; + if (map->offset <= offset && + (map->offset + map->size) >= (offset + size)) + break; + } + + if (map && map->type == _DRM_AGP) { + struct drm_agp_mem *agpmem; + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= offset && + (agpmem->bound + (agpmem->pages + << PAGE_SHIFT)) >= (offset + size)) + break; + } + + if (agpmem == NULL) + goto ioremap_failure; + + pt = agpmem->memory->vmptr + (offset - agpmem->bound); + goto ioremap_success; + } + +standard_ioremap: +#endif if (!(pt = ioremap(offset, size))) { +#if __REALLY_HAVE_AGP +ioremap_failure: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; spin_unlock(&DRM(mem_lock)); return NULL; } +#if __REALLY_HAVE_AGP +ioremap_success: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; @@ -316,6 +359,11 @@ void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev) { void *pt; +#if __REALLY_HAVE_AGP + drm_map_t *map = NULL; + drm_map_list_t *r_list; + struct list_head *list; +#endif if (!size) { DRM_MEM_ERROR(DRM_MEM_MAPPINGS, @@ -323,12 +371,50 @@ return NULL; } +#if __REALLY_HAVE_AGP + if (!dev->agp || dev->agp->cant_use_aperture == 0) + goto standard_ioremap; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if (!map) continue; + if (map->offset <= offset && + (map->offset + map->size) >= (offset + size)) + break; + } + + if (map && map->type == _DRM_AGP) { + struct drm_agp_mem *agpmem; + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= offset && + (agpmem->bound + (agpmem->pages + << PAGE_SHIFT)) >= (offset + size)) + break; + } + + if (agpmem == NULL) + goto ioremap_failure; + + pt = agpmem->memory->vmptr + (offset - agpmem->bound); + goto ioremap_success; + } + +standard_ioremap: +#endif if (!(pt = ioremap_nocache(offset, size))) { +#if __REALLY_HAVE_AGP +ioremap_failure: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; spin_unlock(&DRM(mem_lock)); return NULL; } +#if __REALLY_HAVE_AGP +ioremap_success: +#endif spin_lock(&DRM(mem_lock)); ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; @@ -344,7 +430,11 @@ if (!pt) DRM_MEM_ERROR(DRM_MEM_MAPPINGS, "Attempt to free NULL pointer\n"); +#if __REALLY_HAVE_AGP + else if (!dev->agp || dev->agp->cant_use_aperture == 0) +#else else +#endif iounmap(pt); spin_lock(&DRM(mem_lock)); diff -u -Nur linux-2.4.25/drivers/char/drm/drm_vm.h linux-ia64-2.4/drivers/char/drm/drm_vm.h --- linux-2.4.25/drivers/char/drm/drm_vm.h 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm/drm_vm.h 2004-02-18 09:51:42.000000000 -0700 @@ -368,6 +368,7 @@ drm_map_list_t *r_list; unsigned long offset = 0; struct list_head *list; + struct page *page; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); @@ -414,28 +415,30 @@ switch (map->type) { case _DRM_AGP: -#if defined(__alpha__) - /* - * On Alpha we can't talk to bus dma address from the - * CPU, so for memory of type DRM_AGP, we'll deal with - * sorting out the real physical pages and mappings - * in nopage() - */ - vma->vm_ops = &DRM(vm_ops); - break; +#if __REALLY_HAVE_AGP + if (dev->agp->cant_use_aperture) { + /* + * On some systems we can't talk to bus dma address from + * the CPU, so for memory of type DRM_AGP, we'll deal + * with sorting out the real physical pages and mappings + * in nopage() + */ + vma->vm_ops = &DRM(vm_ops); + goto mapswitch_out; + } #endif /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - if (VM_OFFSET(vma) >= __pa(high_memory)) { + page = virt_to_page(__va(VM_OFFSET(vma))); + if (!VALID_PAGE(page) || PageReserved(page)) { #if defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } #elif defined(__ia64__) - if (map->type != _DRM_AGP) - vma->vm_page_prot = + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); #elif defined(__powerpc__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; @@ -474,6 +477,9 @@ default: return -EINVAL; /* This should never happen. */ } +#if __REALLY_HAVE_AGP +mapswitch_out: +#endif vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_file = filp; /* Needed for drm_vm_open() */ diff -u -Nur linux-2.4.25/drivers/char/drm/r128_cce.c linux-ia64-2.4/drivers/char/drm/r128_cce.c --- linux-2.4.25/drivers/char/drm/r128_cce.c 2004-02-18 09:52:08.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm/r128_cce.c 2004-02-18 09:51:06.000000000 -0700 @@ -216,7 +216,22 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { +#ifndef CONFIG_AGP_I460 if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) { +#else + /* + * XXX - this is (I think) a 460GX specific hack + * + * When doing texturing, ring.tail sometimes gets ahead of + * PM4_BUFFER_DL_WPTR by 2; consequently, the card processes + * its whole quota of instructions and *ring.head is still 2 + * short of ring.tail. Work around this for now in lieu of + * a better solution. + */ + if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail || + ( dev_priv->ring.tail - + GET_RING_HEAD( &dev_priv->ring ) ) == 2 ) { +#endif int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -317,7 +332,7 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev, drm_r128_private_t *dev_priv ) { - u32 ring_start; + u32 ring_start, rptr_addr; u32 tmp; DRM_DEBUG( "\n" ); @@ -341,8 +356,24 @@ SET_RING_HEAD( &dev_priv->ring, 0 ); if ( !dev_priv->is_pci ) { - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); + /* + * 460GX doesn't claim PCI writes from the card into + * the AGP aperture, so we have to get space outside + * the aperture for RPTR_ADDR. + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + SET_RING_HEAD( &dev_priv->ring, 0 ); + rptr_addr = __pa( dev_priv->ring.head ); + } else + rptr_addr = dev_priv->ring_rptr->offset; + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, rptr_addr ); } else { drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; @@ -629,7 +660,19 @@ DRM_ERROR( "failed to cleanup PCI GART!\n" ); } #endif - + /* + * Free the page we grabbed for RPTR_ADDR + */ + if ( !dev_priv->is_pci && dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + struct page *p = virt_to_page((void *)alt_rh_off); + + put_page(p); + unlock_page(p); + free_page(alt_rh_off); + } + DRM(free)( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -u -Nur linux-2.4.25/drivers/char/drm/radeon_cp.c linux-ia64-2.4/drivers/char/drm/radeon_cp.c --- linux-2.4.25/drivers/char/drm/radeon_cp.c 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm/radeon_cp.c 2004-02-18 09:51:07.000000000 -0700 @@ -854,7 +854,7 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, drm_radeon_private_t *dev_priv ) { - u32 ring_start, cur_read_ptr; + u32 ring_start, cur_read_ptr, rptr_addr; u32 tmp; /* Initialize the memory controller */ @@ -892,8 +892,24 @@ dev_priv->ring.tail = cur_read_ptr; if ( !dev_priv->is_pci ) { - RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, - dev_priv->ring_rptr->offset ); + /* + * 460GX doesn't claim PCI writes from the card into + * the AGP aperture, so we have to get space outside + * the aperture for RPTR_ADDR. + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + *dev_priv->ring.head = cur_read_ptr; + rptr_addr = __pa( dev_priv->ring.head ); + } else + rptr_addr = dev_priv->ring_rptr->offset; + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, rptr_addr ); } else { drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; @@ -1278,6 +1294,19 @@ #endif /* __REALLY_HAVE_SG */ } + /* + * Free the page we grabbed for RPTR_ADDR + */ + if ( !dev_priv->is_pci && dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + struct page *p = virt_to_page((void *)alt_rh_off); + + put_page(p); + unlock_page(p); + free_page(alt_rh_off); + } + DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/agpsupport.c linux-ia64-2.4/drivers/char/drm-4.0/agpsupport.c --- linux-2.4.25/drivers/char/drm-4.0/agpsupport.c 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/agpsupport.c 2004-02-18 09:51:39.000000000 -0700 @@ -30,6 +30,7 @@ #define __NO_VERSION__ #include "drmP.h" +#include #include #if LINUX_VERSION_CODE < 0x020400 #include "agpsupport-pre24.h" @@ -305,6 +306,13 @@ default: head->chipset = "Unknown"; break; } +#if LINUX_VERSION_CODE <= 0x020408 + head->cant_use_aperture = 0; + head->page_mask = ~(0xfff); +#else + head->cant_use_aperture = head->agp_info.cant_use_aperture; + head->page_mask = head->agp_info.page_mask; +#endif DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", head->agp_info.version.major, head->agp_info.version.minor, diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/bufs.c linux-ia64-2.4/drivers/char/drm-4.0/bufs.c --- linux-2.4.25/drivers/char/drm-4.0/bufs.c 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/bufs.c 2004-02-18 09:51:04.000000000 -0700 @@ -73,7 +73,7 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#ifndef __sparc__ +#if !defined(__sparc__) && !defined(__ia64__) if (map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory)) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/drmP.h linux-ia64-2.4/drivers/char/drm-4.0/drmP.h --- linux-2.4.25/drivers/char/drm-4.0/drmP.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/drmP.h 2004-02-18 09:51:23.000000000 -0700 @@ -510,6 +510,8 @@ int acquired; unsigned long base; int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; } drm_agp_head_t; #endif diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/memory.c linux-ia64-2.4/drivers/char/drm-4.0/memory.c --- linux-2.4.25/drivers/char/drm-4.0/memory.c 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/memory.c 2004-02-18 09:51:40.000000000 -0700 @@ -306,12 +306,44 @@ return NULL; } + if (dev->agp->cant_use_aperture) { + drm_map_t *map = NULL; + int i; + + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (!map) continue; + if (map->offset <= offset && + (map->offset + map->size) >= (offset + size)) + break; + } + + if (map && map->type == _DRM_AGP) { + struct drm_agp_mem *agpmem; + + for (agpmem = dev->agp->memory; agpmem; + agpmem = agpmem->next) { + if(agpmem->bound <= offset && + (agpmem->bound + (agpmem->pages + << PAGE_SHIFT)) >= (offset + size)) + break; + } + + if (agpmem) { + pt = agpmem->memory->vmptr + (offset - agpmem->bound); + goto ioremap_success; + } + } + } + if (!(pt = ioremap(offset, size))) { spin_lock(&drm_mem_lock); ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count; spin_unlock(&drm_mem_lock); return NULL; } + +ioremap_success: spin_lock(&drm_mem_lock); ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count; drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; @@ -327,7 +359,7 @@ if (!pt) DRM_MEM_ERROR(DRM_MEM_MAPPINGS, "Attempt to free NULL pointer\n"); - else + else if (dev->agp->cant_use_aperture == 0) iounmap(pt); spin_lock(&drm_mem_lock); diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/mga_dma.c linux-ia64-2.4/drivers/char/drm-4.0/mga_dma.c --- linux-2.4.25/drivers/char/drm-4.0/mga_dma.c 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/mga_dma.c 2004-02-18 09:51:24.000000000 -0700 @@ -741,10 +741,18 @@ return -ENOMEM; } - /* Write status page when secend or softrap occurs */ + /* Write status page when secend or softrap occurs + * + * Disable this on ia64 on the off chance that real status page will be + * above 4GB. + */ +#if defined(__ia64__) + MGA_WRITE(MGAREG_PRIMPTR, + virt_to_bus((void *)dev_priv->real_status_page)); +#else MGA_WRITE(MGAREG_PRIMPTR, virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); - +#endif /* Private is now filled in, initialize the hardware */ { diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/mga_drv.h linux-ia64-2.4/drivers/char/drm-4.0/mga_drv.h --- linux-2.4.25/drivers/char/drm-4.0/mga_drv.h 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/mga_drv.h 2004-02-18 09:51:20.000000000 -0700 @@ -295,7 +295,7 @@ num_dwords + 1 + outcount, ADRINDEX(reg), val); \ if( ++outcount == 4) { \ outcount = 0; \ - dma_ptr[0] = *(unsigned long *)tempIndex; \ + dma_ptr[0] = *(u32 *)tempIndex; \ dma_ptr+=5; \ num_dwords += 5; \ } \ diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/r128_cce.c linux-ia64-2.4/drivers/char/drm-4.0/r128_cce.c --- linux-2.4.25/drivers/char/drm-4.0/r128_cce.c 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/r128_cce.c 2004-02-18 09:51:25.000000000 -0700 @@ -229,7 +229,21 @@ int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { +#ifndef CONFIG_AGP_I460 if ( *dev_priv->ring.head == dev_priv->ring.tail ) { +#else + /* + * XXX - this is (I think) a 460GX specific hack + * + * When doing texturing, ring.tail sometimes gets ahead of + * PM4_BUFFER_DL_WPTR by 2; consequently, the card processes + * its whole quota of instructions and *ring.head is still 2 + * short of ring.tail. Work around this for now in lieu of + * a better solution. + */ + if ( (*dev_priv->ring.head == dev_priv->ring.tail) || + ((dev_priv->ring.tail - *dev_priv->ring.head) == 2) ) { +#endif int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -330,7 +344,7 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev ) { drm_r128_private_t *dev_priv = dev->dev_private; - u32 ring_start; + u32 ring_start, rptr_addr; u32 tmp; /* The manual (p. 2) says this address is in "VM space". This @@ -342,10 +356,27 @@ R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); + /* + * 460GX doesn't claim PCI writes from the card into the AGP + * aperture, so we have to get space outside the aperture for + * RPTR_ADDR. + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + rptr_addr = __pa( dev_priv->ring.head ); + } else { + rptr_addr = dev_priv->ring_rptr->offset; + } + /* DL_RPTR_ADDR is a physical address in AGP space. */ *dev_priv->ring.head = 0; - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, rptr_addr ); /* Set watermark control */ R128_WRITE( R128_PM4_BUFFER_WM_CNTL, @@ -530,6 +561,19 @@ } #endif + /* + * Free the page we grabbed for RPTR_ADDR + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + + atomic_dec(&virt_to_page(alt_rh_off)->count); + clear_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + wake_up(&virt_to_page(alt_rh_off)->wait); + free_page(alt_rh_off); + } + drm_free( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/radeon_cp.c linux-ia64-2.4/drivers/char/drm-4.0/radeon_cp.c --- linux-2.4.25/drivers/char/drm-4.0/radeon_cp.c 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/radeon_cp.c 2004-02-18 09:51:30.000000000 -0700 @@ -569,7 +569,7 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = dev->dev_private; - u32 ring_start, cur_read_ptr; + u32 ring_start, cur_read_ptr, rptr_addr; u32 tmp; /* Initialize the memory controller */ @@ -592,10 +592,29 @@ /* Initialize the ring buffer's read and write pointers */ cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); + *dev_priv->ring.head = cur_read_ptr; dev_priv->ring.tail = cur_read_ptr; - RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset ); + /* + * 460GX doesn't claim PCI writes from the card into the AGP + * aperture, so we have to get space outside the aperture for + * RPTR_ADDR. + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off; + + alt_rh_off = __get_free_page(GFP_KERNEL | GFP_DMA); + atomic_inc(&virt_to_page(alt_rh_off)->count); + set_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + + dev_priv->ring.head = (__volatile__ u32 *) alt_rh_off; + *dev_priv->ring.head = cur_read_ptr; + rptr_addr = __pa( dev_priv->ring.head ); + } else + rptr_addr = dev_priv->ring_rptr->offset; + + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, rptr_addr); /* Set ring buffer size */ RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw ); @@ -837,6 +856,19 @@ } #endif + /* + * Free the page we grabbed for RPTR_ADDR. + */ + if ( dev->agp->agp_info.chipset == INTEL_460GX ) { + unsigned long alt_rh_off = + (unsigned long) dev_priv->ring.head; + + atomic_dec(&virt_to_page(alt_rh_off)->count); + clear_bit(PG_locked, &virt_to_page(alt_rh_off)->flags); + wake_up(&virt_to_page(alt_rh_off)->wait); + free_page(alt_rh_off); + } + drm_free( dev->dev_private, sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/radeon_drv.h linux-ia64-2.4/drivers/char/drm-4.0/radeon_drv.h --- linux-2.4.25/drivers/char/drm-4.0/radeon_drv.h 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/radeon_drv.h 2004-02-18 09:51:25.000000000 -0700 @@ -535,7 +535,7 @@ #define RADEON_MAX_VB_VERTS (0xffff) -#define RADEON_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) #define RADEON_ADDR(reg) (RADEON_BASE(reg) + reg) #define RADEON_DEREF(reg) *(__volatile__ u32 *)RADEON_ADDR(reg) diff -u -Nur linux-2.4.25/drivers/char/drm-4.0/vm.c linux-ia64-2.4/drivers/char/drm-4.0/vm.c --- linux-2.4.25/drivers/char/drm-4.0/vm.c 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/drivers/char/drm-4.0/vm.c 2004-02-18 09:51:22.000000000 -0700 @@ -30,6 +30,7 @@ */ #define __NO_VERSION__ +#include #include "drmP.h" struct vm_operations_struct drm_vm_ops = { @@ -67,7 +68,56 @@ int write_access) #endif { - return NOPAGE_SIGBUS; /* Disallow mremap */ + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + int i; + + if (!dev->agp->cant_use_aperture) + return NOPAGE_SIGBUS; /* Disallow mremap */ + + /* + * Find the right map + */ + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + if (!map) continue; + if (map->offset == VM_OFFSET(vma)) break; + } + + if (map && map->type == _DRM_AGP) { + unsigned long offset = address - vma->vm_start; + unsigned long baddr = VM_OFFSET(vma) + offset, paddr; + struct drm_agp_mem *agpmem; + struct page *page; + + /* + * It's AGP memory - find the real physical page to map + */ + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= baddr && + agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) + break; + } + + if (!agpmem) + return NOPAGE_SIGBUS; + + /* + * Get the page, inc the use count, and return it + */ + offset = (baddr - agpmem->bound) >> PAGE_SHIFT; + paddr = agpmem->memory->memory[offset]; + page = virt_to_page(__va(paddr)); + get_page(page); + +#if LINUX_VERSION_CODE < 0x020317 + return page_address(page); +#else + return page; +#endif + } + return NOPAGE_SIGBUS; } #if LINUX_VERSION_CODE < 0x020317 @@ -272,6 +322,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; + unsigned long off; int i; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", @@ -288,7 +339,16 @@ bit longer. */ for (i = 0; i < dev->map_count; i++) { map = dev->maplist[i]; - if (map->offset == VM_OFFSET(vma)) break; + off = map->offset ^ VM_OFFSET(vma); +#ifdef __ia64__ + /* + * Ignore region bits, makes IA32 processes happier + * XXX This is a hack... + */ + off &= ~0xe000000000000000; +#endif + if (off == 0) + break; } if (i >= dev->map_count) return -EINVAL; @@ -312,9 +372,19 @@ } switch (map->type) { + case _DRM_AGP: + if (dev->agp->cant_use_aperture) { + /* + * On some systems we can't talk to bus dma address from + * the CPU, so for memory of type DRM_AGP, we'll deal + * with sorting out the real physical pages and mappings + * in nopage() + */ + vma->vm_ops = &drm_vm_ops; + break; + } case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - case _DRM_AGP: if (VM_OFFSET(vma) >= __pa(high_memory)) { #if defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { diff -u -Nur linux-2.4.25/drivers/char/mem.c linux-ia64-2.4/drivers/char/mem.c --- linux-2.4.25/drivers/char/mem.c 2004-02-18 09:52:35.000000000 -0700 +++ linux-ia64-2.4/drivers/char/mem.c 2004-02-18 09:51:23.000000000 -0700 @@ -27,6 +27,10 @@ #include #include +#ifdef CONFIG_IA64 +# include +#endif + #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif @@ -42,7 +46,46 @@ #if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR) extern void tapechar_init(void); #endif - + +/* + * Architectures vary in how they handle caching for addresses + * outside of main memory. + * + */ +static inline int uncached_access(struct file *file, unsigned long addr) +{ +#if defined(__i386__) + /* + * On the PPro and successors, the MTRRs are used to set + * memory types for physical addresses outside main memory, + * so blindly setting PCD or PWT on those pages is wrong. + * For Pentiums and earlier, the surround logic should disable + * caching for the high addresses through the KEN pin, but + * we maintain the tradition of paranoia in this code. + */ + if (file->f_flags & O_SYNC) + return 1; + return !( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) || + test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) || + test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) || + test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) ) + && addr >= __pa(high_memory); +#elif defined(CONFIG_IA64) + /* + * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. + */ + return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); +#else + /* + * Accessing memory above the top the kernel knows about or through a file pointer + * that was marked O_SYNC will be done non-cached. + */ + if (file->f_flags & O_SYNC) + return 1; + return addr >= __pa(high_memory); +#endif +} + static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) { @@ -79,7 +122,7 @@ unsigned long p = *ppos; unsigned long end_mem; ssize_t read; - + end_mem = __pa(high_memory); if (p >= end_mem) return 0; @@ -123,77 +166,16 @@ return do_write_mem(file, __va(p), p, buf, count, ppos); } -#ifndef pgprot_noncached - -/* - * This should probably be per-architecture in - */ -static inline pgprot_t pgprot_noncached(pgprot_t _prot) -{ - unsigned long prot = pgprot_val(_prot); - -#if defined(__i386__) || defined(__x86_64__) - /* On PPro and successors, PCD alone doesn't always mean - uncached because of interactions with the MTRRs. PCD | PWT - means definitely uncached. */ - if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD | _PAGE_PWT; -#elif defined(__powerpc__) - prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; -#elif defined(__mc68000__) -#ifdef SUN3_PAGE_NOCACHE - if (MMU_IS_SUN3) - prot |= SUN3_PAGE_NOCACHE; - else -#endif - if (MMU_IS_851 || MMU_IS_030) - prot |= _PAGE_NOCACHE030; - /* Use no-cache mode, serialized */ - else if (MMU_IS_040 || MMU_IS_060) - prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S; -#endif - - return __pgprot(prot); -} - -#endif /* !pgprot_noncached */ - -/* - * Architectures vary in how they handle caching for addresses - * outside of main memory. - */ -static inline int noncached_address(unsigned long addr) -{ -#if defined(__i386__) - /* - * On the PPro and successors, the MTRRs are used to set - * memory types for physical addresses outside main memory, - * so blindly setting PCD or PWT on those pages is wrong. - * For Pentiums and earlier, the surround logic should disable - * caching for the high addresses through the KEN pin, but - * we maintain the tradition of paranoia in this code. - */ - return !( test_bit(X86_FEATURE_MTRR, &boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_K6_MTRR, &boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CYRIX_ARR, &boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CENTAUR_MCR, &boot_cpu_data.x86_capability) ) - && addr >= __pa(high_memory); -#else - return addr >= __pa(high_memory); -#endif -} - static int mmap_mem(struct file * file, struct vm_area_struct * vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int uncached; - /* - * Accessing memory above the top the kernel knows about or - * through a file pointer that was marked O_SYNC will be - * done non-cached. - */ - if (noncached_address(offset) || (file->f_flags & O_SYNC)) + uncached = uncached_access(file, offset); +#ifdef pgprot_noncached + if (uncached) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif /* Don't try to swap out physical pages.. */ vma->vm_flags |= VM_RESERVED; @@ -201,7 +183,7 @@ /* * Don't dump addresses that are not real memory to a core file. */ - if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) + if (uncached) vma->vm_flags |= VM_IO; if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, @@ -512,11 +494,13 @@ ret = file->f_pos; force_successful_syscall_return(); break; + case 1: file->f_pos += offset; ret = file->f_pos; force_successful_syscall_return(); break; + default: ret = -EINVAL; } @@ -581,6 +565,7 @@ { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long size = vma->vm_end - vma->vm_start; + int uncached; /* * If the user is not attempting to mmap a high memory address then @@ -591,13 +576,11 @@ if ((offset + size) < (unsigned long) high_memory) return mmap_mem(file, vma); - /* - * Accessing memory above the top the kernel knows about or - * through a file pointer that was marked O_SYNC will be - * done non-cached. - */ - if (noncached_address(offset) || (file->f_flags & O_SYNC)) + uncached = uncached_access(file, offset); +#ifdef pgprot_noncached + if (uncached) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif /* Don't do anything here; "nopage" will fill the holes */ vma->vm_ops = &kmem_vm_ops; @@ -608,7 +591,8 @@ /* * Don't dump addresses that are not real memory to a core file. */ - vma->vm_flags |= VM_IO; + if (uncached) + vma->vm_flags |= VM_IO; return 0; } diff -u -Nur linux-2.4.25/drivers/char/serial.c linux-ia64-2.4/drivers/char/serial.c --- linux-2.4.25/drivers/char/serial.c 2004-02-18 09:52:28.000000000 -0700 +++ linux-ia64-2.4/drivers/char/serial.c 2004-02-18 09:51:19.000000000 -0700 @@ -92,9 +92,8 @@ * ever possible. * * CONFIG_SERIAL_ACPI - * Enable support for serial console port and serial - * debug port as defined by the SPCR and DBGP tables in - * ACPI 2.0. + * Enable support for serial ports found in the ACPI + * namespace. */ #include @@ -222,6 +221,10 @@ #ifdef CONFIG_MAGIC_SYSRQ #include #endif +#ifdef ENABLE_SERIAL_ACPI +#include +#include +#endif /* * All of the compatibilty code so we can compile serial.c against @@ -257,6 +260,10 @@ static struct timer_list serial_timer; +#define HP_DIVA_CHECKTIME (1*HZ) +static struct timer_list hp_diva_timer; +static int hp_diva_count = 0; + /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL #define SERIAL_TYPE_NORMAL 1 @@ -793,6 +800,41 @@ } #ifdef CONFIG_SERIAL_SHARE_IRQ +static inline int is_hp_diva_info(struct async_struct *info) +{ + struct pci_dev *dev = info->state->dev; + return (dev && dev->vendor == PCI_VENDOR_ID_HP && + dev->device == PCI_DEVICE_ID_HP_SAS); +} + +static inline int is_hp_diva_irq(int irq) +{ + struct async_struct *info = IRQ_ports[irq]; + return (info && is_hp_diva_info(info)); +} + +/* + * It is possible to "use up" transmit empty interrupts in some + * cases with HP Diva cards. Figure out if there _should_ be a + * transmit interrupt and if so, return a suitable iir value so + * that we can recover when called from rs_timer(). + */ +static inline int hp_diva_iir(int irq, struct async_struct *info) +{ + int iir = serial_in(info, UART_IIR); + + if (is_hp_diva_info(info) && + (iir & UART_IIR_NO_INT) != 0 && + (info->IER & UART_IER_THRI) != 0 && + (info->xmit.head != info->xmit.tail || info->x_char) && + (serial_in(info, UART_LSR) & UART_LSR_THRE) != 0) { + iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); + iir |= UART_IIR_THRI; + } + + return iir; +} + /* * This is the serial driver's generic interrupt routine */ @@ -823,7 +865,7 @@ do { if (!info->tty || - ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { + ((iir=hp_diva_iir(irq, info)) & UART_IIR_NO_INT)) { if (!end_mark) end_mark = info; goto next; @@ -1097,9 +1139,11 @@ #ifdef CONFIG_SERIAL_SHARE_IRQ if (info->next_port) { do { - serial_out(info, UART_IER, 0); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); + if (!is_hp_diva_info(info)) { + serial_out(info, UART_IER, 0); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } info = info->next_port; } while (info); #ifdef CONFIG_SERIAL_MULTIPORT @@ -1131,6 +1175,35 @@ } /* + * This subroutine is called when the hp_diva_timer goes off. In + * certain cases (multiple gettys in particular) Diva seems to issue + * only a single transmit empty interrupt instead of one each time + * THRI is enabled, causing interrupts to be "used up". This serves + * to poll the Diva UARTS more frequently than rs_timer() does. + */ +static void hp_diva_check(unsigned long dummy) +{ +#ifdef CONFIG_SERIAL_SHARE_IRQ + static unsigned long last_strobe; + unsigned long flags; + int i; + + if (time_after_eq(jiffies, last_strobe + HP_DIVA_CHECKTIME)) { + for (i = 0; i < NR_IRQS; i++) { + if (is_hp_diva_irq(i)) { + save_flags(flags); cli(); + rs_interrupt(i, NULL, NULL); + restore_flags(flags); + } + } + } + last_strobe = jiffies; + mod_timer(&hp_diva_timer, jiffies + HP_DIVA_CHECKTIME); +#endif +} + + +/* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver: routines to * figure out the appropriate timeout for an interrupt chain, routines @@ -4294,6 +4367,12 @@ break; } + if (hp_diva_count++ == 0) { + init_timer(&hp_diva_timer); + hp_diva_timer.function = hp_diva_check; + mod_timer(&hp_diva_timer, jiffies + HP_DIVA_CHECKTIME); + } + return 0; } @@ -4597,6 +4676,129 @@ } } +#ifdef ENABLE_SERIAL_ACPI +static acpi_status acpi_serial_address(struct serial_struct *req, + struct acpi_resource_address64 *addr) +{ + unsigned long size; + + size = addr->max_address_range - addr->min_address_range + 1; + req->iomem_base = ioremap(addr->min_address_range, size); + if (!req->iomem_base) { + printk("%s: couldn't ioremap 0x%lx-0x%lx\n", __FUNCTION__, + addr->min_address_range, addr->max_address_range); + return AE_ERROR; + } + req->io_type = SERIAL_IO_MEM; + return AE_OK; +} + +static acpi_status acpi_serial_ext_irq(struct serial_struct *req, + struct acpi_resource_ext_irq *ext_irq) +{ + if (ext_irq->number_of_interrupts > 0) { +#ifdef CONFIG_IA64 + req->irq = acpi_register_irq(ext_irq->interrupts[0], + ext_irq->active_high_low, ext_irq->edge_level); +#else + req->irq = ext_irq->interrupts[0]; +#endif + } + return AE_OK; +} + +static acpi_status acpi_serial_port(struct serial_struct *req, + struct acpi_resource_io *io) +{ + req->port = io->min_base_address; + req->io_type = SERIAL_IO_PORT; + return AE_OK; +} + +static acpi_status acpi_serial_irq(struct serial_struct *req, + struct acpi_resource_irq *irq) +{ + if (irq->number_of_interrupts > 0) { +#ifdef CONFIG_IA64 + req->irq = acpi_register_irq(irq->interrupts[0], + irq->active_high_low, irq->edge_level); +#else + req->irq = irq->interrupts[0]; +#endif + } + return AE_OK; +} + +static acpi_status acpi_serial_resource(struct acpi_resource *res, void *data) +{ + struct serial_struct *serial_req = (struct serial_struct *) data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = acpi_resource_to_address64(res, &addr); + if (ACPI_SUCCESS(status)) + return acpi_serial_address(serial_req, &addr); + else if (res->id == ACPI_RSTYPE_EXT_IRQ) + return acpi_serial_ext_irq(serial_req, &res->data.extended_irq); + else if (res->id == ACPI_RSTYPE_IO) + return acpi_serial_port(serial_req, &res->data.io); + else if (res->id == ACPI_RSTYPE_IRQ) + return acpi_serial_irq(serial_req, &res->data.irq); + return AE_OK; +} + +static int acpi_serial_add(struct acpi_device *device) +{ + acpi_status status; + struct serial_struct serial_req; + int line; + + memset(&serial_req, 0, sizeof(serial_req)); + + status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + acpi_serial_resource, &serial_req); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (!serial_req.iomem_base && !serial_req.port) { + printk("%s: no iomem or port address in %s _CRS\n", __FUNCTION__, + device->pnp.bus_id); + return -ENODEV; + } + + serial_req.baud_base = BASE_BAUD; + serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ; + serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; + serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; + serial_req.iomem_reg_shift = 0; + + line = register_serial(&serial_req); + if (line < 0) + return -ENODEV; + + return 0; +} + +static int acpi_serial_remove(struct acpi_device *device, int type) +{ + return 0; +} + +static struct acpi_driver acpi_serial_driver = { + .name = "serial", + .class = "", + .ids = "PNP0501", + .ops = { + .add = acpi_serial_add, + .remove = acpi_serial_remove, + }, +}; + +static void __devinit probe_serial_acpi(void) +{ + acpi_bus_register_driver(&acpi_serial_driver); +} +#endif /* ENABLE_SERIAL_ACPI */ static struct pci_device_id serial_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, @@ -5558,6 +5760,9 @@ tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); } +#ifdef ENABLE_SERIAL_ACPI + probe_serial_acpi(); +#endif #ifdef ENABLE_SERIAL_PCI probe_serial_pci(); #endif @@ -5735,6 +5940,8 @@ /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ del_timer_sync(&serial_timer); + if (hp_diva_count > 0) + del_timer_sync(&hp_diva_timer); save_flags(flags); cli(); remove_bh(SERIAL_BH); if ((e1 = tty_unregister_driver(&serial_driver))) diff -u -Nur linux-2.4.25/drivers/net/tulip/media.c linux-ia64-2.4/drivers/net/tulip/media.c --- linux-2.4.25/drivers/net/tulip/media.c 2004-02-18 09:52:26.000000000 -0700 +++ linux-ia64-2.4/drivers/net/tulip/media.c 2004-02-18 09:51:19.000000000 -0700 @@ -284,6 +284,10 @@ for (i = 0; i < init_length; i++) outl(init_sequence[i], ioaddr + CSR12); } + + (void) inl(ioaddr + CSR6); /* flush CSR12 writes */ + udelay(500); /* Give MII time to recover */ + tmp_info = get_u16(&misc_info[1]); if (tmp_info) tp->advertising[phy_num] = tmp_info | 1; diff -u -Nur linux-2.4.25/drivers/pci/pci.c linux-ia64-2.4/drivers/pci/pci.c --- linux-2.4.25/drivers/pci/pci.c 2004-02-18 09:52:26.000000000 -0700 +++ linux-ia64-2.4/drivers/pci/pci.c 2004-02-18 09:51:19.000000000 -0700 @@ -1061,8 +1061,14 @@ { unsigned int pos, reg, next; u32 l, sz; + u16 cmd; struct resource *res; + /* Disable I/O & memory decoding while we size the BARs. */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); + for(pos=0; posresource[pos]; @@ -1127,13 +1133,16 @@ if (sz && sz != 0xffffffff) { sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK); if (!sz) - return; + goto out; res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; res->end = res->start + (unsigned long) sz; } } + +out: + pci_write_config_word(dev, PCI_COMMAND, cmd); } void __devinit pci_read_bridge_bases(struct pci_bus *child) @@ -2066,16 +2075,16 @@ int map, block; if ((page = pool_find_page (pool, dma)) == 0) { - printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n", + printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, (unsigned long) dma); return; } #ifdef CONFIG_PCIPOOL_DEBUG if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n", + printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n", pool->dev ? pool->dev->slot_name : NULL, - pool->name, vaddr, (int) (dma & 0xffffffff)); + pool->name, vaddr, (unsigned long) dma); return; } #endif diff -u -Nur linux-2.4.25/drivers/scsi/megaraid.c linux-ia64-2.4/drivers/scsi/megaraid.c --- linux-2.4.25/drivers/scsi/megaraid.c 2004-02-18 09:52:05.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/megaraid.c 2004-02-18 09:51:03.000000000 -0700 @@ -2234,9 +2234,6 @@ #if DEBUG -static unsigned int cum_time = 0; -static unsigned int cum_time_cnt = 0; - static void showMbox (mega_scb * pScb) { mega_mailbox *mbox; @@ -2245,7 +2242,7 @@ return; mbox = (mega_mailbox *) pScb->mboxData; - printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", + printk ("%lu cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", pScb->SCpnt->pid, mbox->cmd, mbox->cmdid, mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements); @@ -3569,10 +3566,14 @@ mbox[0] = IS_BIOS_ENABLED; mbox[2] = GET_BIOS; - mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer); + mboxpnt->xferaddr = pci_map_single(megacfg->dev, + (void *) megacfg->mega_buffer, (2 * 1024L), + PCI_DMA_FROMDEVICE); ret = megaIssueCmd (megacfg, mbox, NULL, 0); + pci_unmap_single(megacfg->dev, mboxpnt->xferaddr, 2 * 1024L, PCI_DMA_FROMDEVICE); + return (*(char *) megacfg->mega_buffer); } diff -u -Nur linux-2.4.25/drivers/scsi/qla1280.c linux-ia64-2.4/drivers/scsi/qla1280.c --- linux-2.4.25/drivers/scsi/qla1280.c 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/qla1280.c 2004-02-18 09:51:42.000000000 -0700 @@ -2112,7 +2112,7 @@ ha->flags.abort_isp_active = 0; ha->flags.ints_enabled = 0; -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) +#if defined(CONFIG_IA64_SGI_SN2) if (ia64_platform_is("sn2")) { int count1, count2; int c; diff -u -Nur linux-2.4.25/drivers/scsi/scsi_dma.c linux-ia64-2.4/drivers/scsi/scsi_dma.c --- linux-2.4.25/drivers/scsi/scsi_dma.c 2004-02-18 09:52:36.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/scsi_dma.c 2004-02-18 09:51:23.000000000 -0700 @@ -30,8 +30,69 @@ typedef unsigned char FreeSectorBitmap; #elif SECTORS_PER_PAGE <= 32 typedef unsigned int FreeSectorBitmap; -#else -#error You lose. +#elif SECTORS_PER_PAGE <= 64 +typedef u64 FreeSectorBitmap; +#elif SECTORS_PER_PAGE <= 128 + +typedef struct { + u64 hi, lo; +} FreeSectorBitmap; + +/* No side effects on MAP-macro-arguments, please... */ + +#define MAP_MAKE_MASK(m, nbits) \ +do { \ + if ((nbits) >= 64) { \ + (m).hi = ((u64) 1 << ((nbits) - 64)) - 1; \ + (m).lo = ~(u64) 0; \ + } else { \ + (m).hi = 0; \ + (m).lo = ((u64) 1 << (nbits)) - 1; \ + } \ +} while (0) + +#define MAP_SHIFT_LEFT(m, count) \ +do { \ + if ((count) >= 64) { \ + (m).hi = (m).lo << ((count) - 64); \ + (m).lo = 0; \ + } else { \ + (m).hi = ((m).hi << (count)) | ((m).lo >> (64 - (count))); \ + (m).lo <<= count; \ + } \ +} while (0) + +#define MAP_AND(r, left, right) \ +do { \ + (r).hi = (left).hi & (right).hi; \ + (r).lo = (left).lo & (right).lo; \ +} while (0) + +#define MAP_SET(r, mask) \ +do { \ + (r).hi |= (mask).hi; \ + (r).lo |= (mask).lo; \ +} while (0) + +#define MAP_CLEAR(r, mask) \ +do { \ + (r).hi &= ~(mask).hi; \ + (r).lo &= ~(mask).lo; \ +} while (0) + +#define MAP_EQUAL(left, right) (((left.hi ^ right.hi) | (left.lo ^ right.lo)) == 0) +#define MAP_EMPTY(m) ((m.lo | m.hi) == 0) + +#endif + +#ifndef MAP_MAKE_MASK +# define MAP_MAKE_MASK(m,nbits) ((m) = (((u64) 1 << (nbits)) - 1)) +# define MAP_SHIFT_LEFT(m,nbits) ((m) <<= (nbits)) +# define MAP_AND(res,l,r) ((res) = (l) & (r)) +# define MAP_EQUAL(l,r) ((l) == (r)) +# define MAP_EMPTY(m) ((m) == 0) +# define MAP_CLEAR(m, bits) ((m) &= ~(bits)) +# define MAP_SET(m, bits) ((m) |= (bits)) #endif /* @@ -71,7 +132,8 @@ */ void *scsi_malloc(unsigned int len) { - unsigned int nbits, mask; + FreeSectorBitmap mask, busy_sectors, result; + unsigned int nbits; unsigned long flags; int i, j; @@ -79,23 +141,29 @@ return NULL; nbits = len >> 9; - mask = (1 << nbits) - 1; spin_lock_irqsave(&allocator_request_lock, flags); - for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) + for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) { + MAP_MAKE_MASK(mask, nbits); + busy_sectors = dma_malloc_freelist[i]; for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) { - if ((dma_malloc_freelist[i] & (mask << j)) == 0) { - dma_malloc_freelist[i] |= (mask << j); + MAP_AND(result, busy_sectors, mask); + if (MAP_EMPTY(result)) { + MAP_SET(dma_malloc_freelist[i], mask); scsi_dma_free_sectors -= nbits; #ifdef DEBUG - SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9))); - printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)); + SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p\n", + len, dma_malloc_pages[i] + (j << 9))); + printk("SMalloc: %d %p\n", + len, dma_malloc_pages[i] + (j << 9)); #endif spin_unlock_irqrestore(&allocator_request_lock, flags); return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); } + MAP_SHIFT_LEFT(mask, 1); } + } spin_unlock_irqrestore(&allocator_request_lock, flags); return NULL; /* Nope. No more */ } @@ -121,7 +189,8 @@ */ int scsi_free(void *obj, unsigned int len) { - unsigned int page, sector, nbits, mask; + FreeSectorBitmap mask, result; + unsigned int page, sector, nbits; unsigned long flags; #ifdef DEBUG @@ -145,13 +214,14 @@ sector = (((unsigned long) obj) - page_addr) >> 9; nbits = len >> 9; - mask = (1 << nbits) - 1; + MAP_MAKE_MASK(mask, nbits); if (sector + nbits > SECTORS_PER_PAGE) panic("scsi_free:Bad memory alignment"); - if ((dma_malloc_freelist[page] & - (mask << sector)) != (mask << sector)) { + MAP_SHIFT_LEFT(mask, sector); + MAP_AND(result, mask, dma_malloc_freelist[page]); + if (!MAP_EQUAL(result, mask)) { #ifdef DEBUG printk("scsi_free(obj=%p, len=%d) called from %08lx\n", obj, len, ret); @@ -159,7 +229,7 @@ panic("scsi_free:Trying to free unused memory"); } scsi_dma_free_sectors += nbits; - dma_malloc_freelist[page] &= ~(mask << sector); + MAP_CLEAR(dma_malloc_freelist[page], mask); spin_unlock_irqrestore(&allocator_request_lock, flags); return 0; } diff -u -Nur linux-2.4.25/drivers/scsi/scsi_ioctl.c linux-ia64-2.4/drivers/scsi/scsi_ioctl.c --- linux-2.4.25/drivers/scsi/scsi_ioctl.c 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/scsi_ioctl.c 2004-02-18 09:51:41.000000000 -0700 @@ -198,6 +198,9 @@ unsigned int needed, buf_needed; int timeout, retries, result; int data_direction; +#if __GNUC__ < 3 + int foo; +#endif if (!sic) return -EINVAL; @@ -207,12 +210,21 @@ if (verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) return -EFAULT; - if(__get_user(inlen, &sic->inlen)) +#if __GNUC__ < 3 + foo = __get_user(inlen, &sic->inlen); + if(foo) return -EFAULT; - if(__get_user(outlen, &sic->outlen)) + foo = __get_user(outlen, &sic->outlen); + if(foo) + return -EFAULT; +#else + if(__get_user(inlen, &sic->inlen)) return -EFAULT; + if(__get_user(outlen, &sic->outlen)) + return -EFAULT; +#endif /* * We do not transfer more than MAX_BUF with this interface. * If the user needs to transfer more data than this, they diff -u -Nur linux-2.4.25/drivers/scsi/scsi_merge.c linux-ia64-2.4/drivers/scsi/scsi_merge.c --- linux-2.4.25/drivers/scsi/scsi_merge.c 2004-02-18 09:52:41.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/scsi_merge.c 2004-02-18 09:51:41.000000000 -0700 @@ -1155,7 +1155,7 @@ { struct Scsi_Host *SHpnt = SDpnt->host; request_queue_t *q = &SDpnt->request_queue; - dma64_addr_t bounce_limit; + u64 bounce_limit; /* * If this host has an unlimited tablesize, then don't bother with a diff -u -Nur linux-2.4.25/drivers/scsi/sym53c8xx.c linux-ia64-2.4/drivers/scsi/sym53c8xx.c --- linux-2.4.25/drivers/scsi/sym53c8xx.c 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/sym53c8xx.c 2004-02-18 09:51:26.000000000 -0700 @@ -12966,6 +12966,7 @@ } if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ continue; +#ifdef CONFIG_X86 /* Some HW as the HP LH4 may report twice PCI devices */ for (i = 0; i < count ; i++) { if (devtbl[i].slot.bus == PciBusNumber(pcidev) && @@ -12974,6 +12975,7 @@ } if (i != count) /* Ignore this device if we already have it */ continue; +#endif devp = &devtbl[count]; devp->host_id = driver_setup.host_id; devp->attach_done = 0; diff -u -Nur linux-2.4.25/drivers/scsi/sym53c8xx_2/sym_glue.c linux-ia64-2.4/drivers/scsi/sym53c8xx_2/sym_glue.c --- linux-2.4.25/drivers/scsi/sym53c8xx_2/sym_glue.c 2004-02-18 09:52:55.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/sym53c8xx_2/sym_glue.c 2004-02-18 09:51:42.000000000 -0700 @@ -302,12 +302,8 @@ #ifndef SYM_LINUX_DYNAMIC_DMA_MAPPING typedef u_long bus_addr_t; #else -#if SYM_CONF_DMA_ADDRESSING_MODE > 0 -typedef dma64_addr_t bus_addr_t; -#else typedef dma_addr_t bus_addr_t; #endif -#endif /* * Used by the eh thread to wait for command completion. @@ -2803,6 +2799,7 @@ /* This one is guaranteed by AC to do nothing :-) */ if (pci_enable_device(pcidev)) continue; +#ifdef CONFIG_X86 /* Some HW as the HP LH4 may report twice PCI devices */ for (i = 0; i < count ; i++) { if (devtbl[i].s.bus == PciBusNumber(pcidev) && @@ -2811,6 +2808,7 @@ } if (i != count) /* Ignore this device if we already have it */ continue; +#endif devp = &devtbl[count]; devp->host_id = SYM_SETUP_HOST_ID; devp->attach_done = 0; diff -u -Nur linux-2.4.25/drivers/scsi/sym53c8xx_comm.h linux-ia64-2.4/drivers/scsi/sym53c8xx_comm.h --- linux-2.4.25/drivers/scsi/sym53c8xx_comm.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/drivers/scsi/sym53c8xx_comm.h 2004-02-18 09:51:03.000000000 -0700 @@ -2579,6 +2579,7 @@ } if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */ continue; +#ifdef CONFIG_X86 /* Some HW as the HP LH4 may report twice PCI devices */ for (i = 0; i < count ; i++) { if (devtbl[i].slot.bus == PciBusNumber(pcidev) && @@ -2587,6 +2588,7 @@ } if (i != count) /* Ignore this device if we already have it */ continue; +#endif devp = &devtbl[count]; devp->host_id = driver_setup.host_id; devp->attach_done = 0; diff -u -Nur linux-2.4.25/fs/Config.in linux-ia64-2.4/fs/Config.in --- linux-2.4.25/fs/Config.in 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/fs/Config.in 2004-02-18 09:51:26.000000000 -0700 @@ -54,6 +54,13 @@ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS define_bool CONFIG_RAMFS y +bool 'HugeTLB file system support' CONFIG_HUGETLBFS +if [ "$CONFIG_HUGETLBFS" = "y" ] ; then + define_bool CONFIG_HUGETLB_PAGE y +else + define_bool CONFIG_HUGETLB_PAGE n +fi + tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS dep_mbool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS dep_mbool ' Transparent decompression extension' CONFIG_ZISOFS $CONFIG_ISO9660_FS @@ -72,13 +79,17 @@ bool '/proc file system support' CONFIG_PROC_FS -# For some reason devfs corrupts memory badly on x86-64. Disable it -# for now. -if [ "$CONFIG_X86_64" != "y" ] ; then -dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL +if [ "$CONFIG_IA64_SGI_SN2" = "y" ] ; then + define_bool CONFIG_DEVFS_FS y +else + # For some reason devfs corrupts memory badly on x86-64. Disable it + # for now. + if [ "$CONFIG_X86_64" != "y" ] ; then + dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL + fi +fi dep_bool ' Automatically mount at boot' CONFIG_DEVFS_MOUNT $CONFIG_DEVFS_FS dep_bool ' Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS -fi # It compiles as a module for testing only. It should not be used # as a module in general. If we make this "tristate", a bunch of people diff -u -Nur linux-2.4.25/fs/Makefile linux-ia64-2.4/fs/Makefile --- linux-2.4.25/fs/Makefile 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/fs/Makefile 2004-02-18 09:51:24.000000000 -0700 @@ -28,6 +28,7 @@ subdir-$(CONFIG_EXT2_FS) += ext2 subdir-$(CONFIG_CRAMFS) += cramfs subdir-$(CONFIG_RAMFS) += ramfs +subdir-$(CONFIG_HUGETLBFS) += hugetlbfs subdir-$(CONFIG_CODA_FS) += coda subdir-$(CONFIG_INTERMEZZO_FS) += intermezzo subdir-$(CONFIG_MINIX_FS) += minix diff -u -Nur linux-2.4.25/fs/binfmt_misc.c linux-ia64-2.4/fs/binfmt_misc.c --- linux-2.4.25/fs/binfmt_misc.c 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/fs/binfmt_misc.c 2004-02-18 09:51:20.000000000 -0700 @@ -35,6 +35,7 @@ static int enabled = 1; enum {Enabled, Magic}; +#define MISC_FMT_PRESERVE_ARGV0 (1<<31) typedef struct { struct list_head list; @@ -121,7 +122,9 @@ bprm->file = NULL; /* Build args for interpreter */ - remove_arg_zero(bprm); + if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) { + remove_arg_zero(bprm); + } retval = copy_strings_kernel(1, &bprm->filename, bprm); if (retval < 0) goto _ret; bprm->argc++; @@ -287,6 +290,11 @@ if (!e->interpreter[0]) goto Einval; + if (*p == 'P') { + p++; + e->flags |= MISC_FMT_PRESERVE_ARGV0; + } + if (*p == '\n') p++; if (p != buf + count) diff -u -Nur linux-2.4.25/fs/hugetlbfs/Makefile linux-ia64-2.4/fs/hugetlbfs/Makefile --- linux-2.4.25/fs/hugetlbfs/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux-ia64-2.4/fs/hugetlbfs/Makefile 2004-02-18 09:51:06.000000000 -0700 @@ -0,0 +1,11 @@ +# +# Makefile for the linux hugetlbfs routines. +# + +O_TARGET := hugetlbfs.o + +obj-y := inode.o + +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u -Nur linux-2.4.25/fs/hugetlbfs/inode.c linux-ia64-2.4/fs/hugetlbfs/inode.c --- linux-2.4.25/fs/hugetlbfs/inode.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-ia64-2.4/fs/hugetlbfs/inode.c 2004-02-18 09:51:24.000000000 -0700 @@ -0,0 +1,762 @@ +/* + * hugetlbpage-backed filesystem. Based on ramfs. + * + * William Irwin, 2002 + * + * Copyright (C) 2002 Linus Torvalds. + * Backported from 2.5.48 11/19/2002 Rohit Seth + */ + +#include +#include +#include /* remove ASAP */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern struct list_head inode_unused; + +/* some random number */ +#define HUGETLBFS_MAGIC 0x958458f6 + +static struct super_operations hugetlbfs_ops; +static struct address_space_operations hugetlbfs_aops; +struct file_operations hugetlbfs_file_operations; +static struct inode_operations hugetlbfs_dir_inode_operations; +static struct inode_operations hugetlbfs_inode_operations; + +static inline int hugetlbfs_positive(struct dentry *dentry) +{ + return dentry->d_inode && ! d_unhashed(dentry); +} + +static int hugetlbfs_empty(struct dentry *dentry) +{ + struct list_head *list; + spin_lock (&dcache_lock); + list = dentry->d_subdirs.next; + while (list != &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (hugetlbfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; + } + list = list->next; + } + spin_unlock(&dcache_lock); + return 1; +} + +int hugetlbfs_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ + return 0; +} +static int hugetlbfs_statfs(struct super_block *sb, struct statfs *buf) +{ + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + if (sbinfo) { + spin_lock(&sbinfo->stat_lock); + buf->f_blocks = sbinfo->max_blocks; + buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; + buf->f_files = sbinfo->max_inodes; + buf->f_ffree = sbinfo->free_inodes; + spin_unlock(&sbinfo->stat_lock); + } + buf->f_type = HUGETLBFS_MAGIC; + buf->f_bsize = HPAGE_SIZE; + buf->f_namelen = NAME_MAX; + return 0; +} + +static int hugetlbfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) +{ + int error = - ENOTEMPTY; + + if (hugetlbfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); + } + old_dir->i_size -= PSEUDO_DIRENT_SIZE; + new_dir->i_size += PSEUDO_DIRENT_SIZE; + old_dir->i_ctime = old_dir->i_mtime = + new_dir->i_ctime = new_dir->i_mtime = + inode->i_ctime = CURRENT_TIME; + error = 0; + } + return error; +} +static int hugetlbfs_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + if (!hugetlbfs_empty(dentry)) + return -ENOTEMPTY; + dir->i_size -= PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dentry->d_inode->i_nlink--; + dput (dentry); + return 0; +} + +#define hugetlbfs_rmdir hugetlbfs_unlink + +static int hugetlbfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + if (S_ISDIR(inode->i_mode)) + return -EPERM; + dir->i_size += PSEUDO_DIRENT_SIZE; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; +} + +static struct dentry *hugetlbfs_lookup(struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + loff_t len, vma_len; + int ret; + + if (vma->vm_start & ~HPAGE_MASK) + return -EINVAL; + + if (vma->vm_end & ~HPAGE_MASK) + return -EINVAL; + + if (vma->vm_end - vma->vm_start < HPAGE_SIZE) + return -EINVAL; +#ifdef CONFIG_IA64 + if (vma->vm_start < (REGION_HPAGE << REGION_SHIFT)) + return -EINVAL; +#endif + vma_len = (loff_t)(vma->vm_end - vma->vm_start); + + down(&inode->i_sem); + + UPDATE_ATIME(inode); + vma->vm_flags |= VM_HUGETLB | VM_RESERVED; + vma->vm_ops = &hugetlb_vm_ops; + ret = hugetlb_prefault(mapping, vma); + len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); + if (ret == 0 && inode->i_size < len) + inode->i_size = len; + up(&inode->i_sem); + + return ret; +} + +/* + * Called under down_write(mmap_sem), page_table_lock is not held + */ + +#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA +unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags); +#else +static unsigned long +hugetlb_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + + if (len & ~HPAGE_MASK) + return -EINVAL; + if (len > TASK_SIZE) + return -ENOMEM; + + if (addr) { + addr = COLOR_HALIGN(addr); + vma = find_vma(mm, addr); + if (TASK_SIZE - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + addr = PAGE_ALIGN(TASK_UNMAPPED_BASE); + + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (TASK_SIZE - len < addr) + return -ENOMEM; + if (!vma || addr + len <= vma->vm_start) + return addr; + addr = COLOR_HALIGN(vma->vm_end); + } +} +#endif + +/* + * Read a page. Again trivial. If it didn't already exist + * in the page cache, it is zero-filled. + */ +static int hugetlbfs_readpage(struct file *file, struct page * page) +{ + return -EINVAL; +} + +static int hugetlbfs_prepare_write(struct file *file, + struct page *page, unsigned offset, unsigned to) +{ + return -EINVAL; +} + +static int hugetlbfs_commit_write(struct file *file, + struct page *page, unsigned offset, unsigned to) +{ + return -EINVAL; +} + +void truncate_huge_page(struct address_space *mapping, struct page *page) +{ + if (page->mapping != mapping) + return; + + ClearPageDirty(page); + ClearPageUptodate(page); + remove_inode_page(page); + set_page_count(page, 1); + huge_page_release(page); +} + +void truncate_hugepages(struct inode *inode, struct address_space *mapping, loff_t lstart) +{ + unsigned long start = lstart >> HPAGE_SHIFT; + unsigned long next; + unsigned long max_idx; + struct page *page; + + max_idx = inode->i_size >> HPAGE_SHIFT; + next = start; + while (next < max_idx) { + page = find_lock_page(mapping, next); + next++; + if (page == NULL) + continue; + page_cache_release(page); + truncate_huge_page(mapping, page); + unlock_page(page); + hugetlb_put_quota(mapping); + } +} + +static void hugetlbfs_delete_inode(struct inode *inode) +{ + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); + + list_del_init(&inode->i_hash); + list_del_init(&inode->i_list); + inode->i_state |= I_FREEING; + inodes_stat.nr_inodes--; + + if (inode->i_data.nrpages) + truncate_hugepages(inode, &inode->i_data, 0); + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } + +} + +static void hugetlbfs_forget_inode(struct inode *inode) +{ + struct super_block *super_block = inode->i_sb; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(super_block); + + if (list_empty(&inode->i_hash)) + goto out_truncate; + + if (!(inode->i_state & (I_DIRTY|I_LOCK))) { + list_del(&inode->i_list); + list_add(&inode->i_list, &inode_unused); + } + inodes_stat.nr_unused++; + if (!super_block || (super_block->s_flags & MS_ACTIVE)) { + return; + } + + /* write_inode_now() ? */ + inodes_stat.nr_unused--; + list_del_init(&inode->i_hash); +out_truncate: + list_del_init(&inode->i_list); + inode->i_state |= I_FREEING; + inodes_stat.nr_inodes--; + if (inode->i_data.nrpages) + truncate_hugepages(inode, &inode->i_data, 0); + + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_inodes++; + spin_unlock(&sbinfo->stat_lock); + } +} + +static void hugetlbfs_drop_inode(struct inode *inode) +{ + if (!inode->i_nlink) + hugetlbfs_delete_inode(inode); + else + hugetlbfs_forget_inode(inode); +} + +static void +hugetlb_vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff) +{ + + do { + unsigned long h_vm_pgoff; + unsigned long v_length; + unsigned long h_length; + unsigned long v_offset; + + h_vm_pgoff = mpnt->vm_pgoff << (HPAGE_SHIFT - PAGE_SHIFT); + v_length = mpnt->vm_end - mpnt->vm_start; + h_length = v_length >> HPAGE_SHIFT; + v_offset = (pgoff - h_vm_pgoff) << HPAGE_SHIFT; + + /* + * Is this VMA fully outside the truncation point? + */ + if (h_vm_pgoff >= pgoff) { + zap_hugepage_range(mpnt, mpnt->vm_start, v_length); + continue; + } + + /* + * Is this VMA fully inside the truncaton point? + */ + if (h_vm_pgoff + (v_length >> HPAGE_SHIFT) <= pgoff) + continue; + + /* + * The VMA straddles the truncation point. v_offset is the + * offset (in bytes) into the VMA where the point lies. + */ + zap_hugepage_range(mpnt, + mpnt->vm_start + v_offset, + v_length - v_offset); + } while ((mpnt = mpnt->vm_next_share) != NULL); +} + +/* + * Expanding truncates are not allowed. + */ +static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) +{ + unsigned long pgoff; + struct address_space *mapping = inode->i_mapping; + + if (offset > inode->i_size) + return -EINVAL; + + BUG_ON(offset & ~HPAGE_MASK); + pgoff = offset >> HPAGE_SHIFT; + + spin_lock(&mapping->i_shared_lock); + if (mapping->i_mmap != NULL) + hugetlb_vmtruncate_list(mapping->i_mmap, pgoff); + if (mapping->i_mmap_shared != NULL) + hugetlb_vmtruncate_list(mapping->i_mmap_shared, pgoff); + + spin_unlock(&mapping->i_shared_lock); + truncate_hugepages(inode, mapping, offset); + inode->i_size = offset; + return 0; +} + +static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error; + unsigned int ia_valid = attr->ia_valid; + + BUG_ON(!inode); + + error = inode_change_ok(inode, attr); + if (error) + goto out; + + if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) + error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; + if (error) + goto out; + if (ia_valid & ATTR_SIZE) { + error = -EINVAL; + if (!(attr->ia_size & ~HPAGE_MASK)) + error = hugetlb_vmtruncate(inode, attr->ia_size); + if (error) + goto out; + attr->ia_valid &= ~ATTR_SIZE; + } + error = inode_setattr(inode, attr); +out: + return error; +} + +static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, + gid_t gid, int mode, int dev) +{ + struct inode *inode; + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); + + if (sbinfo->free_inodes >= 0) { + spin_lock(&sbinfo->stat_lock); + if (!sbinfo->free_inodes) { + spin_unlock(&sbinfo->stat_lock); + return NULL; + } + sbinfo->free_inodes--; + spin_unlock(&sbinfo->stat_lock); + } + + inode = new_inode(sb); + if (inode) { + inode->i_mode = mode; + inode->i_uid = uid; + inode->i_gid = gid; + inode->i_blksize = HPAGE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &hugetlbfs_aops; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_op = &hugetlbfs_inode_operations; + inode->i_fop = &hugetlbfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &hugetlbfs_dir_inode_operations; + inode->i_fop = &dcache_dir_ops; + + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +/* + * File creation. Allocate an inode, and we're done.. + */ +/* SMP-safe */ +static int hugetlbfs_mknod(struct inode *dir, + struct dentry *dentry, int mode, int dev) +{ + struct inode *inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + current->fsgid, mode, dev); + int error = -ENOSPC; + + if (inode) { + dir->i_size += PSEUDO_DIRENT_SIZE; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0); +// if (!retval) + //dir->i_nlink++; + return retval; +} + +static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int hugetlbfs_symlink(struct inode *dir, + struct dentry *dentry, const char *symname) +{ + int error = -ENOSPC; + + error = hugetlbfs_mknod(dir, dentry, S_IFLNK|S_IRWXUGO, 0); + if (!error) { + int l = strlen(symname)+1; + struct inode *inode = dentry->d_inode; + error = block_symlink(inode, symname, l); + } + return error; +} + +static struct address_space_operations hugetlbfs_aops = { + .readpage = hugetlbfs_readpage, + .writepage = fail_writepage, + .prepare_write = hugetlbfs_prepare_write, + .commit_write = hugetlbfs_commit_write, +}; + +struct file_operations hugetlbfs_file_operations = { + .mmap = hugetlbfs_file_mmap, + .fsync = hugetlbfs_sync_file, + .get_unmapped_area = hugetlb_get_unmapped_area, +}; + +static struct inode_operations hugetlbfs_dir_inode_operations = { + .create = hugetlbfs_create, + .lookup = hugetlbfs_lookup, + .link = hugetlbfs_link, + .unlink = hugetlbfs_unlink, + .symlink = hugetlbfs_symlink, + .mkdir = hugetlbfs_mkdir, + .rmdir = hugetlbfs_rmdir, + .mknod = hugetlbfs_mknod, + .rename = hugetlbfs_rename, + .setattr = hugetlbfs_setattr, +}; + +static struct inode_operations hugetlbfs_inode_operations = { + .setattr = hugetlbfs_setattr, +}; + +static struct super_operations hugetlbfs_ops = { + .statfs = hugetlbfs_statfs, + .put_inode = hugetlbfs_drop_inode, +}; + +static int hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) +{ + char *opt, *value, *rest; + + if (!options) + return 0; + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + value = strchr(opt, '='); + if (!value || !*value) + return -EINVAL; + else + *value++ = '\0'; + + if (!strcmp(opt, "uid")) + pconfig->uid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "gid")) + pconfig->gid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "mode")) + pconfig->mode = simple_strtoul(value, &value, 0) & 0777U; + else if (!strcmp(opt, "size")) { + unsigned long long size = memparse(value, &rest); + if (*rest == '%') { + size <<= HPAGE_SHIFT; + size *= htlbpage_max; + do_div(size, 100); + rest++; + } + size &= HPAGE_MASK; + pconfig->nr_blocks = (size >> HPAGE_SHIFT) ; + value = rest; + } else if (!strcmp(opt,"nr_inodes")) { + pconfig->nr_inodes = memparse(value, &rest); + value = rest; + } else + return -EINVAL; + + if (*value) + return -EINVAL; + } + return 0; +} + +static struct super_block * +hugetlbfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + struct hugetlbfs_config config; + struct hugetlbfs_sb_info *sbinfo; + + config.nr_blocks = -1; /* No limit on size by default. */ + config.nr_inodes = -1; /* No limit on number of inodes by default. */ + config.uid = current->fsuid; + config.gid = current->fsgid; + config.mode = 0755; + if (hugetlbfs_parse_options(data, &config)) + return NULL; + + sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); + if (!sbinfo) + return NULL; + sb->u.generic_sbp = sbinfo; + + spin_lock_init(&sbinfo->stat_lock); + sbinfo->max_blocks = config.nr_blocks; + sbinfo->free_blocks = config.nr_blocks; + sbinfo->max_inodes = config.nr_inodes; + sbinfo->free_inodes = config.nr_inodes; + sb->s_blocksize = HPAGE_SIZE; + sb->s_blocksize_bits = HPAGE_SHIFT; + sb->s_magic = HUGETLBFS_MAGIC; + sb->s_op = &hugetlbfs_ops; + inode = hugetlbfs_get_inode(sb, config.uid, config.gid, + S_IFDIR | config.mode, 0); + if (!inode) + goto out_free; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + goto out_free; + } + sb->s_root = root; + return sb; +out_free: + kfree(sbinfo); + return NULL; +} + +static DECLARE_FSTYPE(hugetlbfs_fs_type, "hugetlbfs", hugetlbfs_fill_super, FS_LITTER); + +static struct vfsmount *hugetlbfs_vfsmount; + +static atomic_t hugetlbfs_counter = ATOMIC_INIT(0); + +struct file *hugetlb_zero_setup(size_t size) +{ + int error, n; + struct file *file; + struct inode *inode; + struct dentry *dentry, *root; + struct qstr quick_string; + char buf[16]; + + if (!is_hugepage_mem_enough(size)) + return ERR_PTR(-ENOMEM); + n = atomic_read(&hugetlbfs_counter); + atomic_inc(&hugetlbfs_counter); + + root = hugetlbfs_vfsmount->mnt_root; + snprintf(buf, 16, "%d", n); + quick_string.name = buf; + quick_string.len = strlen(quick_string.name); + quick_string.hash = 0; + dentry = d_alloc(root, &quick_string); + if (!dentry) + return ERR_PTR(-ENOMEM); + + error = -ENFILE; + file = get_empty_filp(); + if (!file) + goto out_dentry; + + error = -ENOSPC; + inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, + current->fsgid, S_IFREG | S_IRWXUGO, 0); + if (!inode) + goto out_file; + + d_instantiate(dentry, inode); + inode->i_size = size; + inode->i_nlink = 0; + file->f_vfsmnt = mntget(hugetlbfs_vfsmount); + file->f_dentry = dentry; + file->f_op = &hugetlbfs_file_operations; + file->f_mode = FMODE_WRITE | FMODE_READ; + return file; + +out_file: + put_filp(file); +out_dentry: + dput(dentry); + return ERR_PTR(error); +} + +int hugetlb_get_quota(struct address_space * mapping) +{ + int ret = 0; + struct hugetlbfs_sb_info *sbinfo = + HUGETLBFS_SB(mapping->host->i_sb); + + if (sbinfo->free_blocks > -1) { + spin_lock(&sbinfo->stat_lock); + if (sbinfo->free_blocks > 0) + sbinfo->free_blocks--; + else + ret = -ENOMEM; + spin_unlock(&sbinfo->stat_lock); + } + + return ret; +} + +void hugetlb_put_quota(struct address_space *mapping) +{ + struct hugetlbfs_sb_info *sbinfo = + HUGETLBFS_SB(mapping->host->i_sb); + + if (sbinfo->free_blocks > -1) { + spin_lock(&sbinfo->stat_lock); + sbinfo->free_blocks++; + spin_unlock(&sbinfo->stat_lock); + } +} + +static int __init init_hugetlbfs_fs(void) +{ + int error; + struct vfsmount *vfsmount; + + error = register_filesystem(&hugetlbfs_fs_type); + if (error) + return error; + + vfsmount = kern_mount(&hugetlbfs_fs_type); + + if (!IS_ERR(vfsmount)) { + printk("Hugetlbfs mounted.\n"); + hugetlbfs_vfsmount = vfsmount; + return 0; + } + + printk("Error in mounting hugetlbfs.\n"); + error = PTR_ERR(vfsmount); + return error; +} + +static void __exit exit_hugetlbfs_fs(void) +{ + unregister_filesystem(&hugetlbfs_fs_type); +} + +module_init(init_hugetlbfs_fs) +module_exit(exit_hugetlbfs_fs) + +MODULE_LICENSE("GPL"); diff -u -Nur linux-2.4.25/fs/inode.c linux-ia64-2.4/fs/inode.c --- linux-2.4.25/fs/inode.c 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/fs/inode.c 2004-02-18 09:51:41.000000000 -0700 @@ -57,7 +57,7 @@ */ static LIST_HEAD(inode_in_use); -static LIST_HEAD(inode_unused); +LIST_HEAD(inode_unused); static LIST_HEAD(inode_unused_pagecache); static struct list_head *inode_hashtable; static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */ diff -u -Nur linux-2.4.25/fs/proc/array.c linux-ia64-2.4/fs/proc/array.c --- linux-2.4.25/fs/proc/array.c 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/fs/proc/array.c 2004-02-18 09:51:24.000000000 -0700 @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -490,6 +491,18 @@ pgd_t *pgd = pgd_offset(mm, vma->vm_start); int pages = 0, shared = 0, dirty = 0, total = 0; + if (is_vm_hugetlb_page(vma)) { + int num_pages = ((vma->vm_end - vma->vm_start)/PAGE_SIZE); + resident +=num_pages; + if (!(vma->vm_flags & VM_DONTCOPY)) + share += num_pages; + if (vma->vm_flags & VM_WRITE) + dt += num_pages; + drs += num_pages; + vma = vma->vm_next; + continue; + + } statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total); resident += pages; share += shared; diff -u -Nur linux-2.4.25/fs/proc/proc_misc.c linux-ia64-2.4/fs/proc/proc_misc.c --- linux-2.4.25/fs/proc/proc_misc.c 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/fs/proc/proc_misc.c 2004-02-18 09:51:05.000000000 -0700 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -210,6 +211,8 @@ K(i.totalswap), K(i.freeswap)); + len += hugetlb_report_meminfo(page + len); + return proc_calc_metrics(page, start, off, count, eof, len); #undef B #undef K diff -u -Nur linux-2.4.25/include/asm-generic/tlb.h linux-ia64-2.4/include/asm-generic/tlb.h --- linux-2.4.25/include/asm-generic/tlb.h 2004-02-18 09:52:05.000000000 -0700 +++ linux-ia64-2.4/include/asm-generic/tlb.h 2004-02-18 09:51:03.000000000 -0700 @@ -31,15 +31,18 @@ pte_t ptes[FREE_PTE_NR]; } mmu_gather_t; +#ifndef local_mmu_gathers /* Users of the generic TLB shootdown code must declare this storage space. */ extern mmu_gather_t mmu_gathers[NR_CPUS]; +#define local_mmu_gathers &mmu_gathers[smp_processor_id()] +#endif /* tlb_gather_mmu * Return a pointer to an initialized mmu_gather_t. */ static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm) { - mmu_gather_t *tlb = &mmu_gathers[smp_processor_id()]; + mmu_gather_t *tlb = local_mmu_gathers; tlb->mm = mm; /* Use fast mode if there is only one user of this mm (this process) */ diff -u -Nur linux-2.4.25/include/asm-generic/xor.h linux-ia64-2.4/include/asm-generic/xor.h --- linux-2.4.25/include/asm-generic/xor.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/asm-generic/xor.h 2004-02-18 09:51:39.000000000 -0700 @@ -13,6 +13,8 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + static void xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) { @@ -121,7 +123,7 @@ d5 ^= p2[5]; d6 ^= p2[6]; d7 ^= p2[7]; - p1[0] = d0; /* Store the result (in burts) */ + p1[0] = d0; /* Store the result (in bursts) */ p1[1] = d1; p1[2] = d2; p1[3] = d3; @@ -166,7 +168,7 @@ d5 ^= p3[5]; d6 ^= p3[6]; d7 ^= p3[7]; - p1[0] = d0; /* Store the result (in burts) */ + p1[0] = d0; /* Store the result (in bursts) */ p1[1] = d1; p1[2] = d2; p1[3] = d3; @@ -220,7 +222,7 @@ d5 ^= p4[5]; d6 ^= p4[6]; d7 ^= p4[7]; - p1[0] = d0; /* Store the result (in burts) */ + p1[0] = d0; /* Store the result (in bursts) */ p1[1] = d1; p1[2] = d2; p1[3] = d3; @@ -283,7 +285,7 @@ d5 ^= p5[5]; d6 ^= p5[6]; d7 ^= p5[7]; - p1[0] = d0; /* Store the result (in burts) */ + p1[0] = d0; /* Store the result (in bursts) */ p1[1] = d1; p1[2] = d2; p1[3] = d3; @@ -299,6 +301,382 @@ } while (--lines > 0); } +static void +xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + prefetchw(p1); + prefetch(p2); + + do { + prefetchw(p1+8); + prefetch(p2+8); + once_more: + p1[0] ^= p2[0]; + p1[1] ^= p2[1]; + p1[2] ^= p2[2]; + p1[3] ^= p2[3]; + p1[4] ^= p2[4]; + p1[5] ^= p2[5]; + p1[6] ^= p2[6]; + p1[7] ^= p2[7]; + p1 += 8; + p2 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + prefetchw(p1); + prefetch(p2); + prefetch(p3); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + once_more: + p1[0] ^= p2[0] ^ p3[0]; + p1[1] ^= p2[1] ^ p3[1]; + p1[2] ^= p2[2] ^ p3[2]; + p1[3] ^= p2[3] ^ p3[3]; + p1[4] ^= p2[4] ^ p3[4]; + p1[5] ^= p2[5] ^ p3[5]; + p1[6] ^= p2[6] ^ p3[6]; + p1[7] ^= p2[7] ^ p3[7]; + p1 += 8; + p2 += 8; + p3 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + once_more: + p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; + p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; + p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; + p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; + p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; + p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; + p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; + p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + prefetch(p5); + + do { + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + prefetch(p5+8); + once_more: + p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; + p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; + p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; + p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; + p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; + p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; + p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; + p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + p5 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + once_more: + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + p1[0] = d0; /* Store the result (in bursts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + once_more: + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + p1[0] = d0; /* Store the result (in bursts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + once_more: + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + d0 ^= p4[0]; + d1 ^= p4[1]; + d2 ^= p4[2]; + d3 ^= p4[3]; + d4 ^= p4[4]; + d5 ^= p4[5]; + d6 ^= p4[6]; + d7 ^= p4[7]; + p1[0] = d0; /* Store the result (in bursts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + +static void +xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + long lines = bytes / (sizeof (long)) / 8 - 1; + + prefetchw(p1); + prefetch(p2); + prefetch(p3); + prefetch(p4); + prefetch(p5); + + do { + register long d0, d1, d2, d3, d4, d5, d6, d7; + + prefetchw(p1+8); + prefetch(p2+8); + prefetch(p3+8); + prefetch(p4+8); + prefetch(p5+8); + once_more: + d0 = p1[0]; /* Pull the stuff into registers */ + d1 = p1[1]; /* ... in bursts, if possible. */ + d2 = p1[2]; + d3 = p1[3]; + d4 = p1[4]; + d5 = p1[5]; + d6 = p1[6]; + d7 = p1[7]; + d0 ^= p2[0]; + d1 ^= p2[1]; + d2 ^= p2[2]; + d3 ^= p2[3]; + d4 ^= p2[4]; + d5 ^= p2[5]; + d6 ^= p2[6]; + d7 ^= p2[7]; + d0 ^= p3[0]; + d1 ^= p3[1]; + d2 ^= p3[2]; + d3 ^= p3[3]; + d4 ^= p3[4]; + d5 ^= p3[5]; + d6 ^= p3[6]; + d7 ^= p3[7]; + d0 ^= p4[0]; + d1 ^= p4[1]; + d2 ^= p4[2]; + d3 ^= p4[3]; + d4 ^= p4[4]; + d5 ^= p4[5]; + d6 ^= p4[6]; + d7 ^= p4[7]; + d0 ^= p5[0]; + d1 ^= p5[1]; + d2 ^= p5[2]; + d3 ^= p5[3]; + d4 ^= p5[4]; + d5 ^= p5[5]; + d6 ^= p5[6]; + d7 ^= p5[7]; + p1[0] = d0; /* Store the result (in bursts) */ + p1[1] = d1; + p1[2] = d2; + p1[3] = d3; + p1[4] = d4; + p1[5] = d5; + p1[6] = d6; + p1[7] = d7; + p1 += 8; + p2 += 8; + p3 += 8; + p4 += 8; + p5 += 8; + } while (--lines > 0); + if (lines == 0) + goto once_more; +} + static struct xor_block_template xor_block_8regs = { name: "8regs", do_2: xor_8regs_2, @@ -315,8 +693,26 @@ do_5: xor_32regs_5, }; +static struct xor_block_template xor_block_8regs_p = { + name: "8regs_prefetch", + do_2: xor_8regs_p_2, + do_3: xor_8regs_p_3, + do_4: xor_8regs_p_4, + do_5: xor_8regs_p_5, +}; + +static struct xor_block_template xor_block_32regs_p = { + name: "32regs_prefetch", + do_2: xor_32regs_p_2, + do_3: xor_32regs_p_3, + do_4: xor_32regs_p_4, + do_5: xor_32regs_p_5, +}; + #define XOR_TRY_TEMPLATES \ do { \ xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_8regs_p); \ xor_speed(&xor_block_32regs); \ + xor_speed(&xor_block_32regs_p); \ } while (0) diff -u -Nur linux-2.4.25/include/asm-i386/hw_irq.h linux-ia64-2.4/include/asm-i386/hw_irq.h --- linux-2.4.25/include/asm-i386/hw_irq.h 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/include/asm-i386/hw_irq.h 2004-02-18 09:51:41.000000000 -0700 @@ -222,4 +222,6 @@ static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {} #endif +extern irq_desc_t irq_desc [NR_IRQS]; + #endif /* _ASM_HW_IRQ_H */ diff -u -Nur linux-2.4.25/include/asm-i386/page.h linux-ia64-2.4/include/asm-i386/page.h --- linux-2.4.25/include/asm-i386/page.h 2004-02-18 09:52:08.000000000 -0700 +++ linux-ia64-2.4/include/asm-i386/page.h 2004-02-18 09:51:06.000000000 -0700 @@ -30,8 +30,8 @@ #endif -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) /* * These are used to make use of C type-checking.. @@ -137,6 +137,8 @@ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define is_invalid_hugepage_range(addr, len) 0 + #endif /* __KERNEL__ */ #endif /* _I386_PAGE_H */ diff -u -Nur linux-2.4.25/include/asm-i386/pgtable.h linux-ia64-2.4/include/asm-i386/pgtable.h --- linux-2.4.25/include/asm-i386/pgtable.h 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/include/asm-i386/pgtable.h 2004-02-18 09:51:29.000000000 -0700 @@ -302,6 +302,13 @@ static inline void ptep_mkdirty(pte_t *ptep) { set_bit(_PAGE_BIT_DIRTY, ptep); } /* + * Macro to mark a page protection value as "uncacheable". On processors which do not support + * it, this is a no-op. + */ +#define pgprot_noncached(prot) ((boot_cpu_data.x86 > 3) \ + ? (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) : (prot)) + +/* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ diff -u -Nur linux-2.4.25/include/asm-i386/ptrace.h linux-ia64-2.4/include/asm-i386/ptrace.h --- linux-2.4.25/include/asm-i386/ptrace.h 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/include/asm-i386/ptrace.h 2004-02-18 09:51:04.000000000 -0700 @@ -58,6 +58,7 @@ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) extern void show_regs(struct pt_regs *); +#define force_successful_syscall_return() do { } while (0) #endif #endif diff -u -Nur linux-2.4.25/include/asm-ia64/a.out.h linux-ia64-2.4/include/asm-ia64/a.out.h --- linux-2.4.25/include/asm-ia64/a.out.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/a.out.h 2004-02-18 09:51:39.000000000 -0700 @@ -7,8 +7,8 @@ * probably would be better to clean up binfmt_elf.c so it does not * necessarily depend on there being a.out support. * - * Copyright (C) 1998-2000, 2002 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2000, 2002 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/bugs.h linux-ia64-2.4/include/asm-ia64/bugs.h --- linux-2.4.25/include/asm-ia64/bugs.h 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/bugs.h 2004-02-18 09:51:41.000000000 -0700 @@ -4,8 +4,10 @@ * Needs: * void check_bugs(void); * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/byteorder.h linux-ia64-2.4/include/asm-ia64/byteorder.h --- linux-2.4.25/include/asm-ia64/byteorder.h 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/byteorder.h 2004-02-18 09:51:05.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_BYTEORDER_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co. */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/checksum.h linux-ia64-2.4/include/asm-ia64/checksum.h --- linux-2.4.25/include/asm-ia64/checksum.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/checksum.h 2004-02-18 09:51:03.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_CHECKSUM_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ /* diff -u -Nur linux-2.4.25/include/asm-ia64/current.h linux-ia64-2.4/include/asm-ia64/current.h --- linux-2.4.25/include/asm-ia64/current.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/current.h 2004-02-18 09:51:39.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_CURRENT_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ /* In kernel mode, thread pointer (r13) is used to point to the diff -u -Nur linux-2.4.25/include/asm-ia64/errno.h linux-ia64-2.4/include/asm-ia64/errno.h --- linux-2.4.25/include/asm-ia64/errno.h 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/errno.h 2004-02-18 09:51:20.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_ERRNO_H /* - * This is derived from the Linux/x86 version. + * Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define EPERM 1 /* Operation not permitted */ diff -u -Nur linux-2.4.25/include/asm-ia64/fcntl.h linux-ia64-2.4/include/asm-ia64/fcntl.h --- linux-2.4.25/include/asm-ia64/fcntl.h 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/fcntl.h 2004-02-18 09:51:24.000000000 -0700 @@ -1,10 +1,10 @@ #ifndef _ASM_IA64_FCNTL_H #define _ASM_IA64_FCNTL_H /* - * This is mostly compatible with Linux/x86. + * Based on . * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co. */ /* diff -u -Nur linux-2.4.25/include/asm-ia64/ioctl.h linux-ia64-2.4/include/asm-ia64/ioctl.h --- linux-2.4.25/include/asm-ia64/ioctl.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/ioctl.h 2004-02-18 09:51:23.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_IOCTL_H /* - * This is mostly derived from the Linux/x86 version. + * Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ /* ioctl command encoding: 32 bits total, command in lower 16 bits, diff -u -Nur linux-2.4.25/include/asm-ia64/ioctls.h linux-ia64-2.4/include/asm-ia64/ioctls.h --- linux-2.4.25/include/asm-ia64/ioctls.h 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/ioctls.h 2004-02-18 09:51:05.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_IOCTLS_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/mca.h linux-ia64-2.4/include/asm-ia64/mca.h --- linux-2.4.25/include/asm-ia64/mca.h 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/mca.h 2004-02-18 09:51:08.000000000 -0700 @@ -2,7 +2,7 @@ * File: mca.h * Purpose: Machine check handling specific defines * - * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) 1999, 2004 Silicon Graphics, Inc. * Copyright (C) Vijay Chander (vijay@engr.sgi.com) * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) */ @@ -17,23 +17,8 @@ #include #include -/* These are the return codes from all the IA64_MCA specific interfaces */ -typedef int ia64_mca_return_code_t; - -enum { - IA64_MCA_SUCCESS = 0, - IA64_MCA_FAILURE = 1 -}; - #define IA64_MCA_RENDEZ_TIMEOUT (20 * 1000) /* value in milliseconds - 20 seconds */ -#define IA64_CMC_INT_DISABLE 0 -#define IA64_CMC_INT_ENABLE 1 - - -typedef u32 int_vector_t; -typedef u64 millisec_t; - typedef union cmcv_reg_u { u64 cmcv_regval; struct { @@ -50,10 +35,6 @@ #define cmcv_mask cmcv_reg_s.cmcr_mask #define cmcv_vector cmcv_reg_s.cmcr_vector - -#define IA64_MCA_UCMC_HANDLER_SIZE 0x10 -#define IA64_INIT_HANDLER_SIZE 0x10 - enum { IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0, IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1 @@ -82,16 +63,6 @@ } ia64_mc_info_t; -/* Possible rendez states passed from SAL to OS during MCA - * handoff - */ -enum { - IA64_MCA_RENDEZ_NOT_RQD = 0x0, - IA64_MCA_RENDEZ_DONE_WITHOUT_INIT = 0x1, - IA64_MCA_RENDEZ_DONE_WITH_INIT = 0x2, - IA64_MCA_RENDEZ_FAILURE = -1 -}; - typedef struct ia64_mca_sal_to_os_state_s { u64 imsto_os_gp; /* GP of the os registered with the SAL */ u64 imsto_pal_proc; /* PAL_PROC entry point - physical addr */ @@ -133,41 +104,13 @@ */ } ia64_mca_os_to_sal_state_t; -typedef int (*prfunc_t)(const char * fmt, ...); - extern void ia64_mca_init(void); extern void ia64_os_mca_dispatch(void); extern void ia64_os_mca_dispatch_end(void); extern void ia64_mca_ucmc_handler(void); extern void ia64_monarch_init_handler(void); extern void ia64_slave_init_handler(void); -extern void ia64_mca_rendez_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cmc_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cmc_int_caller(int,void *,struct pt_regs *); -extern void ia64_mca_cpe_int_handler(int,void *,struct pt_regs *); -extern void ia64_mca_cpe_int_caller(int,void *,struct pt_regs *); -extern int ia64_log_print(int,prfunc_t); extern void ia64_mca_cmc_vector_setup(void); -extern int ia64_mca_check_errors(void); - -#define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") -#define platform_mem_dev_err_print ia64_log_prt_oem_data -#define platform_pci_bus_err_print ia64_log_prt_oem_data -#define platform_pci_comp_err_print ia64_log_prt_oem_data -#define platform_plat_specific_err_print ia64_log_prt_oem_data -#define platform_host_ctlr_err_print ia64_log_prt_oem_data -#define platform_plat_bus_err_print ia64_log_prt_oem_data - -#undef MCA_TEST - -#undef IA64_MCA_DEBUG_INFO - -#if defined(IA64_MCA_DEBUG_INFO) -# define IA64_MCA_DEBUG(fmt...) printk(fmt) -#else -# define IA64_MCA_DEBUG(fmt...) -#endif #endif /* !__ASSEMBLY__ */ #endif /* _ASM_IA64_MCA_H */ diff -u -Nur linux-2.4.25/include/asm-ia64/mman.h linux-ia64-2.4/include/asm-ia64/mman.h --- linux-2.4.25/include/asm-ia64/mman.h 2004-02-18 09:52:35.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/mman.h 2004-02-18 09:51:23.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_MMAN_H /* - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #define PROT_READ 0x1 /* page can be read */ diff -u -Nur linux-2.4.25/include/asm-ia64/namei.h linux-ia64-2.4/include/asm-ia64/namei.h --- linux-2.4.25/include/asm-ia64/namei.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/namei.h 2004-02-18 09:51:39.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_NAMEI_H /* - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998, 1999, 2001 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/page.h linux-ia64-2.4/include/asm-ia64/page.h --- linux-2.4.25/include/asm-ia64/page.h 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/page.h 2004-02-18 09:51:05.000000000 -0700 @@ -59,6 +59,7 @@ #endif #define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ + #ifdef __ASSEMBLY__ # define __pa(x) ((x) - PAGE_OFFSET) # define __va(x) ((x) + PAGE_OFFSET) diff -u -Nur linux-2.4.25/include/asm-ia64/param.h linux-ia64-2.4/include/asm-ia64/param.h --- linux-2.4.25/include/asm-ia64/param.h 2004-02-18 09:52:33.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/param.h 2004-02-18 09:51:23.000000000 -0700 @@ -4,8 +4,10 @@ /* * Fundamental kernel parameters. * - * Copyright (C) 1998, 1999, 2002-2003 Hewlett-Packard Co - * David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999, 2002-2003 + * David Mosberger-Tang , Hewlett-Packard Co */ #define EXEC_PAGESIZE 65536 diff -u -Nur linux-2.4.25/include/asm-ia64/poll.h linux-ia64-2.4/include/asm-ia64/poll.h --- linux-2.4.25/include/asm-ia64/poll.h 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/poll.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,10 +2,10 @@ #define _ASM_IA64_POLL_H /* - * poll(2) bit definitions. Chosen to be compatible with Linux/x86. + * poll(2) bit definitions. Based on . * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define POLLIN 0x0001 diff -u -Nur linux-2.4.25/include/asm-ia64/posix_types.h linux-ia64-2.4/include/asm-ia64/posix_types.h --- linux-2.4.25/include/asm-ia64/posix_types.h 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/posix_types.h 2004-02-18 09:51:19.000000000 -0700 @@ -6,8 +6,10 @@ * be a little careful about namespace pollution etc. Also, we cannot * assume GCC is being used. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ typedef unsigned int __kernel_dev_t; diff -u -Nur linux-2.4.25/include/asm-ia64/resource.h linux-ia64-2.4/include/asm-ia64/resource.h --- linux-2.4.25/include/asm-ia64/resource.h 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/resource.h 2004-02-18 09:51:30.000000000 -0700 @@ -4,8 +4,10 @@ /* * Resource limits * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/scatterlist.h linux-ia64-2.4/include/asm-ia64/scatterlist.h --- linux-2.4.25/include/asm-ia64/scatterlist.h 2004-02-18 09:52:36.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/scatterlist.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_SCATTERLIST_H /* - * Copyright (C) 1998-1999, 2001-2002 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-1999, 2001-2002 + * David Mosberger-Tang , Hewlett-Packard Co */ struct scatterlist { diff -u -Nur linux-2.4.25/include/asm-ia64/siginfo.h linux-ia64-2.4/include/asm-ia64/siginfo.h --- linux-2.4.25/include/asm-ia64/siginfo.h 2004-02-18 09:52:41.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/siginfo.h 2004-02-18 09:51:41.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_SIGINFO_H /* - * Copyright (C) 1998-2002 Hewlett-Packard Co - * David Mosberger-Tang + * Based on . + * + * Modified 1998-2002 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/signal.h linux-ia64-2.4/include/asm-ia64/signal.h --- linux-2.4.25/include/asm-ia64/signal.h 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/signal.h 2004-02-18 09:51:05.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_SIGNAL_H /* - * Copyright (C) 1998-2001 Hewlett-Packard Co - * David Mosberger-Tang + * Modified 1998-2001 + * David Mosberger-Tang , Hewlett-Packard Co * * Unfortunately, this file is being included by bits/signal.h in * glibc-2.x. Hence the #ifdef __KERNEL__ ugliness. diff -u -Nur linux-2.4.25/include/asm-ia64/socket.h linux-ia64-2.4/include/asm-ia64/socket.h --- linux-2.4.25/include/asm-ia64/socket.h 2004-02-18 09:52:05.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/socket.h 2004-02-18 09:51:03.000000000 -0700 @@ -2,10 +2,12 @@ #define _ASM_IA64_SOCKET_H /* - * Socket related defines. This mostly mirrors the Linux/x86 version. + * Socket related defines. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-ia64/sockios.h linux-ia64-2.4/include/asm-ia64/sockios.h --- linux-2.4.25/include/asm-ia64/sockios.h 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/sockios.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,11 +2,12 @@ #define _ASM_IA64_SOCKIOS_H /* - * Socket-level I/O control calls. This mostly mirrors the Linux/x86 - * version. + * Socket-level I/O control calls. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ #define FIOSETOWN 0x8901 #define SIOCSPGRP 0x8902 diff -u -Nur linux-2.4.25/include/asm-ia64/stat.h linux-ia64-2.4/include/asm-ia64/stat.h --- linux-2.4.25/include/asm-ia64/stat.h 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/stat.h 2004-02-18 09:51:20.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_STAT_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ struct stat { diff -u -Nur linux-2.4.25/include/asm-ia64/statfs.h linux-ia64-2.4/include/asm-ia64/statfs.h --- linux-2.4.25/include/asm-ia64/statfs.h 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/statfs.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_STATFS_H /* - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Based on . + * + * Modified 1998, 1999 + * David Mosberger-Tang , Hewlett-Packard Co */ # ifndef __KERNEL_STRICT_NAMES diff -u -Nur linux-2.4.25/include/asm-ia64/termbits.h linux-ia64-2.4/include/asm-ia64/termbits.h --- linux-2.4.25/include/asm-ia64/termbits.h 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/termbits.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,8 +2,10 @@ #define _ASM_IA64_TERMBITS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Based on . + * + * Modified 1999 + * David Mosberger-Tang , Hewlett-Packard Co * * 99/01/28 Added new baudrates */ diff -u -Nur linux-2.4.25/include/asm-ia64/termios.h linux-ia64-2.4/include/asm-ia64/termios.h --- linux-2.4.25/include/asm-ia64/termios.h 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/termios.h 2004-02-18 09:51:24.000000000 -0700 @@ -2,8 +2,8 @@ #define _ASM_IA64_TERMIOS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Modified 1999 + * David Mosberger-Tang , Hewlett-Packard Co * * 99/01/28 Added N_IRDA and N_SMSBLOCK */ diff -u -Nur linux-2.4.25/include/asm-ia64/types.h linux-ia64-2.4/include/asm-ia64/types.h --- linux-2.4.25/include/asm-ia64/types.h 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/types.h 2004-02-18 09:51:07.000000000 -0700 @@ -8,8 +8,10 @@ * not a major issue. However, for interoperability, libraries still * need to be careful to avoid a name clashes. * - * Copyright (C) 1998-2000 Hewlett-Packard Co - * Copyright (C) 1998-2000 David Mosberger-Tang + * Based on . + * + * Modified 1998-2000 + * David Mosberger-Tang , Hewlett-Packard Co */ #ifdef __ASSEMBLY__ diff -u -Nur linux-2.4.25/include/asm-ia64/uaccess.h linux-ia64-2.4/include/asm-ia64/uaccess.h --- linux-2.4.25/include/asm-ia64/uaccess.h 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/uaccess.h 2004-02-18 09:51:19.000000000 -0700 @@ -26,6 +26,8 @@ * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and * then resumes execution at the continuation point. * + * Based on . + * * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co * David Mosberger-Tang */ diff -u -Nur linux-2.4.25/include/asm-ia64/unaligned.h linux-ia64-2.4/include/asm-ia64/unaligned.h --- linux-2.4.25/include/asm-ia64/unaligned.h 2004-02-18 09:52:41.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/unaligned.h 2004-02-18 09:51:41.000000000 -0700 @@ -4,8 +4,9 @@ #include /* - * The main single-value unaligned transfer routines. Derived from - * the Linux/Alpha version. + * The main single-value unaligned transfer routines. + * + * Based on . * * Copyright (C) 1998, 1999, 2003 Hewlett-Packard Co * David Mosberger-Tang diff -u -Nur linux-2.4.25/include/asm-ia64/user.h linux-ia64-2.4/include/asm-ia64/user.h --- linux-2.4.25/include/asm-ia64/user.h 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/include/asm-ia64/user.h 2004-02-18 09:51:29.000000000 -0700 @@ -24,8 +24,8 @@ * current->start_stack, so we round each of these in order to be able * to write an integer number of pages. * - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang + * Modified 1998, 1999, 2001 + * David Mosberger-Tang , Hewlett-Packard Co */ #include diff -u -Nur linux-2.4.25/include/asm-m68k/pgtable.h linux-ia64-2.4/include/asm-m68k/pgtable.h --- linux-2.4.25/include/asm-m68k/pgtable.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/asm-m68k/pgtable.h 2004-02-18 09:51:39.000000000 -0700 @@ -180,6 +180,24 @@ #ifndef __ASSEMBLY__ #include + +/* + * Macro to mark a page protection value as "uncacheable". + */ +#ifdef SUN3_PAGE_NOCACHE +# define __SUN3_PAGE_NOCACHE SUN3_PAGE_NOCACHE +#else +# define __SUN3_PAGE_NOCACHE 0 +#endif +#define pgprot_noncached(prot) \ + (MMU_IS_SUN3 \ + ? (__pgprot(pgprot_val(prot) | __SUN3_PAGE_NOCACHE)) \ + : ((MMU_IS_851 || MMU_IS_030) \ + ? (__pgprot(pgprot_val(prot) | _PAGE_NOCACHE030)) \ + : (MMU_IS_040 || MMU_IS_060) \ + ? (__pgprot((pgprot_val(prot) & _CACHEMASK040) | _PAGE_NOCACHE_S)) \ + : (prot))) + #endif /* !__ASSEMBLY__ */ /* diff -u -Nur linux-2.4.25/include/asm-ppc/pgtable.h linux-ia64-2.4/include/asm-ppc/pgtable.h --- linux-2.4.25/include/asm-ppc/pgtable.h 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/include/asm-ppc/pgtable.h 2004-02-18 09:51:08.000000000 -0700 @@ -587,6 +587,11 @@ pte_update(ptep, 0, _PAGE_DIRTY); } +/* + * Macro to mark a page protection value as "uncacheable". + */ +#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) + #define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0) #define pmd_page(pmd) (pmd_val(pmd) & PAGE_MASK) diff -u -Nur linux-2.4.25/include/asm-ppc64/pgtable.h linux-ia64-2.4/include/asm-ppc64/pgtable.h --- linux-2.4.25/include/asm-ppc64/pgtable.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/include/asm-ppc64/pgtable.h 2004-02-18 09:51:03.000000000 -0700 @@ -317,6 +317,11 @@ pte_update(ptep, 0, _PAGE_DIRTY); } +/* + * Macro to mark a page protection value as "uncacheable". + */ +#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED)) + #define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0) /* diff -u -Nur linux-2.4.25/include/asm-x86_64/pgtable.h linux-ia64-2.4/include/asm-x86_64/pgtable.h --- linux-2.4.25/include/asm-x86_64/pgtable.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/include/asm-x86_64/pgtable.h 2004-02-18 09:51:23.000000000 -0700 @@ -342,6 +342,11 @@ static inline void ptep_mkdirty(pte_t *ptep) { set_bit(_PAGE_BIT_DIRTY, ptep); } /* + * Macro to mark a page protection value as "uncacheable". + */ +#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_PCD | _PAGE_PWT)) + +/* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ diff -u -Nur linux-2.4.25/include/linux/agp_backend.h linux-ia64-2.4/include/linux/agp_backend.h --- linux-2.4.25/include/linux/agp_backend.h 2004-02-18 09:52:40.000000000 -0700 +++ linux-ia64-2.4/include/linux/agp_backend.h 2004-02-18 09:51:39.000000000 -0700 @@ -142,6 +142,7 @@ size_t page_count; int num_scratch_pages; unsigned long *memory; + void *vmptr; off_t pg_start; u32 type; u32 physical; diff -u -Nur linux-2.4.25/include/linux/fs.h linux-ia64-2.4/include/linux/fs.h --- linux-2.4.25/include/linux/fs.h 2004-02-18 09:52:26.000000000 -0700 +++ linux-ia64-2.4/include/linux/fs.h 2004-02-18 09:51:19.000000000 -0700 @@ -247,7 +247,7 @@ /* First cache line: */ struct buffer_head *b_next; /* Hash queue list */ unsigned long b_blocknr; /* block number */ - unsigned short b_size; /* block size */ + unsigned int b_size; /* block size */ unsigned short b_list; /* List that this buffer appears */ kdev_t b_dev; /* device (B_FREE = free) */ diff -u -Nur linux-2.4.25/include/linux/highmem.h linux-ia64-2.4/include/linux/highmem.h --- linux-2.4.25/include/linux/highmem.h 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/include/linux/highmem.h 2004-02-18 09:51:30.000000000 -0700 @@ -84,7 +84,7 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr) { void *addr = kmap_atomic(page, KM_USER0); - clear_user_page(addr, vaddr); + clear_user_page(addr, vaddr, page); kunmap_atomic(addr, KM_USER0); } @@ -116,7 +116,7 @@ vfrom = kmap_atomic(from, KM_USER0); vto = kmap_atomic(to, KM_USER1); - copy_user_page(vto, vfrom, vaddr); + copy_user_page(vto, vfrom, vaddr, to); kunmap_atomic(vfrom, KM_USER0); kunmap_atomic(vto, KM_USER1); } diff -u -Nur linux-2.4.25/include/linux/hugetlb.h linux-ia64-2.4/include/linux/hugetlb.h --- linux-2.4.25/include/linux/hugetlb.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-ia64-2.4/include/linux/hugetlb.h 2004-02-18 09:51:21.000000000 -0700 @@ -0,0 +1,102 @@ +#ifndef _LINUX_HUGETLB_H +#define _LINUX_HUGETLB_H + +#ifdef CONFIG_HUGETLB_PAGE + +#define COLOR_HALIGN(addr) ((addr + HPAGE_SIZE - 1) & ~(HPAGE_SIZE - 1)) +struct ctl_table; + +static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) +{ + return vma->vm_flags & VM_HUGETLB; +} +static inline int is_hugepage_addr(unsigned long addr) +{ + return (rgn_index(addr) == REGION_HPAGE); +} + +int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void *, size_t *); +int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); +int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int); +void zap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); +void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long); +int hugetlb_prefault(struct address_space *, struct vm_area_struct *); +void huge_page_release(struct page *); +int hugetlb_report_meminfo(char *); +int is_hugepage_mem_enough(size_t); +int is_aligned_hugepage_range(unsigned long addr, unsigned long len); +void hugetlb_free_pgtables(struct mm_struct * mm, struct vm_area_struct * prev, + unsigned long start, unsigned long end); + +extern int htlbpage_max; + +#else /* !CONFIG_HUGETLB_PAGE */ +static inline int is_vm_hugetlb_page(struct vm_area_struct *vma) +{ + return 0; +} + +#define follow_hugetlb_page(m,v,p,vs,a,b,i) ({ BUG(); 0; }) +#define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; }) +#define hugetlb_prefault(mapping, vma) ({ BUG(); 0; }) +#define zap_hugepage_range(vma, start, len) BUG() +#define unmap_hugepage_range(vma, start, end) BUG() +#define huge_page_release(page) BUG() +#define hugetlb_report_meminfo(buf) 0 +#define is_hugepage_mem_enough(size) 0 +#define is_hugepage_addr(addr) 0 +#define is_aligned_hugepage_range(addr, len) 0 +#define hugetlb_free_pgtables(mm, prev, start, end) do { } while (0) + +#endif /* !CONFIG_HUGETLB_PAGE */ + +#ifdef CONFIG_HUGETLBFS +struct hugetlbfs_config { + uid_t uid; + gid_t gid; + umode_t mode; + long nr_blocks; + long nr_inodes; +}; + +struct hugetlbfs_sb_info { + long max_blocks; /* How many blocks are allowed */ + long free_blocks; /* How many are left for allocation */ + long max_inodes; /* How many inodes are allowed */ + long free_inodes; /* How many are left for allocation */ + spinlock_t stat_lock; +}; + +static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) +{ + return sb->u.generic_sbp; +} + +#define PSEUDO_DIRENT_SIZE 20 + +extern struct file_operations hugetlbfs_file_operations; +extern struct vm_operations_struct hugetlb_vm_ops; +struct file *hugetlb_zero_setup(size_t); +int hugetlb_get_quota(struct address_space *mapping); +void hugetlb_put_quota(struct address_space *mapping); + +static inline int is_file_hugepages(struct file *file) +{ + return file->f_op == &hugetlbfs_file_operations; +} + +static inline void set_file_hugepages(struct file *file) +{ + file->f_op = &hugetlbfs_file_operations; +} +#else /* !CONFIG_HUGETLBFS */ + +#define is_file_hugepages(file) 0 +#define set_file_hugepages(file) BUG() +#define hugetlb_zero_setup(size) ERR_PTR(-ENOSYS) +#define hugetlb_get_quota(mapping) 0 +#define hugetlb_put_quota(mapping) 0 + +#endif /* !CONFIG_HUGETLBFS */ + +#endif /* _LINUX_HUGETLB_H */ diff -u -Nur linux-2.4.25/include/linux/irq.h linux-ia64-2.4/include/linux/irq.h --- linux-2.4.25/include/linux/irq.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/include/linux/irq.h 2004-02-18 09:51:22.000000000 -0700 @@ -56,7 +56,7 @@ * * Pad this out to 32 bytes for cache and indexing reasons. */ -typedef struct { +typedef struct irq_desc { unsigned int status; /* IRQ status */ hw_irq_controller *handler; struct irqaction *action; /* IRQ action list */ @@ -64,8 +64,6 @@ spinlock_t lock; } ____cacheline_aligned irq_desc_t; -extern irq_desc_t irq_desc [NR_IRQS]; - #include /* the arch dependent stuff */ extern int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *); diff -u -Nur linux-2.4.25/include/linux/irq_cpustat.h linux-ia64-2.4/include/linux/irq_cpustat.h --- linux-2.4.25/include/linux/irq_cpustat.h 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/include/linux/irq_cpustat.h 2004-02-18 09:51:21.000000000 -0700 @@ -23,15 +23,31 @@ #define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) #else #define __IRQ_STAT(cpu, member) ((void)(cpu), irq_stat[0].member) -#endif +#endif /* arch independent irq_stat fields */ #define softirq_pending(cpu) __IRQ_STAT((cpu), __softirq_pending) -#define local_irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) -#define local_bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) +#define irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) +#define bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) #define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) #define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) /* arch dependent irq_stat fields */ #define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386, ia64 */ +#define local_hardirq_trylock() hardirq_trylock(smp_processor_id()) +#define local_hardirq_endlock() hardirq_trylock(smp_processor_id()) +#define local_irq_enter(irq) irq_enter(smp_processor_id(), (irq)) +#define local_irq_exit(irq) irq_exit(smp_processor_id(), (irq)) +#define local_softirq_pending() softirq_pending(smp_processor_id()) +#define local_ksoftirqd_task() ksoftirqd_task(smp_processor_id()) + +/* These will lose the "really_" prefix when the interim macros below are removed. */ +#define really_local_irq_count()irq_count(smp_processor_id()) +#define really_local_bh_count() bh_count(smp_processor_id()) + +/* Interim macros for backward compatibility. They are deprecated. Use irq_count() and + bh_count() instead. --davidm 01/11/28 */ +#define local_irq_count(cpu) irq_count(cpu) +#define local_bh_count(cpu) bh_count(cpu) + #endif /* __irq_cpustat_h */ diff -u -Nur linux-2.4.25/include/linux/mm.h linux-ia64-2.4/include/linux/mm.h --- linux-2.4.25/include/linux/mm.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/include/linux/mm.h 2004-02-18 09:51:04.000000000 -0700 @@ -103,6 +103,9 @@ #define VM_DONTCOPY 0x00020000 /* Do not copy this vma on fork */ #define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ #define VM_RESERVED 0x00080000 /* Don't unmap it from swap_out */ +#define VM_WRITECOMBINED 0x00100000 /* Write-combined */ +#define VM_NONCACHED 0x00200000 /* Noncached access */ +#define VM_HUGETLB 0x00400000 /* Huge tlb Page*/ #ifndef VM_STACK_FLAGS #define VM_STACK_FLAGS 0x00000177 diff -u -Nur linux-2.4.25/include/linux/mmzone.h linux-ia64-2.4/include/linux/mmzone.h --- linux-2.4.25/include/linux/mmzone.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/include/linux/mmzone.h 2004-02-18 09:51:03.000000000 -0700 @@ -8,6 +8,12 @@ #include #include #include +#ifdef CONFIG_DISCONTIGMEM +#include +#endif +#ifndef MAX_NUMNODES +#define MAX_NUMNODES 1 +#endif /* * Free memory management - zoned buddy allocator. @@ -134,7 +140,7 @@ * footprint of this construct is very small. */ typedef struct zonelist_struct { - zone_t * zones [MAX_NR_ZONES+1]; // NULL delimited + zone_t * zones [MAX_NUMNODES*MAX_NR_ZONES+1]; // NULL delimited } zonelist_t; #define GFP_ZONEMASK 0x0f @@ -236,6 +242,18 @@ #define for_each_zone(zone) \ for(zone = pgdat_list->node_zones; zone; zone = next_zone(zone)) +#ifdef CONFIG_NUMA +#define MAX_NR_MEMBLKS BITS_PER_LONG /* Max number of Memory Blocks */ +#include +#else /* !CONFIG_NUMA */ +#define MAX_NR_MEMBLKS 1 +#endif /* CONFIG_NUMA */ + +/* Returns the number of the current Node. */ + +#ifndef CONFIG_NUMA +#define numa_node_id() (__cpu_to_node(smp_processor_id())) +#endif #ifndef CONFIG_DISCONTIGMEM diff -u -Nur linux-2.4.25/include/linux/shm.h linux-ia64-2.4/include/linux/shm.h --- linux-2.4.25/include/linux/shm.h 2004-02-18 09:52:39.000000000 -0700 +++ linux-ia64-2.4/include/linux/shm.h 2004-02-18 09:51:29.000000000 -0700 @@ -75,6 +75,7 @@ /* shm_mode upper byte flags */ #define SHM_DEST 01000 /* segment will be destroyed on last detach */ #define SHM_LOCKED 02000 /* segment will not be swapped */ +#define SHM_HUGETLB 04000 /* segment will use HugeTLB pages */ asmlinkage long sys_shmget (key_t key, size_t size, int flag); asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr); diff -u -Nur linux-2.4.25/include/linux/smp.h linux-ia64-2.4/include/linux/smp.h --- linux-2.4.25/include/linux/smp.h 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/include/linux/smp.h 2004-02-18 09:51:24.000000000 -0700 @@ -35,11 +35,6 @@ extern void smp_boot_cpus(void); /* - * Processor call in. Must hold processors until .. - */ -extern void smp_callin(void); - -/* * Multiprocessors may now schedule */ extern void smp_commence(void); @@ -57,10 +52,6 @@ extern int smp_num_cpus; -extern volatile unsigned long smp_msg_data; -extern volatile int smp_src_cpu; -extern volatile int smp_msg_id; - #define MSG_ALL_BUT_SELF 0x8000 /* Assume <32768 CPU's */ #define MSG_ALL 0x8001 @@ -86,6 +77,7 @@ #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) ({ 0; }) #define cpu_online_map 1 +#define cpu_online(cpu) (cpu == 0) #endif #endif diff -u -Nur linux-2.4.25/include/linux/sysctl.h linux-ia64-2.4/include/linux/sysctl.h --- linux-2.4.25/include/linux/sysctl.h 2004-02-18 09:52:06.000000000 -0700 +++ linux-ia64-2.4/include/linux/sysctl.h 2004-02-18 09:51:03.000000000 -0700 @@ -156,6 +156,7 @@ VM_MAPPED_RATIO=20, /* amount of unfreeable pages that triggers swapout */ VM_LAPTOP_MODE=21, /* kernel in laptop flush mode */ VM_BLOCK_DUMP=22, /* dump fs activity to log */ + VM_HUGETLB_PAGES=23, /* int: Number of available Huge Pages */ }; diff -u -Nur linux-2.4.25/init/main.c linux-ia64-2.4/init/main.c --- linux-2.4.25/init/main.c 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/init/main.c 2004-02-18 09:51:06.000000000 -0700 @@ -291,6 +291,7 @@ extern void setup_arch(char **); +extern void __init build_all_zonelists(void); extern void cpu_idle(void); unsigned long wait_init_idle; @@ -361,6 +362,7 @@ lock_kernel(); printk(linux_banner); setup_arch(&command_line); + build_all_zonelists(); printk("Kernel command line: %s\n", saved_command_line); parse_options(command_line); trap_init(); diff -u -Nur linux-2.4.25/ipc/shm.c linux-ia64-2.4/ipc/shm.c --- linux-2.4.25/ipc/shm.c 2004-02-18 09:52:35.000000000 -0700 +++ linux-ia64-2.4/ipc/shm.c 2004-02-18 09:51:23.000000000 -0700 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -125,7 +126,8 @@ shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; shm_rmid (shp->id); shm_unlock(shp->id); - shmem_lock(shp->shm_file, 0); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 0); fput (shp->shm_file); kfree (shp); } @@ -193,8 +195,12 @@ shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_USER); if (!shp) return -ENOMEM; - sprintf (name, "SYSV%08x", key); - file = shmem_file_setup(name, size); + if (shmflg & SHM_HUGETLB) + file = hugetlb_zero_setup(size); + else { + sprintf (name, "SYSV%08x", key); + file = shmem_file_setup(name, size); + } error = PTR_ERR(file); if (IS_ERR(file)) goto no_file; @@ -214,7 +220,10 @@ shp->id = shm_buildid(id,shp->shm_perm.seq); shp->shm_file = file; file->f_dentry->d_inode->i_ino = shp->id; - file->f_op = &shm_file_operations; + if (shmflg & SHM_HUGETLB) + set_file_hugepages(file); + else + file->f_op = &shm_file_operations; shm_tot += numpages; shm_unlock (id); return shp->id; @@ -452,7 +461,10 @@ tbuf.shm_ctime = shp->shm_ctim; tbuf.shm_cpid = shp->shm_cprid; tbuf.shm_lpid = shp->shm_lprid; - tbuf.shm_nattch = shp->shm_nattch; + if (!is_file_hugepages(shp->shm_file)) + tbuf.shm_nattch = shp->shm_nattch; + else + tbuf.shm_nattch = file_count(shp->shm_file)-1; shm_unlock(shmid); if(copy_shmid_to_user (buf, &tbuf, version)) return -EFAULT; @@ -474,10 +486,12 @@ if(err) goto out_unlock; if(cmd==SHM_LOCK) { - shmem_lock(shp->shm_file, 1); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 1); shp->shm_flags |= SHM_LOCKED; } else { - shmem_lock(shp->shm_file, 0); + if (!is_file_hugepages(shp->shm_file)) + shmem_lock(shp->shm_file, 0); shp->shm_flags &= ~SHM_LOCKED; } shm_unlock(shmid); @@ -678,7 +692,7 @@ down_write(&mm->mmap_sem); for (shmd = mm->mmap; shmd; shmd = shmdnext) { shmdnext = shmd->vm_next; - if (shmd->vm_ops == &shm_vm_ops + if (((shmd->vm_ops == &shm_vm_ops) || is_vm_hugetlb_page(shmd)) && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) { do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); retval = 0; @@ -718,7 +732,7 @@ shp->shm_segsz, shp->shm_cprid, shp->shm_lprid, - shp->shm_nattch, + is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file)-1) : shp->shm_nattch, shp->shm_perm.uid, shp->shm_perm.gid, shp->shm_perm.cuid, diff -u -Nur linux-2.4.25/kernel/printk.c linux-ia64-2.4/kernel/printk.c --- linux-2.4.25/kernel/printk.c 2004-02-18 09:52:54.000000000 -0700 +++ linux-ia64-2.4/kernel/printk.c 2004-02-18 09:51:42.000000000 -0700 @@ -330,6 +330,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 } /* @@ -696,3 +702,101 @@ tty->driver.write(tty, 0, msg, strlen(msg)); return; } + +#ifdef CONFIG_IA64_EARLY_PRINTK + +#include + +#ifdef CONFIG_IA64_EARLY_PRINTK_UART + +#include +#include + +static void early_printk_uart(const char *str, size_t len) +{ + static char *uart = 0; + unsigned long uart_base; + char c; + + if (!uart) { +#ifdef CONFIG_SERIAL_HCDP + extern unsigned long hcdp_early_uart(void); + uart_base = hcdp_early_uart(); +#endif +#if CONFIG_IA64_EARLY_PRINTK_UART_BASE + uart_base = CONFIG_IA64_EARLY_PRINTK_UART_BASE; +#endif + if (uart_base) + uart = ioremap(uart_base, 64); + } + + if (!uart) + return; + + while (len-- > 0) { + c = *str++; + while (!(UART_LSR_TEMT & readb(uart + UART_LSR))) + ; /* 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_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 */ + +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 +} + +#endif /* CONFIG_IA64_EARLY_PRINTK */ diff -u -Nur linux-2.4.25/kernel/signal.c linux-ia64-2.4/kernel/signal.c --- linux-2.4.25/kernel/signal.c 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/kernel/signal.c 2004-02-18 09:51:22.000000000 -0700 @@ -1171,8 +1171,19 @@ ss_sp = NULL; } else { error = -ENOMEM; +#ifdef __ia64__ + /* + * XXX fix me: due to an oversight, MINSIGSTKSZ used to be defined + * as 2KB, which is far too small. This was after Linux kernel + * 2.4.9 but since there are a fair number of ia64 apps out there, + * we continue to allow "too" small sigaltstacks for a while. + */ + if (ss_size < 2048) + goto out; +#else if (ss_size < MINSIGSTKSZ) goto out; +#endif } current->sas_ss_sp = (unsigned long) ss_sp; diff -u -Nur linux-2.4.25/kernel/softirq.c linux-ia64-2.4/kernel/softirq.c --- linux-2.4.25/kernel/softirq.c 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/kernel/softirq.c 2004-02-18 09:51:18.000000000 -0700 @@ -40,7 +40,10 @@ - Bottom halves: globally serialized, grr... */ +/* No separate irq_stat for ia64, it is part of PSA */ +#if !defined(CONFIG_IA64) irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned; +#endif static struct softirq_action softirq_vec[32] __cacheline_aligned; @@ -60,7 +63,6 @@ asmlinkage void do_softirq() { - int cpu = smp_processor_id(); __u32 pending; unsigned long flags; __u32 mask; @@ -70,7 +72,7 @@ local_irq_save(flags); - pending = softirq_pending(cpu); + pending = local_softirq_pending(); if (pending) { struct softirq_action *h; @@ -79,7 +81,7 @@ local_bh_disable(); restart: /* Reset the pending bitmask before enabling irqs */ - softirq_pending(cpu) = 0; + local_softirq_pending() = 0; local_irq_enable(); @@ -94,7 +96,7 @@ local_irq_disable(); - pending = softirq_pending(cpu); + pending = local_softirq_pending(); if (pending & mask) { mask &= ~pending; goto restart; @@ -102,7 +104,7 @@ __local_bh_enable(); if (pending) - wakeup_softirqd(cpu); + wakeup_softirqd(smp_processor_id()); } local_irq_restore(flags); @@ -124,7 +126,7 @@ * Otherwise we wake up ksoftirqd to make sure we * schedule the softirq soon. */ - if (!(local_irq_count(cpu) | local_bh_count(cpu))) + if (!(irq_count(cpu) | bh_count(cpu))) wakeup_softirqd(cpu); } @@ -287,18 +289,16 @@ static void bh_action(unsigned long nr) { - int cpu = smp_processor_id(); - if (!spin_trylock(&global_bh_lock)) goto resched; - if (!hardirq_trylock(cpu)) + if (!local_hardirq_trylock()) goto resched_unlock; if (bh_base[nr]) bh_base[nr](); - hardirq_endlock(cpu); + local_hardirq_endlock(); spin_unlock(&global_bh_lock); return; @@ -377,15 +377,15 @@ __set_current_state(TASK_INTERRUPTIBLE); mb(); - ksoftirqd_task(cpu) = current; + local_ksoftirqd_task() = current; for (;;) { - if (!softirq_pending(cpu)) + if (!local_softirq_pending()) schedule(); __set_current_state(TASK_RUNNING); - while (softirq_pending(cpu)) { + while (local_softirq_pending()) { do_softirq(); if (current->need_resched) schedule(); diff -u -Nur linux-2.4.25/kernel/sysctl.c linux-ia64-2.4/kernel/sysctl.c --- linux-2.4.25/kernel/sysctl.c 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/kernel/sysctl.c 2004-02-18 09:51:04.000000000 -0700 @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -312,6 +313,10 @@ &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec}, {VM_BLOCK_DUMP, "block_dump", &block_dump, sizeof(int), 0644, NULL, &proc_dointvec}, +#ifdef CONFIG_HUGETLB_PAGE + {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, + &hugetlb_sysctl_handler}, +#endif {0} }; diff -u -Nur linux-2.4.25/kernel/time.c linux-ia64-2.4/kernel/time.c --- linux-2.4.25/kernel/time.c 2004-02-18 09:52:25.000000000 -0700 +++ linux-ia64-2.4/kernel/time.c 2004-02-18 09:51:08.000000000 -0700 @@ -39,6 +39,7 @@ /* The xtime_lock is not only serializing the xtime read/writes but it's also serializing all accesses to the global NTP variables now. */ extern rwlock_t xtime_lock; +extern unsigned long last_time_offset; #if !defined(__alpha__) && !defined(__ia64__) @@ -84,6 +85,7 @@ xtime.tv_sec = value; xtime.tv_usec = 0; vxtime_unlock(); + last_time_offset = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; @@ -131,6 +133,7 @@ vxtime_lock(); xtime.tv_sec += sys_tz.tz_minuteswest * 60; vxtime_unlock(); + last_time_offset = 0; write_unlock_irq(&xtime_lock); } @@ -217,7 +220,7 @@ /* In order to modify anything, you gotta be super-user! */ if (txc->modes && !capable(CAP_SYS_TIME)) return -EPERM; - + /* Now we validate the data before disabling interrupts */ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) @@ -228,7 +231,7 @@ if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET)) /* adjustment Offset limited to +- .512 seconds */ if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE ) - return -EINVAL; + return -EINVAL; /* if the quartz is off by more than 10% something is VERY wrong ! */ if (txc->modes & ADJ_TICK) @@ -365,7 +368,7 @@ && (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0)) /* p. 24, (d) */ result = TIME_ERROR; - + if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) txc->offset = save_adjust; else { @@ -390,6 +393,7 @@ txc->calcnt = pps_calcnt; txc->errcnt = pps_errcnt; txc->stbcnt = pps_stbcnt; + last_time_offset = 0; write_unlock_irq(&xtime_lock); do_gettimeofday(&txc->time); return(result); diff -u -Nur linux-2.4.25/kernel/timer.c linux-ia64-2.4/kernel/timer.c --- linux-2.4.25/kernel/timer.c 2004-02-18 09:52:27.000000000 -0700 +++ linux-ia64-2.4/kernel/timer.c 2004-02-18 09:51:19.000000000 -0700 @@ -615,7 +615,7 @@ else kstat.per_cpu_user[cpu] += user_tick; kstat.per_cpu_system[cpu] += system; - } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) + } else if (really_local_bh_count() || really_local_irq_count() > 1) kstat.per_cpu_system[cpu] += system; } @@ -667,6 +667,7 @@ * This spinlock protect us from races in SMP while playing with xtime. -arca */ rwlock_t xtime_lock = RW_LOCK_UNLOCKED; +unsigned long last_time_offset; static inline void update_times(void) { @@ -686,6 +687,7 @@ update_wall_time(ticks); } vxtime_unlock(); + last_time_offset = 0; write_unlock_irq(&xtime_lock); calc_load(ticks); } @@ -698,7 +700,7 @@ void do_timer(struct pt_regs *regs) { - (*(unsigned long *)&jiffies)++; + (*(volatile unsigned long *)&jiffies)++; #ifndef CONFIG_SMP /* SMP process accounting uses the local APIC timer */ @@ -844,7 +846,7 @@ if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0) return -EINVAL; - +#if !defined(__ia64__) if (t.tv_sec == 0 && t.tv_nsec <= 2000000L && current->policy != SCHED_OTHER) { @@ -857,6 +859,7 @@ udelay((t.tv_nsec + 999) / 1000); return 0; } +#endif expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); diff -u -Nur linux-2.4.25/mm/bootmem.c linux-ia64-2.4/mm/bootmem.c --- linux-2.4.25/mm/bootmem.c 2004-02-18 09:52:29.000000000 -0700 +++ linux-ia64-2.4/mm/bootmem.c 2004-02-18 09:51:19.000000000 -0700 @@ -49,8 +49,24 @@ bootmem_data_t *bdata = pgdat->bdata; unsigned long mapsize = ((end - start)+7)/8; - pgdat->node_next = pgdat_list; - pgdat_list = pgdat; + + /* + * sort pgdat_list so that the lowest one comes first, + * which makes alloc_bootmem_low_pages work as desired. + */ + if (!pgdat_list || pgdat_list->node_start_paddr > pgdat->node_start_paddr) { + pgdat->node_next = pgdat_list; + pgdat_list = pgdat; + } else { + pg_data_t *tmp = pgdat_list; + while (tmp->node_next) { + if (tmp->node_next->node_start_paddr > pgdat->node_start_paddr) + break; + tmp = tmp->node_next; + } + pgdat->node_next = tmp->node_next; + tmp->node_next = pgdat; + } mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL); bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT); @@ -144,6 +160,7 @@ static void * __init __alloc_bootmem_core (bootmem_data_t *bdata, unsigned long size, unsigned long align, unsigned long goal) { + static unsigned long last_success; unsigned long i, start = 0; void *ret; unsigned long offset, remaining_size; @@ -169,6 +186,9 @@ if (goal && (goal >= bdata->node_boot_start) && ((goal >> PAGE_SHIFT) < bdata->node_low_pfn)) { preferred = goal - bdata->node_boot_start; + + if (last_success >= preferred) + preferred = last_success; } else preferred = 0; @@ -180,6 +200,8 @@ restart_scan: for (i = preferred; i < eidx; i += incr) { unsigned long j; + i = find_next_zero_bit((char *)bdata->node_bootmem_map, eidx, i); + i = (i + incr - 1) & -incr; if (test_bit(i, bdata->node_bootmem_map)) continue; for (j = i + 1; j < i + areasize; ++j) { @@ -198,6 +220,7 @@ } return NULL; found: + last_success = start << PAGE_SHIFT; if (start >= eidx) BUG(); @@ -244,22 +267,24 @@ static unsigned long __init free_all_bootmem_core(pg_data_t *pgdat) { - struct page *page = pgdat->node_mem_map; bootmem_data_t *bdata = pgdat->bdata; unsigned long i, count, total = 0; + struct page *page; unsigned long idx; if (!bdata->node_bootmem_map) BUG(); count = 0; + page = virt_to_page(phys_to_virt(bdata->node_boot_start)); idx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); - for (i = 0; i < idx; i++, page++) { - if (!test_bit(i, bdata->node_bootmem_map)) { - count++; - ClearPageReserved(page); - set_page_count(page, 1); - __free_page(page); - } + for (i = find_first_zero_bit(bdata->node_bootmem_map, idx); + i < idx; + i = find_next_zero_bit(bdata->node_bootmem_map, idx, i + 1)) + { + count++; + ClearPageReserved(page+i); + set_page_count(page+i, 1); + __free_page(page+i); } total += count; diff -u -Nur linux-2.4.25/mm/memory.c linux-ia64-2.4/mm/memory.c --- linux-2.4.25/mm/memory.c 2004-02-18 09:52:31.000000000 -0700 +++ linux-ia64-2.4/mm/memory.c 2004-02-18 09:51:23.000000000 -0700 @@ -37,6 +37,7 @@ */ #include +#include #include #include #include @@ -121,7 +122,7 @@ pmd = pmd_offset(dir, 0); pgd_clear(dir); for (j = 0; j < PTRS_PER_PMD ; j++) { - prefetchw(pmd+j+(PREFETCH_STRIDE/16)); + prefetchw(pmd + j + PREFETCH_STRIDE/sizeof(*pmd)); free_one_pmd(pmd+j); } pmd_free(pmd); @@ -181,6 +182,9 @@ unsigned long end = vma->vm_end; unsigned long cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; + if (is_vm_hugetlb_page(vma)) + return copy_hugetlb_page_range(dst, src, vma); + src_pgd = pgd_offset(src, address)-1; dst_pgd = pgd_offset(dst, address)-1; @@ -473,6 +477,10 @@ if ( !vma || (pages && vma->vm_flags & VM_IO) || !(flags & vma->vm_flags) ) return i ? : -EFAULT; + if (is_vm_hugetlb_page(vma)) { + i = follow_hugetlb_page(mm, vma, pages, vmas, &start, &len, i); + continue; + } spin_lock(&mm->page_table_lock); do { struct page *map; @@ -1371,6 +1379,9 @@ current->state = TASK_RUNNING; pgd = pgd_offset(mm, address); + if (is_vm_hugetlb_page(vma)) + return 0; /* mapping truncation does this. */ + /* * We need the page table lock to synchronize with kswapd * and the SMP-safe atomic PTE updates. diff -u -Nur linux-2.4.25/mm/mmap.c linux-ia64-2.4/mm/mmap.c --- linux-2.4.25/mm/mmap.c 2004-02-18 09:52:38.000000000 -0700 +++ linux-ia64-2.4/mm/mmap.c 2004-02-18 09:51:24.000000000 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -600,7 +601,10 @@ fput(file); /* Undo any partial mapping done by a device driver. */ - zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start); + if (is_vm_hugetlb_page(vma)) + zap_hugepage_range(vma, vma->vm_start, vma->vm_end-vma->vm_start); + else + zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start); free_vma: kmem_cache_free(vm_area_cachep, vma); return error; @@ -650,10 +654,26 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { if (flags & MAP_FIXED) { + unsigned long ret; + if (addr > TASK_SIZE - len) return -ENOMEM; if (addr & ~PAGE_MASK) return -EINVAL; + if (file && is_file_hugepages(file)) + /* If the request is for hugepages, then make sure + * that addr and length is properly aligned. + */ + ret = is_aligned_hugepage_range(addr, len); + else + /* + * Make sure that a normal request is not falling + * in reserved hugepage range. For some archs like + * IA-64, there is a separate region for hugepages. + */ + ret = is_invalid_hugepage_range(addr, len); + if (ret) + return ret; return addr; } @@ -947,6 +967,12 @@ return 0; /* we have addr < mpnt->vm_end */ + if (is_vm_hugetlb_page(mpnt)) { + int ret = is_aligned_hugepage_range(addr, len); + if (ret) + return ret; + } + if (mpnt->vm_start >= addr+len) return 0; @@ -1000,7 +1026,10 @@ remove_shared_vm_struct(mpnt); mm->map_count--; - zap_page_range(mm, st, size); + if (is_vm_hugetlb_page(mpnt)) + zap_hugepage_range(mpnt, st, size); + else + zap_page_range(mm, st, size); /* * Fix the mapping, and free the old area if it wasn't reused. @@ -1015,7 +1044,10 @@ if (extra) kmem_cache_free(vm_area_cachep, extra); - free_pgtables(mm, prev, addr, addr+len); + if (is_hugepage_addr(addr)) + hugetlb_free_pgtables(mm, prev, addr, addr+len); + else + free_pgtables(mm, prev, addr, addr+len); return 0; } @@ -1160,7 +1192,10 @@ } mm->map_count--; remove_shared_vm_struct(mpnt); - zap_page_range(mm, start, size); + if (is_vm_hugetlb_page(mpnt)) + zap_hugepage_range(mpnt, start, size); + else + zap_page_range(mm, start, size); if (mpnt->vm_file) fput(mpnt->vm_file); kmem_cache_free(vm_area_cachep, mpnt); diff -u -Nur linux-2.4.25/mm/mprotect.c linux-ia64-2.4/mm/mprotect.c --- linux-2.4.25/mm/mprotect.c 2004-02-18 09:52:30.000000000 -0700 +++ linux-ia64-2.4/mm/mprotect.c 2004-02-18 09:51:22.000000000 -0700 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -294,6 +295,10 @@ /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ + if (is_vm_hugetlb_page(vma)) { + error = -EACCES; + goto out; + } newflags = prot | (vma->vm_flags & ~(PROT_READ | PROT_WRITE | PROT_EXEC)); if ((newflags & ~(newflags >> 4)) & 0xf) { error = -EACCES; diff -u -Nur linux-2.4.25/mm/mremap.c linux-ia64-2.4/mm/mremap.c --- linux-2.4.25/mm/mremap.c 2004-02-18 09:52:37.000000000 -0700 +++ linux-ia64-2.4/mm/mremap.c 2004-02-18 09:51:24.000000000 -0700 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -283,6 +284,10 @@ vma = find_vma(current->mm, addr); if (!vma || vma->vm_start > addr) goto out; + if (is_vm_hugetlb_page(vma)) { + ret = -EINVAL; + goto out; + } /* We can't remap across vm area boundaries */ if (old_len > vma->vm_end - addr) goto out; diff -u -Nur linux-2.4.25/mm/page_alloc.c linux-ia64-2.4/mm/page_alloc.c --- linux-2.4.25/mm/page_alloc.c 2004-02-18 09:52:07.000000000 -0700 +++ linux-ia64-2.4/mm/page_alloc.c 2004-02-18 09:51:04.000000000 -0700 @@ -49,11 +49,11 @@ /* * Temporary debugging check. */ -#define BAD_RANGE(zone, page) \ -( \ - (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \ - || (((page) - mem_map) < (zone)->zone_start_mapnr) \ - || ((zone) != page_zone(page)) \ +#define BAD_RANGE(zone, page) \ +( \ + (((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \ + || (((page) - mem_map) < (zone)->zone_start_mapnr) \ + || ((zone) != page_zone(page)) \ ) /* @@ -592,7 +592,7 @@ unsigned long nr, total, flags; total = 0; - if (zone->size) { + if (zone->realsize) { spin_lock_irqsave(&zone->lock, flags); for (order = 0; order < MAX_ORDER; order++) { head = &(zone->free_area + order)->free_list; @@ -624,13 +624,44 @@ /* * Builds allocation fallback zone lists. */ -static inline void build_zonelists(pg_data_t *pgdat) +static int __init build_zonelists_node(pg_data_t *pgdat, zonelist_t *zonelist, int j, int k) { - int i, j, k; + zone_t *zone; + switch (k) { + default: + BUG(); + /* + * fallthrough: + */ + case ZONE_HIGHMEM: + zone = pgdat->node_zones + ZONE_HIGHMEM; + if (zone->realsize) { +#ifndef CONFIG_HIGHMEM + BUG(); +#endif + zonelist->zones[j++] = zone; + } + case ZONE_NORMAL: + zone = pgdat->node_zones + ZONE_NORMAL; + if (zone->realsize) + zonelist->zones[j++] = zone; + case ZONE_DMA: + zone = pgdat->node_zones + ZONE_DMA; + if (zone->realsize) + zonelist->zones[j++] = zone; + } + + return j; +} + +static void __init build_zonelists(pg_data_t *pgdat) +{ + int i, j, k, node, local_node; + local_node = pgdat->node_id; + printk("Building zonelist for node : %d\n", local_node); for (i = 0; i <= GFP_ZONEMASK; i++) { zonelist_t *zonelist; - zone_t *zone; zonelist = pgdat->node_zonelists + i; memset(zonelist, 0, sizeof(*zonelist)); @@ -642,33 +673,32 @@ if (i & __GFP_DMA) k = ZONE_DMA; - switch (k) { - default: - BUG(); - /* - * fallthrough: - */ - case ZONE_HIGHMEM: - zone = pgdat->node_zones + ZONE_HIGHMEM; - if (zone->size) { -#ifndef CONFIG_HIGHMEM - BUG(); -#endif - zonelist->zones[j++] = zone; - } - case ZONE_NORMAL: - zone = pgdat->node_zones + ZONE_NORMAL; - if (zone->size) - zonelist->zones[j++] = zone; - case ZONE_DMA: - zone = pgdat->node_zones + ZONE_DMA; - if (zone->size) - zonelist->zones[j++] = zone; - } + j = build_zonelists_node(pgdat, zonelist, j, k); + /* + * Now we build the zonelist so that it contains the zones + * of all the other nodes. + * We don't want to pressure a particular node, so when + * building the zones for node N, we make sure that the + * zones coming right after the local ones are those from + * node N+1 (modulo N) + */ + for (node = local_node + 1; node < numnodes; node++) + j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); + for (node = 0; node < local_node; node++) + j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); + zonelist->zones[j++] = NULL; } } +void __init build_all_zonelists(void) +{ + int i; + + for(i = 0 ; i < numnodes ; i++) + build_zonelists(NODE_DATA(i)); +} + /* * Helper functions to size the waitqueue hash table. * Essentially these want to choose hash table sizes sufficiently @@ -711,6 +741,31 @@ return ffz(~size); } +static unsigned long memmap_init(struct page *start, struct page *end, + int zone, unsigned long start_paddr, int highmem) +{ + struct page *page; + + for (page = start; page < end; page++) { + set_page_zone(page, zone); + set_page_count(page, 0); + SetPageReserved(page); + INIT_LIST_HEAD(&page->list); + if (!highmem) + set_page_address(page, __va(start_paddr)); + start_paddr += PAGE_SIZE; + } + return start_paddr; +} + +#ifdef HAVE_ARCH_MEMMAP_INIT +#define MEMMAP_INIT(start, end, zone, paddr, highmem) \ + arch_memmap_init(memmap_init, start, end, zone, paddr, highmem) +#else +#define MEMMAP_INIT(start, end, zone, paddr, highmem) \ + memmap_init(start, end, zone, paddr, highmem) +#endif + #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) /* @@ -732,10 +787,8 @@ BUG(); totalpages = 0; - for (i = 0; i < MAX_NR_ZONES; i++) { - unsigned long size = zones_size[i]; - totalpages += size; - } + for (i = 0; i < MAX_NR_ZONES; i++) + totalpages += zones_size[i]; realtotalpages = totalpages; if (zholes_size) for (i = 0; i < MAX_NR_ZONES; i++) @@ -744,7 +797,7 @@ printk("On node %d totalpages: %lu\n", nid, realtotalpages); /* - * Some architectures (with lots of mem and discontinous memory + * Some architectures (with lots of mem and discontigous memory * maps) have to search for a good mem_map area: * For discontigmem, the conceptual mem map array starts from * PAGE_OFFSET, we need to align the actual array onto a mem map @@ -757,7 +810,7 @@ MAP_ALIGN((unsigned long)lmem_map - PAGE_OFFSET)); } *gmap = pgdat->node_mem_map = lmem_map; - pgdat->node_size = totalpages; + pgdat->node_size = 0; pgdat->node_start_paddr = zone_start_paddr; pgdat->node_start_mapnr = (lmem_map - mem_map); pgdat->nr_zones = 0; @@ -774,7 +827,7 @@ if (zholes_size) realsize -= zholes_size[j]; - printk("zone(%lu): %lu pages.\n", j, size); + printk("zone(%lu): %lu pages.\n", j, realsize); zone->size = size; zone->realsize = realsize; zone->name = zone_names[j]; @@ -785,6 +838,7 @@ zone->nr_active_pages = zone->nr_inactive_pages = 0; + pgdat->node_size += realsize; if (!size) continue; @@ -845,16 +899,10 @@ * up by free_all_bootmem() once the early boot process is * done. Non-atomic initialization, single-pass. */ - for (i = 0; i < size; i++) { - struct page *page = mem_map + offset + i; - set_page_zone(page, nid * MAX_NR_ZONES + j); - set_page_count(page, 0); - SetPageReserved(page); - INIT_LIST_HEAD(&page->list); - if (j != ZONE_HIGHMEM) - set_page_address(page, __va(zone_start_paddr)); - zone_start_paddr += PAGE_SIZE; - } + zone_start_paddr = MEMMAP_INIT(mem_map + offset, + mem_map + offset + size, + nid * MAX_NR_ZONES + j, zone_start_paddr, + (j == ZONE_HIGHMEM ? 1 : 0)); offset += size; for (i = 0; ; i++) { @@ -895,7 +943,6 @@ (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size); } } - build_zonelists(pgdat); } void __init free_area_init(unsigned long *zones_size)