===== arch/ia64/kernel/mca.c 1.62 vs edited ===== Index: linux/arch/ia64/kernel/mca.c =================================================================== --- linux.orig/arch/ia64/kernel/mca.c 2004-11-04 15:12:40.000000000 -0600 +++ linux/arch/ia64/kernel/mca.c 2004-11-04 15:45:01.000000000 -0600 @@ -868,8 +868,10 @@ ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; - if (recover) + if (recover) { ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; + ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); + } else ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT; @@ -900,15 +902,74 @@ void ia64_mca_ucmc_handler(void) { + struct io_range *range; + unsigned long io_addr = 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); + int recover = 0; + ia64_err_rec_t *curr_record; + INC_KDBA_MCA_TRACE(); KDBA_MCA_TRACE(); /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); + /* TLB errors are fixed up before we get here, so recover */ + if (psp->tc) { + recover = 1; + goto return_to_sal; + } + + /* + * If it's not a bus check with a valid target identifier, + * we don't have a chance. + */ + if (!psp->bc) { + recover = 0; + goto return_to_sal; + } + + /* + * If we can't get this lock, we can't safely look at the list, + * so give up. + */ + if (!spin_trylock(&io_range_list_lock)) { + recover = 0; + goto return_to_sal; + } + + curr_record = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); + io_addr = curr_record->proc_err.info->target_identifier; + + /* + * See if an I/O error occured in a previously registered range + */ + list_for_each_entry(range, &pci_io_ranges, range_list) { + if (range->start <= io_addr && io_addr <= range->end) { + struct siginfo siginfo; + struct task_struct *owner = NULL; + recover = 1; + siginfo.si_signo = SIGBUS; + siginfo.si_code = BUS_ADRERR; + siginfo.si_addr = (void *) io_addr; + owner = find_task_by_pid(range->owner); + if (owner) + force_sig_info(SIGBUS, &siginfo, owner); + else { + /* + * need to free memory too, is that safe + * here? + */ + list_del(&range->range_list); + } + break; + } + } + spin_unlock(&io_range_list_lock); + +return_to_sal: + #ifdef CONFIG_KDB kdba_mca_init(SAL_INFO_TYPE_MCA, psp, recover); #endif /* CONFIG_KDB */ Index: linux/arch/ia64/pci/pci.c =================================================================== --- linux.orig/arch/ia64/pci/pci.c 2004-11-04 15:12:40.000000000 -0600 +++ linux/arch/ia64/pci/pci.c 2004-11-04 15:46:20.000000000 -0600 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,8 @@ #endif #include +#include "../sn/include/pci/pcidev.h" +#include "../sn/include/pci/pcibus_provider_defs.h" #undef DEBUG #define DEBUG @@ -47,6 +50,9 @@ struct pci_fixup pcibios_fixups[1]; +LIST_HEAD(pci_io_ranges); +spinlock_t io_range_list_lock = SPIN_LOCK_UNLOCKED; + /* * Low-level SAL-based PCI configuration access functions. Note that SAL * calls are already serialized (via sal_lock), so we don't need another @@ -466,18 +472,25 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine) { - /* - * I/O space cannot be accessed via normal processor loads and stores on this - * platform. - */ - if (mmap_state == pci_mmap_io) - /* - * XXX we could relax this for I/O spaces for which ACPI indicates that - * the space is 1-to-1 mapped. But at the moment, we don't support - * multiple PCI address spaces and the legacy I/O space is not 1-to-1 - * mapped, so this is moot. - */ - return -EINVAL; + struct io_range *new_range; + + /* Remap legacy I/O space for this bus if the offset is 0 */ + if (mmap_state == pci_mmap_io && + (vma->vm_pgoff << PAGE_SHIFT) < (1<<16)) { + if (SN_PCIDEV_BUSSOFT(dev) == NULL) + return -EINVAL; + + vma->vm_pgoff = SN_PCIDEV_BUSSOFT(dev)->bs_legacy_io >> PAGE_SHIFT; + } + + /* Remap legacy mem space for this bus if the offset is 0 */ + if (mmap_state == pci_mmap_mem && + (vma->vm_pgoff << PAGE_SHIFT) < (1<<20)) { + if (SN_PCIDEV_BUSSOFT(dev) == NULL) + return -EINVAL; + + vma->vm_pgoff = SN_PCIDEV_BUSSOFT(dev)->bs_legacy_mem >> PAGE_SHIFT; + } /* * Leave vm_pgoff as-is, the PCI space address is the physical address on this @@ -494,6 +507,29 @@ vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; + new_range = kmalloc(sizeof(struct io_range), GFP_KERNEL); + if (!new_range) { + printk(KERN_WARNING "%s: cannot allocate io_range, " + "I/O errors for 0x%016lx-0x%016lx will be fatal", + __FUNCTION__, vma->vm_start, vma->vm_end); + goto out; + } + + /* + * Track this range and its associated process for use by the + * MCA handler. + */ + new_range->start = __pa(vma->vm_pgoff << PAGE_SHIFT); + new_range->end = new_range->start + (vma->vm_end - vma->vm_start); + new_range->owner = current->pid; + + spin_lock(&io_range_list_lock); + list_add(&new_range->range_list, &pci_io_ranges); + spin_unlock(&io_range_list_lock); + + printk("I/O range 0x%016lx-0x%016lx registered\n", + new_range->start, new_range->end); + out: return 0; } Index: linux/drivers/pci/proc.c =================================================================== --- linux.orig/drivers/pci/proc.c 2004-11-04 15:12:40.000000000 -0600 +++ linux/drivers/pci/proc.c 2004-11-04 15:45:01.000000000 -0600 @@ -279,9 +279,23 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file) { + struct io_range *range; + kfree(file->private_data); file->private_data = NULL; + spin_lock(&io_range_list_lock); + list_for_each_entry(range, &pci_io_ranges, range_list) { + if (range->owner == current->pid) { + list_del(&range->range_list); + printk("I/O range 0x%016lx-0x%016lx de-registered\n", + range->start, range->end); + kfree(range); + break; + } + } + spin_unlock(&io_range_list_lock); + return 0; } #endif /* HAVE_PCI_MMAP */ Index: linux/include/asm-ia64/io.h =================================================================== --- linux.orig/include/asm-ia64/io.h 2004-11-04 15:12:40.000000000 -0600 +++ linux/include/asm-ia64/io.h 2004-11-04 15:45:01.000000000 -0600 @@ -1,6 +1,8 @@ #ifndef _ASM_IA64_IO_H #define _ASM_IA64_IO_H +#include + /* * This file contains the definitions for the emulated IO instructions * inb/inw/inl/outb/outw/outl and the "string versions" of the same @@ -50,13 +52,27 @@ extern struct io_space io_space[]; extern unsigned int num_io_spaces; +/* + * Simple I/O range object with owner (if there is one) + */ +struct io_range { + unsigned long start, end; + struct list_head range_list; + pid_t owner; +}; + +extern struct list_head pci_io_ranges; + # ifdef __KERNEL__ +#include #include #include #include #include +extern spinlock_t io_range_list_lock; + /* * Change virtual addresses to physical addresses and vv. */