Changes since 2.4.24-ia64-040106: - workaround menuconfig "HP-simulator" vs. "HP" bug (Bjorn Helgaas). diff -u -rN linux-2.4.24/Documentation/Configure.help linux-2.4.24-ia64-040109/Documentation/Configure.help --- linux-2.4.24/Documentation/Configure.help 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/Documentation/Configure.help 2004-01-09 09:55:46.000000000 -0700 @@ -18345,6 +18345,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 @@ -27150,16 +27155,11 @@ will run on any supported IA-64 system. However, if you configure a kernel for your specific system, it will be faster and smaller. - To find out what type of IA-64 system you have, you may want to - check the IA-64 Linux web site at . - As of the time of this writing, most hardware is DIG compliant, - so the "DIG-compliant" option is usually the right choice. - - HP-simulator For the HP simulator (). - HP-zx1 For HP zx1 Platforms. - SN1 For SGI SN1 Platforms. - SN2 For SGI SN2 Platforms. - DIG-compliant For DIG ("Developer's Interface Guide") compliant systems. + generic For any supported IA-64 system + DIG-compliant For DIG ("Developer's Interface Guide") compliant systems + HP For HP systems + SGI-SN2 For SGI SN2 systems + Ski-simulator For the HP simulator () If you don't know what to do, choose "generic". diff -u -rN linux-2.4.24/Documentation/vm/hugetlbpage.txt linux-2.4.24-ia64-040109/Documentation/vm/hugetlbpage.txt --- linux-2.4.24/Documentation/vm/hugetlbpage.txt 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/Documentation/vm/hugetlbpage.txt 2004-01-09 09:54:49.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;iiommu) +#ifdef CONFIG_PCI +# define GET_IOC(dev) ((struct ioc *) PCI_CONTROLLER(dev)->iommu) +#else +# define GET_IOC(dev) NULL +#endif /* ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up @@ -510,7 +520,7 @@ sba_alloc_range(struct ioc *ioc, size_t size) { unsigned int pages_needed = size >> IOVP_SHIFT; -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS unsigned long itc_start = ia64_get_itc(); #endif unsigned long pide; @@ -544,7 +554,7 @@ (uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map), ioc->res_bitshift ); -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS { unsigned long itc_end = ia64_get_itc(); unsigned long tmp = itc_end - itc_start; @@ -586,7 +596,7 @@ __FUNCTION__, (uint) iova, size, bits_not_wanted, m, pide, res_ptr, *res_ptr); -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->used_pages -= bits_not_wanted; #endif @@ -749,12 +759,12 @@ * @dev: instance of PCI owned by the driver that's asking. * @addr: driver buffer to map. * @size: number of bytes to map in driver buffer. - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ dma_addr_t -sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction) +sba_map_single(struct pci_dev *dev, void *addr, size_t size, int dir) { struct ioc *ioc; unsigned long flags; @@ -778,7 +788,7 @@ ** Device is bit capable of DMA'ing to the buffer... ** just return the PCI address of ptr */ -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS spin_lock_irqsave(&ioc->res_lock, flags); ioc->msingle_bypass++; spin_unlock_irqrestore(&ioc->res_lock, flags); @@ -804,7 +814,7 @@ panic("Sanity check failed"); #endif -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->msingle_calls++; ioc->msingle_pages += size >> IOVP_SHIFT; #endif @@ -842,12 +852,11 @@ * @dev: instance of PCI owned by the driver that's asking. * @iova: IOVA of driver buffer previously mapped. * @size: number of bytes mapped in driver buffer. - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, - int direction) +void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size, int dir) { struct ioc *ioc; #if DELAYED_RESOURCE_CNT > 0 @@ -864,7 +873,7 @@ /* ** Address does not fall w/in IOVA, must be bypassing */ -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS spin_lock_irqsave(&ioc->res_lock, flags); ioc->usingle_bypass++; spin_unlock_irqrestore(&ioc->res_lock, flags); @@ -872,7 +881,7 @@ DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova); #ifdef ENABLE_MARK_CLEAN - if (direction == PCI_DMA_FROMDEVICE) { + if (dir == PCI_DMA_FROMDEVICE) { mark_clean(phys_to_virt(iova), size); } #endif @@ -889,7 +898,7 @@ size = ROUNDUP(size, IOVP_SIZE); spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->usingle_calls++; ioc->usingle_pages += size >> IOVP_SHIFT; #endif @@ -914,7 +923,7 @@ READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */ #endif /* DELAYED_RESOURCE_CNT == 0 */ #ifdef ENABLE_MARK_CLEAN - if (direction == PCI_DMA_FROMDEVICE) { + if (dir == PCI_DMA_FROMDEVICE) { u32 iovp = (u32) SBA_IOVP(ioc,iova); int off = PDIR_INDEX(iovp); void *addr; @@ -951,55 +960,51 @@ /** - * sba_alloc_consistent - allocate/map shared mem for DMA - * @hwdev: instance of PCI owned by the driver that's asking. + * sba_alloc_coherent - allocate/map shared mem for DMA + * @dev: instance of PCI owned by the driver that's asking. * @size: number of bytes mapped in driver buffer. * @dma_handle: IOVA of new buffer. * * See Documentation/DMA-mapping.txt */ void * -sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +sba_alloc_coherent (struct pci_dev *dev, size_t size, dma_addr_t *dma_handle) { struct ioc *ioc; - void *ret; + void *addr; - if (!hwdev) { - /* only support PCI */ - *dma_handle = 0; - return 0; - } + if (!dev) + return NULL; /* only support PCI */ - ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + addr = (void *) __get_free_pages(GFP_ATOMIC, get_order(size)); + if (!addr) + return NULL; - if (ret) { - memset(ret, 0, size); - /* - * REVISIT: if sba_map_single starts needing more - * than dma_mask from the device, this needs to be - * updated. - */ - ioc = GET_IOC(hwdev); - *dma_handle = sba_map_single(ioc->sac_only_dev, ret, size, 0); - } + /* + * REVISIT: if sba_map_single starts needing more than dma_mask from the + * device, this needs to be updated. + */ + ioc = GET_IOC(dev); + ASSERT(ioc); + *dma_handle = sba_map_single(ioc->sac_only_dev, addr, size, 0); - return ret; + memset(addr, 0, size); + return addr; } /** - * sba_free_consistent - free/unmap shared mem for DMA - * @hwdev: instance of PCI owned by the driver that's asking. + * sba_free_coherent - free/unmap shared mem for DMA + * @dev: instance of PCI owned by the driver that's asking. * @size: number of bytes mapped in driver buffer. * @vaddr: virtual address IOVA of "consistent" buffer. * @dma_handler: IO virtual address of "consistent" buffer. * * See Documentation/DMA-mapping.txt */ -void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) +void sba_free_coherent (struct pci_dev *dev, size_t size, void *vaddr, dma_addr_t dma_handle) { - sba_unmap_single(hwdev, dma_handle, size, 0); + sba_unmap_single(dev, dma_handle, size, 0); free_pages((unsigned long) vaddr, get_order(size)); } @@ -1079,7 +1084,7 @@ cnt += dma_offset; dma_offset=0; /* only want offset on first chunk */ cnt = ROUNDUP(cnt, IOVP_SIZE); -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->msg_pages += cnt >> IOVP_SHIFT; #endif do { @@ -1121,7 +1126,7 @@ * in the DMA stream. Allocates PDIR entries but does not fill them. * Returns the number of DMA chunks. * - * Doing the fill seperate from the coalescing/allocation keeps the + * Doing the fill separate from the coalescing/allocation keeps the * code simpler. Future enhancement could make one pass through * the sglist do both. */ @@ -1246,11 +1251,11 @@ * @dev: instance of PCI owned by the driver that's asking. * @sglist: array of buffer/length pairs * @nents: number of entries in list - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction) +int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int dir) { struct ioc *ioc; int coalesced, filled = 0; @@ -1269,7 +1274,7 @@ sg->dma_length = sg->length; sg->dma_address = virt_to_phys(sba_sg_address(sg)); } -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS spin_lock_irqsave(&ioc->res_lock, flags); ioc->msg_bypass++; spin_unlock_irqrestore(&ioc->res_lock, flags); @@ -1280,10 +1285,9 @@ /* Fast path single entry scatterlists. */ if (nents == 1) { sglist->dma_length = sglist->length; - sglist->dma_address = sba_map_single(dev, - sba_sg_address(sglist), - sglist->length, direction); -#ifdef CONFIG_PROC_FS + sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length, + dir); +#if SBA_PROC_FS /* ** Should probably do some stats counting, but trying to ** be precise quickly starts wasting CPU time. @@ -1302,7 +1306,7 @@ } #endif -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->msg_calls++; #endif @@ -1348,12 +1352,11 @@ * @dev: instance of PCI owned by the driver that's asking. * @sglist: array of buffer/length pairs * @nents: number of entries in list - * @direction: R/W or both. + * @dir: R/W or both. * * See Documentation/DMA-mapping.txt */ -void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, - int direction) +void sba_unmap_sg (struct pci_dev *dev, struct scatterlist *sglist, int nents, int dir) { struct ioc *ioc; #ifdef ASSERT_PDIR_SANITY @@ -1366,7 +1369,7 @@ ioc = GET_IOC(dev); ASSERT(ioc); -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS ioc->usg_calls++; #endif @@ -1378,9 +1381,8 @@ while (nents && sglist->dma_length) { - sba_unmap_single(dev, sglist->dma_address, - sglist->dma_length, direction); -#ifdef CONFIG_PROC_FS + sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir); +#if SBA_PROC_FS /* ** This leaves inconsistent data in the stats, but we can't ** tell which sg lists were mapped by map_single and which @@ -1416,7 +1418,7 @@ u32 iova_space_mask; int iov_order, tcnfg; int agp_found = 0; - struct pci_dev *device; + struct pci_dev *device = NULL; #ifdef FULL_VALID_PDIR unsigned long index; #endif @@ -1514,7 +1516,7 @@ ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - pci_for_each_dev(device) + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); if (agp_found && reserve_sba_gart) { @@ -1596,7 +1598,7 @@ struct pci_controller *controller = NULL; /* - * pci_alloc_consistent() must return a DMA address which is + * pci_alloc_coherent() must return a DMA address which is * SAC (single address cycle) addressable, so allocate a * pseudo-device to enforce that. */ @@ -1636,6 +1638,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = { { ZX1_IOC_ID, "zx1", ioc_zx1_init }, { REO_IOC_ID, "REO" }, + { SX1000_IOC_ID, "sx1000" }, }; static struct ioc * __init @@ -1671,9 +1674,8 @@ if (!ioc->name) { ioc->name = kmalloc(24, GFP_KERNEL); if (ioc->name) - sprintf(ioc->name, "Unknown (%04x:%04x)", - ioc->func_id & 0xFFFF, - (ioc->func_id >> 16) & 0xFFFF); + sprintf((char *) ioc->name, "Unknown (%04x:%04x)", + ioc->func_id & 0xFFFF, (ioc->func_id >> 16) & 0xFFFF); else ioc->name = "Unknown"; } @@ -1701,7 +1703,7 @@ ** **************************************************************************/ -#ifdef CONFIG_PROC_FS +#if SBA_PROC_FS static void * ioc_start(struct seq_file *s, loff_t *pos) { @@ -1756,33 +1758,31 @@ if (ioc->avg_search[i] < min) min = ioc->avg_search[i]; } avg /= SBA_SEARCH_SAMPLE; - seq_printf(s, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", - min, avg, max); + seq_printf(s, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", min, avg, max); seq_printf(s, "pci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n", - ioc->msingle_calls, ioc->msingle_pages, - (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); + ioc->msingle_calls, ioc->msingle_pages, + (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls)); #ifdef ALLOW_IOV_BYPASS seq_printf(s, "pci_map_single(): %12ld bypasses\n", ioc->msingle_bypass); #endif seq_printf(s, "pci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n", - ioc->usingle_calls, ioc->usingle_pages, - (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls)); + ioc->usingle_calls, ioc->usingle_pages, + (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls)); #ifdef ALLOW_IOV_BYPASS seq_printf(s, "pci_unmap_single: %12ld bypasses\n", ioc->usingle_bypass); #endif seq_printf(s, "pci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n", - ioc->msg_calls, ioc->msg_pages, - (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); + ioc->msg_calls, ioc->msg_pages, + (int) ((ioc->msg_pages * 1000)/ioc->msg_calls)); #ifdef ALLOW_IOV_BYPASS seq_printf(s, "pci_map_sg() : %12ld bypasses\n", ioc->msg_bypass); #endif seq_printf(s, "pci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n", - ioc->usg_calls, ioc->usg_pages, - (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); + ioc->usg_calls, ioc->usg_pages, (int) ((ioc->usg_pages * 1000)/ioc->usg_calls)); return 0; } @@ -1811,11 +1811,10 @@ ioc_map_show(struct seq_file *s, void *v) { struct ioc *ioc = v; - unsigned int *res_ptr = (unsigned int *)ioc->res_map; - int i; + unsigned int i, *res_ptr = (unsigned int *)ioc->res_map; - for (i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) - seq_printf(s, "%s%08x", (i & 7) ? " " : "\n ", *res_ptr); + for (i = 0; i < ioc->res_size / sizeof(unsigned int); ++i, ++res_ptr) + seq_printf(s, "%s%08x", (i & 7) ? " " : "\n ", *res_ptr); seq_printf(s, "\n"); return 0; @@ -1844,29 +1843,36 @@ static void __init ioc_proc_init(void) { - if (ioc_list) { - struct proc_dir_entry *dir, *entry; + struct proc_dir_entry *dir, *entry; - dir = proc_mkdir("bus/mckinley", 0); - entry = create_proc_entry(ioc_list->name, 0, dir); - if (entry) - entry->proc_fops = &ioc_fops; + dir = proc_mkdir("bus/mckinley", 0); + if (!dir) + return; - entry = create_proc_entry("bitmap", 0, dir); - if (entry) - entry->proc_fops = &ioc_map_fops; - } + entry = create_proc_entry(ioc_list->name, 0, dir); + if (entry) + entry->proc_fops = &ioc_fops; + + entry = create_proc_entry("bitmap", 0, dir); + if (entry) + entry->proc_fops = &ioc_map_fops; } #endif -void -sba_enable_device(struct pci_dev *dev) +static void +sba_connect_bus(struct pci_bus *bus) { acpi_handle handle, parent; acpi_status status; struct ioc *ioc; - handle = PCI_CONTROLLER(dev)->acpi_handle; + if (!PCI_CONTROLLER(bus)) + panic(PFX "no sysdata on bus %d!\n", bus->number); + + if (PCI_CONTROLLER(bus)->iommu) + return; + + handle = PCI_CONTROLLER(bus)->acpi_handle; if (!handle) return; @@ -1878,7 +1884,7 @@ do { for (ioc = ioc_list; ioc; ioc = ioc->next) if (ioc->handle == handle) { - PCI_CONTROLLER(dev)->iommu = ioc; + PCI_CONTROLLER(bus)->iommu = ioc; return; } @@ -1886,7 +1892,7 @@ handle = parent; } while (ACPI_SUCCESS(status)); - printk(KERN_WARNING "No IOC for %s in ACPI\n", dev->slot_name); + printk(KERN_WARNING "No IOC for PCI Bus %04x:%02x in ACPI\n", PCI_SEGMENT(bus), bus->number); } static int __init @@ -1924,19 +1930,29 @@ } static struct acpi_driver acpi_sba_ioc_driver = { - name: "IOC IOMMU Driver", - ids: "HWP0001,HWP0004", - ops: { - add: acpi_sba_ioc_add, - }, + .name = "IOC IOMMU Driver", + .ids = "HWP0001,HWP0004", + .ops = { + .add = acpi_sba_ioc_add, + }, }; void __init sba_init(void) { acpi_bus_register_driver(&acpi_sba_ioc_driver); + if (!ioc_list) + return 0; -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_PCI + { + struct pci_bus *b = NULL; + pci_for_each_bus(b) + sba_connect_bus(b); + } +#endif + +#if SBA_PROC_FS ioc_proc_init(); #endif } @@ -1963,5 +1979,5 @@ EXPORT_SYMBOL(sba_map_sg); EXPORT_SYMBOL(sba_unmap_sg); EXPORT_SYMBOL(sba_dma_supported); -EXPORT_SYMBOL(sba_alloc_consistent); -EXPORT_SYMBOL(sba_free_consistent); +EXPORT_SYMBOL(sba_alloc_coherent); +EXPORT_SYMBOL(sba_free_coherent); diff -u -rN linux-2.4.24/arch/ia64/hp/zx1/hpzx1_machvec.c linux-2.4.24-ia64-040109/arch/ia64/hp/zx1/hpzx1_machvec.c --- linux-2.4.24/arch/ia64/hp/zx1/hpzx1_machvec.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/hp/zx1/hpzx1_machvec.c 2004-01-09 09:54:49.000000000 -0700 @@ -1,3 +1,3 @@ -#define MACHVEC_PLATFORM_NAME hpzx1 +#define MACHVEC_PLATFORM_NAME hp #define MACHVEC_PLATFORM_HEADER #include diff -u -rN linux-2.4.24/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.24-ia64-040109/arch/ia64/hp/zx1/hpzx1_misc.c --- linux-2.4.24/arch/ia64/hp/zx1/hpzx1_misc.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/hp/zx1/hpzx1_misc.c 2004-01-09 09:54:49.000000000 -0700 @@ -17,7 +17,7 @@ #include #include -#define PFX "hpzx1: " +#define PFX static int hpzx1_devices; @@ -50,7 +50,14 @@ fake_dev->sizing = 0; \ return PCIBIOS_SUCCESSFUL; \ } \ - *value = read##sz(fake_dev->mapped_csrs + where); \ + switch (where & ~0x7) { \ + case 0x48: /* initiates config cycles */ \ + case 0x78: /* elroy suspend mode register */ \ + *value = 0; \ + break; \ + default: \ + *value = read##sz(fake_dev->mapped_csrs + where); \ + } \ if (where == PCI_COMMAND) \ *value |= PCI_COMMAND_MEMORY; /* SBA omits this */ \ return PCIBIOS_SUCCESSFUL; \ @@ -68,8 +75,14 @@ if (value == (u##bits) ~0) \ fake_dev->sizing = 1; \ return PCIBIOS_SUCCESSFUL; \ - } else \ - write##sz(value, fake_dev->mapped_csrs + where); \ + } \ + switch (where & ~0x7) { \ + case 0x48: /* initiates config cycles */ \ + case 0x78: /* elroy suspend mode register */ \ + break; \ + default: \ + write##sz(value, fake_dev->mapped_csrs + where); \ + } \ return PCIBIOS_SUCCESSFUL; \ } diff -u -rN linux-2.4.24/arch/ia64/ia32/ia32_entry.S linux-2.4.24-ia64-040109/arch/ia64/ia32/ia32_entry.S --- linux-2.4.24/arch/ia64/ia32/ia32_entry.S 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/ia32/ia32_entry.S 2004-01-09 09:54:49.000000000 -0700 @@ -138,6 +138,19 @@ ;; st8 [r2]=r3 // initialize return code to -ENOSYS br.call.sptk.few rp=invoke_syscall_trace // give parent a chance to catch syscall args + // Need to reload arguments (they may be changed by the tracing process) + adds r2=IA64_PT_REGS_R9_OFFSET+16,sp // r2 = &pt_regs.r9 + adds r3=IA64_PT_REGS_R13_OFFSET+16,sp // r3 = &pt_regs.r13 + ;; + ld4 r33=[r2],8 // r9 == ecx + ld4 r37=[r3],16 // r13 == ebp + ;; + ld4 r34=[r2],8 // r10 == edx + ld4 r36=[r3],8 // r15 == edi + ;; + ld4 r32=[r2],8 // r11 == ebx + ld4 r35=[r3],8 // r14 == esi + ;; .ret2: br.call.sptk.few rp=b6 // do the syscall .ia32_strace_check_retval: cmp.lt p6,p0=r8,r0 // syscall failed? diff -u -rN linux-2.4.24/arch/ia64/ia32/sys_ia32.c linux-2.4.24-ia64-040109/arch/ia64/ia32/sys_ia32.c --- linux-2.4.24/arch/ia64/ia32/sys_ia32.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/ia32/sys_ia32.c 2004-01-09 09:54:49.000000000 -0700 @@ -74,6 +74,7 @@ #define OFFSET4K(a) ((a) & 0xfff) #define PAGE_START(addr) ((addr) & PAGE_MASK) #define PAGE_OFF(addr) ((addr) & ~PAGE_MASK) +#define MINSIGSTKSZ_IA32 2048 extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); @@ -201,13 +202,18 @@ asmlinkage long sys32_newstat (char *filename, struct stat32 *statbuf) { + char *name; int ret; struct stat s; mm_segment_t old_fs = get_fs(); + name = getname(filename); + if (IS_ERR(name)) + return PTR_ERR(name); set_fs(KERNEL_DS); - ret = sys_newstat(filename, &s); + ret = sys_newstat(name, &s); set_fs(old_fs); + putname(name); if (putstat(statbuf, &s)) return -EFAULT; return ret; @@ -218,13 +224,18 @@ asmlinkage long sys32_newlstat (char *filename, struct stat32 *statbuf) { + char *name; mm_segment_t old_fs = get_fs(); struct stat s; int ret; + name = getname(filename); + if (IS_ERR(name)) + return PTR_ERR(name); set_fs(KERNEL_DS); - ret = sys_newlstat(filename, &s); + ret = sys_newlstat(name, &s); set_fs(old_fs); + putname(name); if (putstat(statbuf, &s)) return -EFAULT; return ret; @@ -698,13 +709,18 @@ asmlinkage long sys32_statfs (const char *path, struct statfs32 *buf) { + const char *name; int ret; struct statfs s; mm_segment_t old_fs = get_fs(); + name = getname(path); + if (IS_ERR(name)) + return PTR_ERR(name); set_fs(KERNEL_DS); - ret = sys_statfs(path, &s); + ret = sys_statfs(name, &s); set_fs(old_fs); + putname(name); if (put_statfs(buf, &s)) return -EFAULT; return ret; @@ -3388,10 +3404,18 @@ return -EFAULT; uss.ss_sp = (void *) (long) buf32.ss_sp; uss.ss_flags = buf32.ss_flags; - uss.ss_size = buf32.ss_size; + /* MINSIGSTKSZ is different for ia32 vs ia64. We lie here to pass the + check and set it to the user requested value later */ + if (buf32.ss_size < MINSIGSTKSZ_IA32) { + ret = -ENOMEM; + goto out; + } + uss.ss_size = MINSIGSTKSZ; set_fs(KERNEL_DS); ret = do_sigaltstack(uss32 ? &uss : NULL, &uoss, pt->r12); + current->sas_ss_size = buf32.ss_size; set_fs(old_fs); +out: if (ret < 0) return(ret); if (uoss32) { @@ -3689,13 +3713,18 @@ asmlinkage long sys32_stat64 (char *filename, struct stat64 *statbuf) { + char *name; mm_segment_t old_fs = get_fs(); struct stat s; long ret; + name = getname(filename); + if (IS_ERR(name)) + return PTR_ERR(name); set_fs(KERNEL_DS); - ret = sys_newstat(filename, &s); + ret = sys_newstat(name, &s); set_fs(old_fs); + putname(name); if (putstat64(statbuf, &s)) return -EFAULT; return ret; @@ -3704,13 +3733,18 @@ asmlinkage long sys32_lstat64 (char *filename, struct stat64 *statbuf) { + char *name; mm_segment_t old_fs = get_fs(); struct stat s; long ret; + name = getname(filename); + if (IS_ERR(name)) + return PTR_ERR(name); set_fs(KERNEL_DS); - ret = sys_newlstat(filename, &s); + ret = sys_newlstat(name, &s); set_fs(old_fs); + putname(name); if (putstat64(statbuf, &s)) return -EFAULT; return ret; diff -u -rN linux-2.4.24/arch/ia64/kernel/acpi.c linux-2.4.24-ia64-040109/arch/ia64/kernel/acpi.c --- linux-2.4.24/arch/ia64/kernel/acpi.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/acpi.c 2004-01-09 09:54:49.000000000 -0700 @@ -96,7 +96,7 @@ } if (!strcmp(hdr->oem_id, "HP")) { - return "hpzx1"; + return "hp"; } else if (!strcmp(hdr->oem_id, "SGI")) { return "sn2"; @@ -107,7 +107,7 @@ # if defined (CONFIG_IA64_HP_SIM) return "hpsim"; # elif defined (CONFIG_IA64_HP_ZX1) - return "hpzx1"; + return "hp"; # elif defined (CONFIG_IA64_SGI_SN2) return "sn2"; # elif defined (CONFIG_IA64_DIG) @@ -820,4 +820,22 @@ return gsi_to_vector(irq); } +int +acpi_register_irq (u32 gsi, u32 polarity, u32 trigger) +{ + int vector = 0; + + if (has_8259 && gsi < 16) + return isa_irq_to_vector(gsi); + + if (!iosapic_register_intr) + return 0; + + /* Turn it on */ + vector = iosapic_register_intr(gsi, + (polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, + (trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); + return vector; +} + #endif /* CONFIG_ACPI_BOOT */ diff -u -rN linux-2.4.24/arch/ia64/kernel/efi.c linux-2.4.24-ia64-040109/arch/ia64/kernel/efi.c --- linux-2.4.24/arch/ia64/kernel/efi.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/efi.c 2004-01-09 09:54:49.000000000 -0700 @@ -297,9 +297,9 @@ u64 start; u64 end; } prev, curr; - void *efi_map_start, *efi_map_end, *p, *q, *r; + void *efi_map_start, *efi_map_end, *p, *q; efi_memory_desc_t *md, *check_md; - u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0; + u64 efi_desc_size, start, end, granule_addr, last_granule_addr, first_non_wb_addr = 0; efi_map_start = __va(ia64_boot_param->efi_memmap); efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; @@ -312,41 +312,34 @@ if (!(md->attribute & EFI_MEMORY_WB)) continue; - if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > first_non_wb_addr) { - /* - * Search for the next run of contiguous WB memory. Start search - * at first granule boundary covered by md. - */ - granule_addr = ((md->phys_addr + IA64_GRANULE_SIZE - 1) - & -IA64_GRANULE_SIZE); - first_non_wb_addr = granule_addr; - for (q = p; q < efi_map_end; q += efi_desc_size) { - check_md = q; - - if (check_md->attribute & EFI_MEMORY_WB) - trim_bottom(check_md, granule_addr); - - if (check_md->phys_addr < granule_addr) - continue; + /* + * granule_addr is the base of md's first granule. + * [granule_addr - first_non_wb_addr) is guaranteed to + * be contiguous WB memory. + */ + granule_addr = md->phys_addr & ~(IA64_GRANULE_SIZE - 1); + first_non_wb_addr = max(first_non_wb_addr, granule_addr); - if (!(check_md->attribute & EFI_MEMORY_WB)) - break; /* hit a non-WB region; stop search */ + if (first_non_wb_addr < md->phys_addr) { + trim_bottom(md, granule_addr + IA64_GRANULE_SIZE); + granule_addr = md->phys_addr & ~(IA64_GRANULE_SIZE - 1); + first_non_wb_addr = max(first_non_wb_addr, granule_addr); + } - if (check_md->phys_addr != first_non_wb_addr) - break; /* hit a memory hole; stop search */ + for (q = p; q < efi_map_end; q += efi_desc_size) { + check_md = q; + if ((check_md->attribute & EFI_MEMORY_WB) && + (check_md->phys_addr == first_non_wb_addr)) first_non_wb_addr += check_md->num_pages << EFI_PAGE_SHIFT; - } - /* round it down to the previous granule-boundary: */ - first_non_wb_addr &= -IA64_GRANULE_SIZE; - - if (!(first_non_wb_addr > granule_addr)) - continue; /* couldn't find enough contiguous memory */ - - for (r = p; r < q; r += efi_desc_size) - trim_top(r, first_non_wb_addr); + else + break; /* non-WB or hole */ } + last_granule_addr = first_non_wb_addr & ~(IA64_GRANULE_SIZE - 1); + if (last_granule_addr < md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) + trim_top(md, last_granule_addr); + if (is_available_memory(md)) { if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) { if (md->phys_addr > mem_limit) @@ -446,10 +439,12 @@ panic("Woah! PAL code size bigger than a granule!"); mask = ~((1 << IA64_GRANULE_SHIFT) - 1); +#if EFI_DEBUG printk(KERN_INFO "CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), vaddr & mask, (vaddr & mask) + IA64_GRANULE_SIZE); +#endif /* * Cannot write to CRx with PSR.ic=1 @@ -688,8 +683,7 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if ((md->phys_addr <= phys_addr) && (phys_addr <= - (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1))) + if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) return md->type; } return 0; @@ -709,8 +703,7 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; - if ((md->phys_addr <= phys_addr) && (phys_addr <= - (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1))) + if (phys_addr - md->phys_addr < (md->num_pages << EFI_PAGE_SHIFT)) return md->attribute; } return 0; diff -u -rN linux-2.4.24/arch/ia64/kernel/gate.S linux-2.4.24-ia64-040109/arch/ia64/kernel/gate.S --- linux-2.4.24/arch/ia64/kernel/gate.S 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/gate.S 2004-01-09 09:54:49.000000000 -0700 @@ -88,10 +88,10 @@ ld8 r15=[base1] // get address of new RBS base (or NULL) cover // push args in interrupted frame onto backing store ;; - cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? + cmp.ne p1,p0=r15,r0 // do we need to switch rbs? (note: pr is saved by kernel) mov.m r9=ar.bsp // fetch ar.bsp - .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF -(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16) + .spillsp.p p1, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF +(p1) br.cond.spnt setup_rbs // yup -> (clobbers p8, r14-r16, and r18-r20) back_from_setup_rbs: alloc r8=ar.pfs,0,0,3,0 ld8 out0=[base0],16 // load arg0 (signum) @@ -130,8 +130,8 @@ ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF mov r14=ar.bsp ;; - cmp.ne p8,p0=r14,r15 // do we need to restore the rbs? -(p8) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7) + cmp.ne p1,p0=r14,r15 // do we need to restore the rbs? +(p1) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7) ;; back_from_restore_rbs: adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp @@ -160,26 +160,30 @@ setup_rbs: mov ar.rsc=0 // put RSE into enforced lazy mode ;; - .save ar.rnat, r16 - mov r16=ar.rnat // save RNaT before switching backing store area + .save ar.rnat, r19 + mov r19=ar.rnat // save RNaT before switching backing store area adds r14=(RNAT_OFF+SIGCONTEXT_OFF),sp + mov r18=ar.bspstore mov ar.bspstore=r15 // switch over to new register backing store area ;; + .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF - st8 [r14]=r16 // save sc_ar_rnat + st8 [r14]=r19 // save sc_ar_rnat .body - adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp - mov.m r16=ar.bsp // sc_loadrs <- (new bsp - new bspstore) << 16 + adds r14=(LOADRS_OFF+SIGCONTEXT_OFF),sp ;; invala sub r15=r16,r15 + extr.u r20=r18,3,6 ;; + mov ar.rsc=0xf // set RSE into eager mode, pl 3 + cmp.eq p8,p0=63,r20 shl r15=r15,16 ;; st8 [r14]=r15 // save sc_loadrs - mov ar.rsc=0xf // set RSE into eager mode, pl 3 +(p8) st8 [r18]=r19 // if bspstore points at RNaT slot, store RNaT there now .restore sp // pop .prologue br.cond.sptk back_from_setup_rbs diff -u -rN linux-2.4.24/arch/ia64/kernel/ivt.S linux-2.4.24-ia64-040109/arch/ia64/kernel/ivt.S --- linux-2.4.24/arch/ia64/kernel/ivt.S 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/ivt.S 2004-01-09 09:54:49.000000000 -0700 @@ -118,6 +118,10 @@ * - the faulting virtual address has no L1, L2, or L3 mapping */ mov r16=cr.ifa // get address that caused the TLB miss +#ifdef CONFIG_HUGETLB_PAGE + movl r18=PAGE_SHIFT + mov r25=cr.itir +#endif ;; rsm psr.dt // use physical addressing for data mov r31=pr // save the predicate registers @@ -125,8 +129,18 @@ shl r21=r16,3 // shift bit 60 into sign bit shr.u r17=r16,61 // get the region number into r17 ;; + shr r22=r21,3 +#ifdef CONFIG_HUGETLB_PAGE + extr.u r26=r25,2,6 + ;; + cmp.eq p8,p0=HPAGE_SHIFT,r26 + ;; +(p8) dep r25=r18,r25,2,6 +(p8) shr r22=r22,HPAGE_SHIFT-PAGE_SHIFT +#endif + ;; cmp.eq p6,p7=5,r17 // is IFA pointing into to region 5? - shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of the faulting address + shr.u r18=r22,PGDIR_SHIFT // get bits 33-63 of the faulting address ;; (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place srlz.d // ensure "rsm psr.dt" has taken effect @@ -137,7 +151,7 @@ (p6) dep r17=r18,r19,3,(PAGE_SHIFT-3) // r17=PTA + IFA(33,42)*8 (p7) dep r17=r18,r17,3,(PAGE_SHIFT-6) // r17=PTA + (((IFA(61,63) << 7) | IFA(33,39))*8) cmp.eq p7,p6=0,r21 // unused address bits all zeroes? - shr.u r18=r16,PMD_SHIFT // shift L2 index into position + shr.u r18=r22,PMD_SHIFT // shift L2 index into position ;; ld8 r17=[r17] // fetch the L1 entry (may be 0) ;; @@ -145,7 +159,7 @@ dep r17=r18,r17,3,(PAGE_SHIFT-3) // compute address of L2 page table entry ;; (p7) ld8 r20=[r17] // fetch the L2 entry (may be 0) - shr.u r19=r16,PAGE_SHIFT // shift L3 index into position + shr.u r19=r22,PAGE_SHIFT // shift L3 index into position ;; (p7) cmp.eq.or.andcm p6,p7=r20,r0 // was L2 entry NULL? dep r21=r19,r20,3,(PAGE_SHIFT-3) // compute address of L3 page table entry @@ -164,6 +178,10 @@ (p6) br.cond.spnt.many page_fault // handle bad address/page not present (page fault) mov cr.ifa=r22 +#ifdef CONFIG_HUGETLB_PAGE +(p8) mov cr.itir=r25 // change to default page-size for VHPT +#endif + /* * Now compute and insert the TLB entry for the virtual page table. We never * execute in a page table page so there is no need to set the exception deferral diff -u -rN linux-2.4.24/arch/ia64/kernel/mca.c linux-2.4.24-ia64-040109/arch/ia64/kernel/mca.c --- linux-2.4.24/arch/ia64/kernel/mca.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/mca.c 2004-01-09 09:54:49.000000000 -0700 @@ -91,6 +91,7 @@ static void ia64_log_init(int); 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; static struct irqaction cmci_irqaction = { @@ -151,7 +152,7 @@ */ static int cpe_poll_enabled = 1; -extern void salinfo_log_wakeup(int); +extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size); /* * ia64_mca_log_sal_error_record @@ -166,11 +167,13 @@ int ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init) { - int platform_err = 0; + u8 *buffer; + u64 size; + int platform_err; - /* Get the MCA error record */ - if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) - return platform_err; /* no record retrieved */ + size = ia64_log_get(sal_info_type, &buffer); + if (!size) + return 0; /* TODO: * 1. analyze error logs to determine recoverability @@ -178,8 +181,11 @@ * 3. set ia64_os_mca_recovery_successful flag, if applicable */ - salinfo_log_wakeup(sal_info_type); + 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; } @@ -834,7 +840,7 @@ irr = ia64_get_irr3(); break; } - } while (!(irr & (1 << irr_bit))) ; + } while (!(irr & (1UL << irr_bit))) ; } /* @@ -1416,12 +1422,12 @@ * 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}) - * prfunc (fn ptr of log output function) * Outputs : size (total record length) + * *buffer (ptr to error record) * */ u64 -ia64_log_get(int sal_info_type, prfunc_t prfunc) +ia64_log_get(int sal_info_type, u8 **buffer) { sal_log_record_header_t *log_buffer; u64 total_len = 0; @@ -1439,6 +1445,7 @@ 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); @@ -1483,7 +1490,7 @@ void ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc) { - prfunc("+Err Record ID: %d SAL Rev: %2x.%02x\n", lh->id, + 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, @@ -1606,13 +1613,13 @@ if (info->dl) prfunc(" Line: Data,"); prfunc(" Operation: %s,", pal_cache_op[info->op]); - if (info->wv) + 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->mc) + if (info->mcc) prfunc(" MC: Corrected"); prfunc("\n"); } @@ -1648,13 +1655,13 @@ prfunc(" Failure: Data Translation Cache"); if (info->itr) { prfunc(" Failure: Instruction Translation Register"); - prfunc(" ,Slot: %d", info->tr_slot); + prfunc(" ,Slot: %ld", info->tr_slot); } if (info->dtr) { prfunc(" Failure: Data Translation Register"); - prfunc(" ,Slot: %d", info->tr_slot); + prfunc(" ,Slot: %ld", info->tr_slot); } - if (info->mc) + if (info->mcc) prfunc(" ,MC: Corrected"); prfunc("\n"); } @@ -1700,7 +1707,7 @@ prfunc(" ,Error: Internal"); if (info->eb) prfunc(" ,Error: External"); - if (info->mc) + if (info->mcc) prfunc(" ,MC: Corrected"); if (info->tv) prfunc(" ,Target Address: 0x%lx", targ_addr); @@ -2376,7 +2383,8 @@ ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc); break; case SAL_INFO_TYPE_INIT: - prfunc("+MCA INIT ERROR LOG (UNIMPLEMENTED)\n"); + 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"); diff -u -rN linux-2.4.24/arch/ia64/kernel/mca_asm.S linux-2.4.24-ia64-040109/arch/ia64/kernel/mca_asm.S --- linux-2.4.24/arch/ia64/kernel/mca_asm.S 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/mca_asm.S 2004-01-09 09:54:49.000000000 -0700 @@ -267,15 +267,15 @@ add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2 // duplicate r2 in r4 - mov r3=cr0 // cr.dcr - mov r5=cr1 // cr.itm - mov r7=cr2;; // cr.iva + mov r3=cr.dcr + mov r5=cr.itm + mov r7=cr.iva;; st8 [r2]=r3,8*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; // 48 byte rements - mov r3=cr8;; // cr.pta + mov r3=cr.pta;; st8 [r2]=r3,8*8;; // 64 byte rements // if PSR.ic=0, reading interruption registers causes an illegal operation fault @@ -288,23 +288,23 @@ add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2 // duplicate r2 in r6 - mov r3=cr16 // cr.ipsr - mov r5=cr17 // cr.isr - mov r7=r0;; // cr.ida => cr18 (reserved) + mov r3=cr.ipsr + mov r5=cr.isr + mov r7=r0;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; - mov r3=cr19 // cr.iip - mov r5=cr20 // cr.idtr - mov r7=cr21;; // cr.iitr + mov r3=cr.iip + mov r5=cr.ifa + mov r7=cr.itir;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; - mov r3=cr22 // cr.iipa - mov r5=cr23 // cr.ifs - mov r7=cr24;; // cr.iim + mov r3=cr.iipa + mov r5=cr.ifs + mov r7=cr.iim;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; @@ -313,104 +313,101 @@ st8 [r2]=r3,160;; // 160 byte rement SkipIntrRegs: - st8 [r2]=r0,168 // another 168 byte . + st8 [r2]=r0,152;; // another 152 byte . - mov r3=cr66;; // cr.lid - st8 [r2]=r3,40 // 40 byte rement + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2 // duplicate r2 in r6 - mov r3=cr71;; // cr.ivr - st8 [r2]=r3,8 - - mov r3=cr72;; // cr.tpr - st8 [r2]=r3,24 // 24 byte increment - - mov r3=r0;; // cr.eoi => cr75 - st8 [r2]=r3,168 // 168 byte inc. - - mov r3=r0;; // cr.irr0 => cr96 - st8 [r2]=r3,16 // 16 byte inc. - - mov r3=r0;; // cr.irr1 => cr98 - st8 [r2]=r3,16 // 16 byte inc. - - mov r3=r0;; // cr.irr2 => cr100 - st8 [r2]=r3,16 // 16 byte inc - - mov r3=r0;; // cr.irr3 => cr100 - st8 [r2]=r3,16 // 16b inc. - - mov r3=r0;; // cr.itv => cr114 - st8 [r2]=r3,16 // 16 byte inc. + mov r3=cr.lid +// mov r5=cr.ivr // cr.ivr, don't read it + mov r7=cr.tpr;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; - mov r3=r0;; // cr.pmv => cr116 - st8 [r2]=r3,8 + mov r3=r0 // cr.eoi => cr67 + mov r5=r0 // cr.irr0 => cr68 + mov r7=r0;; // cr.irr1 => cr69 + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; - mov r3=r0;; // cr.lrr0 => cr117 - st8 [r2]=r3,8 + mov r3=r0 // cr.irr2 => cr70 + mov r5=r0 // cr.irr3 => cr71 + mov r7=cr.itv;; + st8 [r2]=r3,3*8 + st8 [r4]=r5,3*8 + st8 [r6]=r7,3*8;; - mov r3=r0;; // cr.lrr1 => cr118 - st8 [r2]=r3,8 + mov r3=cr.pmv + mov r5=cr.cmcv;; + st8 [r2]=r3,7*8 + st8 [r4]=r5,7*8;; + + mov r3=r0 // cr.lrr0 => cr80 + mov r5=r0;; // cr.lrr1 => cr81 + st8 [r2]=r3,23*8 + st8 [r4]=r5,23*8;; - mov r3=r0;; // cr.cmcv => cr119 - st8 [r2]=r3,8*10;; + adds r2=25*8,r2;; cSaveARs: // save ARs add r4=8,r2 // duplicate r2 in r4 add r6=2*8,r2 // duplicate r2 in r6 - mov r3=ar0 // ar.kro - mov r5=ar1 // ar.kr1 - mov r7=ar2;; // ar.kr2 + mov r3=ar.k0 + mov r5=ar.k1 + mov r7=ar.k2;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; - mov r3=ar3 // ar.kr3 - mov r5=ar4 // ar.kr4 - mov r7=ar5;; // ar.kr5 + mov r3=ar.k3 + mov r5=ar.k4 + mov r7=ar.k5;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; - mov r3=ar6 // ar.kr6 - mov r5=ar7 // ar.kr7 + mov r3=ar.k6 + mov r5=ar.k7 mov r7=r0;; // ar.kr8 st8 [r2]=r3,10*8 st8 [r4]=r5,10*8 st8 [r6]=r7,10*8;; // rement by 72 bytes - mov r3=ar16 // ar.rsc - mov ar16=r0 // put RSE in enforced lazy mode - mov r5=ar17 // ar.bsp + mov r3=ar.rsc + mov ar.rsc=r0 // put RSE in enforced lazy mode + mov r5=ar.bsp ;; - mov r7=ar18;; // ar.bspstore + mov r7=ar.bspstore;; st8 [r2]=r3,3*8 st8 [r4]=r5,3*8 st8 [r6]=r7,3*8;; - mov r3=ar19;; // ar.rnat + mov r3=ar.rnat;; st8 [r2]=r3,8*13 // increment by 13x8 bytes - mov r3=ar32;; // ar.ccv + mov r3=ar.ccv;; st8 [r2]=r3,8*4 - mov r3=ar36;; // ar.unat + mov r3=ar.unat;; st8 [r2]=r3,8*4 - mov r3=ar40;; // ar.fpsr + mov r3=ar.fpsr;; st8 [r2]=r3,8*4 - mov r3=ar44;; // ar.itc + mov r3=ar.itc;; st8 [r2]=r3,160 // 160 - mov r3=ar64;; // ar.pfs + mov r3=ar.pfs;; st8 [r2]=r3,8 - mov r3=ar65;; // ar.lc + mov r3=ar.lc;; st8 [r2]=r3,8 - mov r3=ar66;; // ar.ec + mov r3=ar.ec;; st8 [r2]=r3 add r2=8*62,r2 //padding @@ -419,7 +416,8 @@ movl r4=0x00;; cStRR: - mov r3=rr[r4];; + dep.z r5=r4,61,3;; + mov r3=rr[r5];; st8 [r2]=r3,8 add r4=1,r4 br.cloop.sptk.few cStRR @@ -503,12 +501,12 @@ ld8 r3=[r2],8*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; // 48 byte increments - mov cr0=r3 // cr.dcr - mov cr1=r5 // cr.itm - mov cr2=r7;; // cr.iva + mov cr.dcr=r3 + mov cr.itm=r5 + mov cr.iva=r7;; ld8 r3=[r2],8*8;; // 64 byte increments -// mov cr8=r3 // cr.pta +// mov cr.pta=r3 // if PSR.ic=1, reading interruption registers causes an illegal operation fault @@ -525,64 +523,66 @@ ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; - mov cr16=r3 // cr.ipsr - mov cr17=r5 // cr.isr is read only -// mov cr18=r7;; // cr.ida (reserved - don't restore) + mov cr.ipsr=r3 +// mov cr.isr=r5 // cr.isr is read only ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; - mov cr19=r3 // cr.iip - mov cr20=r5 // cr.idtr - mov cr21=r7;; // cr.iitr + mov cr.iip=r3 + mov cr.ifa=r5 + mov cr.itir=r7;; ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; - mov cr22=r3 // cr.iipa - mov cr23=r5 // cr.ifs - mov cr24=r7 // cr.iim + mov cr.iipa=r3 + mov cr.ifs=r5 + mov cr.iim=r7 ld8 r3=[r2],160;; // 160 byte increment - mov cr25=r3 // cr.iha + mov cr.iha=r3 rSkipIntrRegs: - ld8 r3=[r2],168;; // another 168 byte inc. - - ld8 r3=[r2],40;; // 40 byte increment - mov cr66=r3 // cr.lid - - ld8 r3=[r2],8;; -// mov cr71=r3 // cr.ivr is read only - ld8 r3=[r2],24;; // 24 byte increment - mov cr72=r3 // cr.tpr - - ld8 r3=[r2],168;; // 168 byte inc. -// mov cr75=r3 // cr.eoi + ld8 r3=[r2],152;; // another 152 byte inc. - ld8 r3=[r2],16;; // 16 byte inc. -// mov cr96=r3 // cr.irr0 is read only + add r4=8,r2 // duplicate r2 in r4 + add r6=2*8,r2;; // duplicate r2 in r6 - ld8 r3=[r2],16;; // 16 byte inc. -// mov cr98=r3 // cr.irr1 is read only + ld8 r3=[r2],8*3 + ld8 r5=[r4],8*3 + ld8 r7=[r6],8*3;; + mov cr.lid=r3 +// mov cr.ivr=r5 // cr.ivr is read only + mov cr.tpr=r7;; + + ld8 r3=[r2],8*3 + ld8 r5=[r4],8*3 + ld8 r7=[r6],8*3;; +// mov cr.eoi=r3 +// mov cr.irr0=r5 // cr.irr0 is read only +// mov cr.irr1=r7;; // cr.irr1 is read only + + ld8 r3=[r2],8*3 + ld8 r5=[r4],8*3 + ld8 r7=[r6],8*3;; +// mov cr.irr2=r3 // cr.irr2 is read only +// mov cr.irr3=r5 // cr.irr3 is read only + mov cr.itv=r7;; + + ld8 r3=[r2],8*7 + ld8 r5=[r4],8*7;; + mov cr.pmv=r3 + mov cr.cmcv=r5;; + + ld8 r3=[r2],8*23 + ld8 r5=[r4],8*23;; + adds r2=8*23,r2 + adds r4=8*23,r4;; +// mov cr.lrr0=r3 +// mov cr.lrr1=r5 - ld8 r3=[r2],16;; // 16 byte inc -// mov cr100=r3 // cr.irr2 is read only - - ld8 r3=[r2],16;; // 16b inc. -// mov cr102=r3 // cr.irr3 is read only - - ld8 r3=[r2],16;; // 16 byte inc. -// mov cr114=r3 // cr.itv - - ld8 r3=[r2],8;; -// mov cr116=r3 // cr.pmv - ld8 r3=[r2],8;; -// mov cr117=r3 // cr.lrr0 - ld8 r3=[r2],8;; -// mov cr118=r3 // cr.lrr1 - ld8 r3=[r2],8*10;; -// mov cr119=r3 // cr.cmcv + adds r2=8*2,r2;; restore_ARs: add r4=8,r2 // duplicate r2 in r4 @@ -591,67 +591,67 @@ ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; - mov ar0=r3 // ar.kro - mov ar1=r5 // ar.kr1 - mov ar2=r7;; // ar.kr2 + mov ar.k0=r3 + mov ar.k1=r5 + mov ar.k2=r7;; ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; - mov ar3=r3 // ar.kr3 - mov ar4=r5 // ar.kr4 - mov ar5=r7;; // ar.kr5 + mov ar.k3=r3 + mov ar.k4=r5 + mov ar.k5=r7;; ld8 r3=[r2],10*8 ld8 r5=[r4],10*8 ld8 r7=[r6],10*8;; - mov ar6=r3 // ar.kr6 - mov ar7=r5 // ar.kr7 -// mov ar8=r6 // ar.kr8 + mov ar.k6=r3 + mov ar.k7=r5 ;; ld8 r3=[r2],3*8 ld8 r5=[r4],3*8 ld8 r7=[r6],3*8;; -// mov ar16=r3 // ar.rsc -// mov ar17=r5 // ar.bsp is read only - mov ar16=r0 // make sure that RSE is in enforced lazy mode +// mov ar.rsc=r3 +// mov ar.bsp=r5 // ar.bsp is read only + mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode ;; - mov ar18=r7;; // ar.bspstore + mov ar.bspstore=r7;; ld8 r9=[r2],8*13;; - mov ar19=r9 // ar.rnat + mov ar.rnat=r9 - mov ar16=r3 // ar.rsc + mov ar.rsc=r3 ld8 r3=[r2],8*4;; - mov ar32=r3 // ar.ccv + mov ar.ccv=r3 ld8 r3=[r2],8*4;; - mov ar36=r3 // ar.unat + mov ar.unat=r3 ld8 r3=[r2],8*4;; - mov ar40=r3 // ar.fpsr + mov ar.fpsr=r3 ld8 r3=[r2],160;; // 160 -// mov ar44=r3 // ar.itc +// mov ar.itc=r3 ld8 r3=[r2],8;; - mov ar64=r3 // ar.pfs + mov ar.pfs=r3 ld8 r3=[r2],8;; - mov ar65=r3 // ar.lc + mov ar.lc=r3 ld8 r3=[r2];; - mov ar66=r3 // ar.ec + mov ar.ec=r3 add r2=8*62,r2;; // padding restore_RRs: mov r5=ar.lc mov ar.lc=0x08-1 - movl r4=0x00 + movl r4=0x00;; cStRRr: + dep.z r7=r4,61,3 ld8 r3=[r2],8;; -// mov rr[r4]=r3 // what are its access previledges? + mov rr[r7]=r3 // what are its access previledges? add r4=1,r4 br.cloop.sptk.few cStRRr ;; diff -u -rN linux-2.4.24/arch/ia64/kernel/pci.c linux-2.4.24-ia64-040109/arch/ia64/kernel/pci.c --- linux-2.4.24/arch/ia64/kernel/pci.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/pci.c 2004-01-09 09:54:49.000000000 -0700 @@ -523,8 +523,6 @@ if (ret < 0) return ret; - platform_pci_enable_device(dev); - printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name); return 0; diff -u -rN linux-2.4.24/arch/ia64/kernel/perfmon.c linux-2.4.24-ia64-040109/arch/ia64/kernel/perfmon.c --- linux-2.4.24/arch/ia64/kernel/perfmon.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/perfmon.c 2004-01-09 09:54:49.000000000 -0700 @@ -4013,6 +4013,10 @@ if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_ONCE) { nctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; DBprintk(("downgrading to INHERIT_NONE for [%d]\n", task->pid)); + /* + * downgrade parent: once means only first child! + */ + ctx->ctx_fl_inherit = PFM_FL_INHERIT_NONE; } /* * task is not yet visible in the tasklist, so we do diff -u -rN linux-2.4.24/arch/ia64/kernel/salinfo.c linux-2.4.24-ia64-040109/arch/ia64/kernel/salinfo.c --- linux-2.4.24/arch/ia64/kernel/salinfo.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/salinfo.c 2004-01-09 09:54:49.000000000 -0700 @@ -3,19 +3,29 @@ * * Creates entries in /proc/sal for various system features. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. * Copyright (c) 2003 Hewlett-Packard Co * Bjorn Helgaas * * 10/30/2001 jbarnes@sgi.com copied much of Stephane's palinfo * code to create this file + * Oct 23 2003 kaos@sgi.com + * Replace IPI with set_cpus_allowed() to read a record from the required cpu. + * Redesign salinfo log processing to separate interrupt and user space + * contexts. + * 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. */ #include #include #include #include +#include +#include +#include #include #include @@ -57,48 +67,175 @@ (2 * ARRAY_SIZE(salinfo_log_name)) + /* /proc/sal/mca/{event,data} */ 1]; /* /proc/sal */ -struct salinfo_log_data { - int type; - u8 *log_buffer; - u64 log_size; -}; +/* Allow build with or without large SSI support */ +#ifdef CPU_MASK_NONE +#define SCA(x, y) set_cpus_allowed((x), &(y)) +#else +#define cpumask_t unsigned long +#define SCA(x, y) set_cpus_allowed((x), (y)) +#endif -struct salinfo_event { - int type; - int cpu; /* next CPU to check */ - volatile unsigned long cpu_mask; - wait_queue_head_t queue; +/* Some records we get ourselves, some are accessed as saved data in buffers + * that are owned by mca.c. + */ +struct salinfo_data_saved { + u8* buffer; + u64 size; + u64 id; + int cpu; }; -static struct salinfo_event *salinfo_event[ARRAY_SIZE(salinfo_log_name)]; +/* State transitions. Actions are :- + * Write "read " to the data file. + * Write "clear " to the data file. + * Write "oemdata to the data file. + * Read from the data file. + * Close the data file. + * + * Start state is NO_DATA. + * + * NO_DATA + * write "read " -> NO_DATA or LOG_RECORD. + * write "clear " -> NO_DATA or LOG_RECORD. + * write "oemdata -> return -EINVAL. + * read data -> return EOF. + * close -> unchanged. Free record areas. + * + * LOG_RECORD + * write "read " -> NO_DATA or LOG_RECORD. + * write "clear " -> NO_DATA or LOG_RECORD. + * write "oemdata -> format the oem data, goto OEMDATA. + * read data -> return the INIT/MCA/CMC/CPE record. + * close -> unchanged. Keep record areas. + * + * OEMDATA + * write "read " -> NO_DATA or LOG_RECORD. + * write "clear " -> NO_DATA or LOG_RECORD. + * write "oemdata -> format the oem data, goto OEMDATA. + * read data -> return the formatted oemdata. + * close -> unchanged. Keep record areas. + * + * Closing the data file does not change the state. This allows shell scripts + * to manipulate salinfo data, each shell redirection opens the file, does one + * action then closes it again. The record areas are only freed at close when + * the state is NO_DATA. + */ +enum salinfo_state { + STATE_NO_DATA, + STATE_LOG_RECORD, + STATE_OEMDATA, +}; struct salinfo_data { - int open; /* single-open to prevent races */ - int type; - int cpu; /* "current" cpu for reads */ + volatile cpumask_t cpu_event; /* which cpus have outstanding events */ + struct semaphore sem; /* count of cpus with outstanding events (bits set in cpu_event) */ + u8 *log_buffer; + u64 log_size; + u8 *oemdata; /* decoded oem data */ + u64 oemdata_size; + int open; /* single-open to prevent races */ + u8 type; + u8 saved_num; /* using a saved record? */ + enum salinfo_state state :8; /* processing state */ + u8 padding; + int cpu_check; /* next CPU to check */ + struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */ }; static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)]; -static spinlock_t data_lock; +static spinlock_t data_lock, data_saved_lock; + +/** salinfo_platform_oemdata - optional callback to decode oemdata from an error + * record. + * @sect_header: pointer to the start of the section to decode. + * @oemdata: returns vmalloc area containing the decded output. + * @oemdata_size: returns length of decoded output (strlen). + * + * Description: If user space asks for oem data to be decoded by the kernel + * and/or prom and the platform has set salinfo_platform_oemdata to the address + * of a platform specific routine then call that routine. salinfo_platform_oemdata + * vmalloc's and formats its output area, returning the address of the text + * and its strlen. Returns 0 for success, -ve for error. The callback is + * invoked on the cpu that generated the error record. + */ +int (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size); + +struct salinfo_platform_oemdata_parms { + const u8 *efi_guid; + u8 **oemdata; + u64 *oemdata_size; + int ret; +}; + +static void +salinfo_platform_oemdata_cpu(void *context) +{ + struct salinfo_platform_oemdata_parms *parms = context; + parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size); +} +static void +shift1_data_saved (struct salinfo_data *data, int shift) +{ + memcpy(data->data_saved+shift, data->data_saved+shift+1, + (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0])); + memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0, + sizeof(data->data_saved[0])); +} + +/* 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. + * + * 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 + * when user space processes the record. Save the record id to identify + * changes. + */ void -salinfo_log_wakeup(int type) +salinfo_log_wakeup(int type, u8 *buffer, u64 size) { - if (type < ARRAY_SIZE(salinfo_log_name)) { - struct salinfo_event *event = salinfo_event[type]; + 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 saved_size = ARRAY_SIZE(data->data_saved); + + BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); + + if (irqsafe) + spin_lock_irqsave(&data_saved_lock, flags); + for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { + if (!data_saved->buffer) + break; + } + if (i == saved_size) { + if (!data->saved_num) { + shift1_data_saved(data, 0); + data_saved = data->data_saved + saved_size - 1; + } else + data_saved = NULL; + } + if (data_saved) { + data_saved->cpu = smp_processor_id(); + data_saved->id = ((sal_log_record_header_t *)buffer)->id; + data_saved->size = size; + data_saved->buffer = buffer; + } + if (irqsafe) + spin_unlock_irqrestore(&data_saved_lock, flags); - if (event) { - set_bit(smp_processor_id(), &event->cpu_mask); - wake_up_interruptible(&event->queue); - } + if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) { + if (irqsafe) + up(&data->sem); } } static int salinfo_event_open(struct inode *inode, struct file *file) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; return 0; } @@ -107,24 +244,23 @@ salinfo_event_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry *entry = (struct proc_dir_entry *) inode->u.generic_ip; - struct salinfo_event *event = entry->data; + struct proc_dir_entry *entry = PDE(inode); + struct salinfo_data *data = entry->data; char cmd[32]; size_t size; int i, n, cpu = -1; retry: - if (!event->cpu_mask) { + if (down_trylock(&data->sem)) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&event->queue); - if (signal_pending(current)) - return -EINTR; + if (down_interruptible(&data->sem)) + return -ERESTARTSYS; } - n = event->cpu; + n = data->cpu_check; for (i = 0; i < NR_CPUS; i++) { - if (event->cpu_mask & 1UL << n) { + if (test_bit(n, &data->cpu_event)) { cpu = n; break; } @@ -135,10 +271,13 @@ if (cpu == -1) goto retry; + /* events are sticky until the user says "clear" */ + up(&data->sem); + /* for next read, start checking at next CPU */ - event->cpu = cpu; - if (++event->cpu == NR_CPUS) - event->cpu = 0; + data->cpu_check = cpu; + if (++data->cpu_check == NR_CPUS) + data->cpu_check = 0; snprintf(cmd, sizeof(cmd), "read %d\n", cpu); @@ -159,10 +298,10 @@ static int salinfo_log_open(struct inode *inode, struct file *file) { - struct proc_dir_entry *entry = (struct proc_dir_entry *) inode->u.generic_ip; + struct proc_dir_entry *entry = PDE(inode); struct salinfo_data *data = entry->data; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; spin_lock(&data_lock); @@ -173,15 +312,27 @@ data->open = 1; spin_unlock(&data_lock); + if (data->state == STATE_NO_DATA && + !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) { + data->open = 0; + return -ENOMEM; + } + return 0; } static int salinfo_log_release(struct inode *inode, struct file *file) { - struct proc_dir_entry *entry = (struct proc_dir_entry *) inode->u.generic_ip; + struct proc_dir_entry *entry = PDE(inode); struct salinfo_data *data = entry->data; + if (data->state == STATE_NO_DATA) { + vfree(data->log_buffer); + vfree(data->oemdata); + data->log_buffer = NULL; + data->oemdata = NULL; + } spin_lock(&data_lock); data->open = 0; spin_unlock(&data_lock); @@ -191,95 +342,131 @@ static void call_on_cpu(int cpu, void (*fn)(void *), void *arg) { - if (cpu == smp_processor_id()) - (*fn)(arg); -#ifdef CONFIG_SMP - else if (cpu_online(cpu)) /* cpu may not have been validated */ - smp_call_function_single(cpu, fn, arg, 0, 1); -#endif + cpumask_t save_cpus_allowed, new_cpus_allowed; + memcpy(&save_cpus_allowed, ¤t->cpus_allowed, sizeof(save_cpus_allowed)); + memset(&new_cpus_allowed, 0, sizeof(new_cpus_allowed)); + set_bit(cpu, &new_cpus_allowed); + SCA(current, new_cpus_allowed); + (*fn)(arg); + SCA(current, save_cpus_allowed); } static void salinfo_log_read_cpu(void *context) { - struct salinfo_log_data *info = context; - struct salinfo_event *event = salinfo_event[info->type]; - u64 size; - - size = ia64_sal_get_state_info_size(info->type); - info->log_buffer = kmalloc(size, GFP_ATOMIC); - if (!info->log_buffer) - return; - - clear_bit(smp_processor_id(), &event->cpu_mask); - info->log_size = ia64_sal_get_state_info(info->type, (u64 *) info->log_buffer); - if (info->log_size) - salinfo_log_wakeup(info->type); + struct salinfo_data *data = context; + data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer); +} + +static void +salinfo_log_new_read(int cpu, struct salinfo_data *data) +{ + struct salinfo_data_saved *data_saved; + unsigned long flags; + int i; + int saved_size = ARRAY_SIZE(data->data_saved); + + data->saved_num = 0; + spin_lock_irqsave(&data_saved_lock, flags); +retry: + for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { + if (data_saved->buffer && data_saved->cpu == cpu) { + sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer); + data->log_size = data_saved->size; + memcpy(data->log_buffer, rh, data->log_size); + barrier(); /* id check must not be moved */ + if (rh->id == data_saved->id) { + data->saved_num = i+1; + break; + } + /* saved record changed by mca.c since interrupt, discard it */ + shift1_data_saved(data, i); + goto retry; + } + } + spin_unlock_irqrestore(&data_saved_lock, flags); + + if (!data->saved_num) + call_on_cpu(cpu, salinfo_log_read_cpu, data); + data->state = data->log_size ? STATE_LOG_RECORD : STATE_NO_DATA; } static ssize_t salinfo_log_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry *entry = (struct proc_dir_entry *) inode->u.generic_ip; + struct proc_dir_entry *entry = PDE(inode); struct salinfo_data *data = entry->data; - struct salinfo_log_data info; - int ret; void *saldata; size_t size; + u8 *buf; + u64 bufsize; - info.type = data->type; - info.log_buffer = 0; - call_on_cpu(data->cpu, salinfo_log_read_cpu, &info); - if (!info.log_buffer || *ppos >= info.log_size) { - ret = 0; - goto out; + if (data->state == STATE_LOG_RECORD) { + buf = data->log_buffer; + bufsize = data->log_size; + } else if (data->state == STATE_OEMDATA) { + buf = data->oemdata; + bufsize = data->oemdata_size; + } else { + buf = NULL; + bufsize = 0; } + if (*ppos >= bufsize) + return 0; - saldata = info.log_buffer + file->f_pos; - size = info.log_size - file->f_pos; + saldata = buf + file->f_pos; + size = bufsize - file->f_pos; if (size > count) size = count; - if (copy_to_user(buffer, saldata, size)) { - ret = -EFAULT; - goto out; - } + if (copy_to_user(buffer, saldata, size)) + return -EFAULT; *ppos += size; - ret = size; - -out: - kfree(info.log_buffer); - return ret; + return size; } static void salinfo_log_clear_cpu(void *context) { struct salinfo_data *data = context; - struct salinfo_event *event = salinfo_event[data->type]; - struct salinfo_log_data info; - - clear_bit(smp_processor_id(), &event->cpu_mask); ia64_sal_clear_state_info(data->type); +} - /* clearing one record may make another visible */ - info.type = data->type; - salinfo_log_read_cpu(&info); - if (info.log_buffer && info.log_size) - salinfo_log_wakeup(data->type); +static int +salinfo_log_clear(struct salinfo_data *data, int cpu) +{ + data->state = STATE_NO_DATA; + if (!test_bit(cpu, &data->cpu_event)) + return 0; + down(&data->sem); + clear_bit(cpu, &data->cpu_event); + if (data->saved_num) { + unsigned long flags; + spin_lock_irqsave(&data_saved_lock, flags); + shift1_data_saved(data, data->saved_num - 1 ); + data->saved_num = 0; + spin_unlock_irqrestore(&data_saved_lock, flags); + } + call_on_cpu(cpu, salinfo_log_clear_cpu, data); - kfree(info.log_buffer); + /* clearing a record may make a new record visible */ + salinfo_log_new_read(cpu, data); + if (data->state == STATE_LOG_RECORD && + !test_and_set_bit(cpu, &data->cpu_event)) + up(&data->sem); + return 0; } static ssize_t salinfo_log_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; - struct proc_dir_entry *entry = (struct proc_dir_entry *) inode->u.generic_ip; + struct proc_dir_entry *entry = PDE(inode); struct salinfo_data *data = entry->data; char cmd[32]; size_t size; + u32 offset; int cpu; size = sizeof(cmd); @@ -288,10 +475,31 @@ if (copy_from_user(cmd, buffer, size)) return -EFAULT; - if (sscanf(cmd, "read %d", &cpu) == 1) - data->cpu = cpu; - else if (sscanf(cmd, "clear %d", &cpu) == 1) - call_on_cpu(cpu, salinfo_log_clear_cpu, data); + if (sscanf(cmd, "read %d", &cpu) == 1) { + salinfo_log_new_read(cpu, data); + } else if (sscanf(cmd, "clear %d", &cpu) == 1) { + int ret; + if ((ret = salinfo_log_clear(data, cpu))) + count = ret; + } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) { + if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA) + return -EINVAL; + if (offset > data->log_size - sizeof(efi_guid_t)) + return -EINVAL; + data->state = STATE_OEMDATA; + if (salinfo_platform_oemdata) { + struct salinfo_platform_oemdata_parms parms = { + .efi_guid = data->log_buffer + offset, + .oemdata = &data->oemdata, + .oemdata_size = &data->oemdata_size + }; + call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms); + if (parms.ret) + count = parms.ret; + } else + data->oemdata_size = 0; + } else + return -EINVAL; return count; } @@ -309,9 +517,8 @@ struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */ struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */ struct proc_dir_entry *dir, *entry; - struct salinfo_event *event; struct salinfo_data *data; - int i, j; + int i, j, online; salinfo_dir = proc_mkdir("sal", NULL); if (!salinfo_dir) @@ -324,6 +531,9 @@ } for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) { + data = salinfo_data + i; + data->type = i; + sema_init(&data->sem, 0); dir = proc_mkdir(salinfo_log_name[i], salinfo_dir); if (!dir) continue; @@ -331,32 +541,26 @@ entry = create_proc_entry("event", S_IRUSR, dir); if (!entry) continue; - - event = kmalloc(sizeof(*event), GFP_KERNEL); - if (!event) - continue; - memset(event, 0, sizeof(*event)); - event->type = i; - init_waitqueue_head(&event->queue); - salinfo_event[i] = event; - /* we missed any events before now */ - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - set_bit(j, &event->cpu_mask); - entry->data = event; + entry->data = data; entry->proc_fops = &salinfo_event_fops; *sdir++ = entry; entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir); if (!entry) continue; - - data = &salinfo_data[i]; - data->type = i; entry->data = data; entry->proc_fops = &salinfo_data_fops; *sdir++ = entry; + /* we missed any events before now */ + online = 0; + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) { + set_bit(j, &data->cpu_event); + ++online; + } + sema_init(&data->sem, online); + *sdir++ = dir; } @@ -365,17 +569,6 @@ return 0; } -static void __exit -salinfo_exit(void) -{ - int i = 0; - - for (i = 0; i < ARRAY_SIZE(salinfo_proc_entries); i++) { - if (salinfo_proc_entries[i]) - remove_proc_entry (salinfo_proc_entries[i]->name, NULL); - } -} - /* * 'data' contains an integer that corresponds to the feature we're * testing @@ -385,8 +578,6 @@ { int len = 0; - MOD_INC_USE_COUNT; - len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n"); if (len <= off+count) *eof = 1; @@ -397,10 +588,7 @@ if (len>count) len = count; if (len<0) len = 0; - MOD_DEC_USE_COUNT; - return len; } module_init(salinfo_init); -module_exit(salinfo_exit); diff -u -rN linux-2.4.24/arch/ia64/kernel/setup.c linux-2.4.24-ia64-040109/arch/ia64/kernel/setup.c --- linux-2.4.24/arch/ia64/kernel/setup.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/setup.c 2004-01-09 09:54:49.000000000 -0700 @@ -46,6 +46,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_RAM # include @@ -64,6 +65,7 @@ struct cpuinfo_ia64 *_cpu_data[NR_CPUS]; #else struct cpuinfo_ia64 _cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section"))); + mmu_gather_t mmu_gathers[NR_CPUS]; #endif unsigned long ia64_cycles_per_usec; @@ -376,7 +378,6 @@ saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ efi_init(); - find_memory(); #ifdef CONFIG_ACPI_BOOT /* Initialize the ACPI boot-time table parser */ @@ -392,6 +393,7 @@ #endif /* CONFIG_APCI_BOOT */ iomem_resource.end = ~0UL; /* FIXME probably belongs elsewhere */ + find_memory(); #if 0 /* XXX fix me */ @@ -659,6 +661,7 @@ _cpu_data[cpu]->cpu_data[smp_processor_id()] = my_cpu_data; #else my_cpu_data = cpu_data(smp_processor_id()); + my_cpu_data->mmu_gathers = &mmu_gathers[smp_processor_id()]; #endif /* diff -u -rN linux-2.4.24/arch/ia64/kernel/sys_ia64.c linux-2.4.24-ia64-040109/arch/ia64/kernel/sys_ia64.c --- linux-2.4.24/arch/ia64/kernel/sys_ia64.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/sys_ia64.c 2004-01-09 09:54:49.000000000 -0700 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,10 @@ if (len > RGN_MAP_LIMIT) return -ENOMEM; +#ifdef CONFIG_HUGETLB_PAGE + if (rgn_index(addr)==REGION_HPAGE) + addr = 0; +#endif if (!addr) addr = TASK_UNMAPPED_BASE; diff -u -rN linux-2.4.24/arch/ia64/kernel/time.c linux-2.4.24-ia64-040109/arch/ia64/kernel/time.c --- linux-2.4.24/arch/ia64/kernel/time.c 2003-08-25 05:44:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/time.c 2004-01-09 09:54:49.000000000 -0700 @@ -93,7 +93,6 @@ * it! */ tv->tv_usec -= gettimeoffset(); - tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); while (tv->tv_usec < 0) { tv->tv_usec += 1000000; diff -u -rN linux-2.4.24/arch/ia64/kernel/traps.c linux-2.4.24-ia64-040109/arch/ia64/kernel/traps.c --- linux-2.4.24/arch/ia64/kernel/traps.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/kernel/traps.c 2004-01-09 09:54:49.000000000 -0700 @@ -221,10 +221,6 @@ unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, unsigned long stack) { - struct pt_regs *regs = (struct pt_regs *) &stack; - - printk(KERN_DEBUG "%s(%d): \n", current->comm, current->pid, - regs->r15, arg0, arg1, arg2, arg3); return -ENOSYS; } diff -u -rN linux-2.4.24/arch/ia64/lib/Makefile linux-2.4.24-ia64-040109/arch/ia64/lib/Makefile --- linux-2.4.24/arch/ia64/lib/Makefile 2003-06-13 08:51:29.000000000 -0600 +++ linux-2.4.24-ia64-040109/arch/ia64/lib/Makefile 2004-01-09 09:54:49.000000000 -0700 @@ -18,6 +18,7 @@ obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o +obj-$(CONFIG_MD_RAID5) += xor.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -u -rN linux-2.4.24/arch/ia64/lib/xor.S linux-2.4.24-ia64-040109/arch/ia64/lib/xor.S --- linux-2.4.24/arch/ia64/lib/xor.S 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/lib/xor.S 2004-01-09 09:54:49.000000000 -0700 @@ -0,0 +1,184 @@ +/* + * arch/ia64/lib/xor.S + * + * Optimized RAID-5 checksumming functions for IA-64. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +GLOBAL_ENTRY(xor_ia64_2) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 3, 0, 13, 16 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov ar.lc = in0 + mov pr.rot = 1 << 16 + ;; + .rotr s1[6+1], s2[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[6+1])st8.nta [r8] = d[1], 8 + nop.f 0 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_2) + +GLOBAL_ENTRY(xor_ia64_3) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 4, 0, 20, 24 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] + ;; +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], s3[6] + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_3) + +GLOBAL_ENTRY(xor_ia64_4) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 5, 0, 27, 32 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + mov r19 = in4 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[0]) ld8.nta s4[0] = [r19], 8 +(p[6]) xor r20 = s3[6], s4[6] + ;; +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], r20 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_4) + +GLOBAL_ENTRY(xor_ia64_5) + .prologue + .fframe 0 + .save ar.pfs, r31 + alloc r31 = ar.pfs, 6, 0, 34, 40 + .save ar.lc, r30 + mov r30 = ar.lc + .save pr, r29 + mov r29 = pr + ;; + .body + mov r8 = in1 + mov ar.ec = 6 + 2 + shr in0 = in0, 3 + ;; + adds in0 = -1, in0 + mov r16 = in1 + mov r17 = in2 + ;; + mov r18 = in3 + mov ar.lc = in0 + mov pr.rot = 1 << 16 + mov r19 = in4 + mov r20 = in5 + ;; + .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], s5[6+1], d[2] + .rotp p[6+2] +0: +(p[0]) ld8.nta s1[0] = [r16], 8 +(p[0]) ld8.nta s2[0] = [r17], 8 +(p[6]) xor d[0] = s1[6], s2[6] +(p[0]) ld8.nta s3[0] = [r18], 8 +(p[0]) ld8.nta s4[0] = [r19], 8 +(p[6]) xor r21 = s3[6], s4[6] + ;; +(p[0]) ld8.nta s5[0] = [r20], 8 +(p[6+1])st8.nta [r8] = d[1], 8 +(p[6]) xor d[0] = d[0], r21 + ;; +(p[6]) xor d[0] = d[0], s5[6] + nop.f 0 + br.ctop.dptk.few 0b + ;; + mov ar.lc = r30 + mov pr = r29, -1 + br.ret.sptk.few rp +END(xor_ia64_5) diff -u -rN linux-2.4.24/arch/ia64/mm/Makefile linux-2.4.24-ia64-040109/arch/ia64/mm/Makefile --- linux-2.4.24/arch/ia64/mm/Makefile 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/mm/Makefile 2004-01-09 09:54:49.000000000 -0700 @@ -14,5 +14,6 @@ obj-y := init.o fault.o tlb.o extable.o obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_DISCONTIGMEM) += discontig.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o include $(TOPDIR)/Rules.make diff -u -rN linux-2.4.24/arch/ia64/mm/hugetlbpage.c linux-2.4.24-ia64-040109/arch/ia64/mm/hugetlbpage.c --- linux-2.4.24/arch/ia64/mm/hugetlbpage.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/mm/hugetlbpage.c 2004-01-09 09:54:49.000000000 -0700 @@ -0,0 +1,461 @@ +/* + * IA-64 Huge TLB Page Support for Kernel. + * + * Copyright (C) 2002, Rohit Seth + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define TASK_HPAGE_BASE (REGION_HPAGE << REGION_SHIFT) + +static long htlbpagemem; +int htlbpage_max; +static long htlbzone_pages; + +struct vm_operations_struct hugetlb_vm_ops; +static LIST_HEAD(htlbpage_freelist); +static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED; + +static struct page *alloc_hugetlb_page(void) +{ + int i; + struct page *page; + + spin_lock(&htlbpage_lock); + if (list_empty(&htlbpage_freelist)) { + spin_unlock(&htlbpage_lock); + return NULL; + } + + page = list_entry(htlbpage_freelist.next, struct page, list); + list_del(&page->list); + htlbpagemem--; + spin_unlock(&htlbpage_lock); + set_page_count(page, 1); + for (i = 0; i < (HPAGE_SIZE/PAGE_SIZE); ++i) + clear_highpage(&page[i]); + return page; +} + +static pte_t * +huge_pte_alloc (struct mm_struct *mm, unsigned long addr) +{ + unsigned long taddr = htlbpage_to_page(addr); + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, taddr); + pmd = pmd_alloc(mm, pgd, taddr); + if (pmd) + pte = pte_alloc(mm, pmd, taddr); + return pte; +} + +static pte_t * +huge_pte_offset (struct mm_struct *mm, unsigned long addr) +{ + unsigned long taddr = htlbpage_to_page(addr); + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, taddr); + pmd = pmd_offset(pgd, taddr); + pte = pte_offset(pmd, taddr); + return pte; +} + +#define mk_pte_huge(entry) { pte_val(entry) |= _PAGE_P; } + +static void +set_huge_pte (struct mm_struct *mm, struct vm_area_struct *vma, + struct page *page, pte_t * page_table, int write_access) +{ + pte_t entry; + + mm->rss += (HPAGE_SIZE / PAGE_SIZE); + if (write_access) { + entry = + pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + } else + entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); + entry = pte_mkyoung(entry); + mk_pte_huge(entry); + set_pte(page_table, entry); + return; +} +/* + * This function checks for proper alignment of input addr and len parameters. + */ +int is_aligned_hugepage_range(unsigned long addr, unsigned long len) +{ + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) + return -EINVAL; + if (REGION_NUMBER(addr) != REGION_HPAGE) + return -EINVAL; + + return 0; +} +/* This function checks if the address and address+len falls out of HugeTLB region. It + * return -EINVAL if any part of address range falls in HugeTLB region. + */ +int is_invalid_hugepage_range(unsigned long addr, unsigned long len) +{ + if (REGION_NUMBER(addr) == REGION_HPAGE) + return -EINVAL; + if (REGION_NUMBER(addr+len) == REGION_HPAGE) + return -EINVAL; + return 0; +} + +int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, + struct vm_area_struct *vma) +{ + pte_t *src_pte, *dst_pte, entry; + struct page *ptepage; + unsigned long addr = vma->vm_start; + unsigned long end = vma->vm_end; + + while (addr < end) { + dst_pte = huge_pte_alloc(dst, addr); + if (!dst_pte) + goto nomem; + src_pte = huge_pte_offset(src, addr); + entry = *src_pte; + ptepage = pte_page(entry); + get_page(ptepage); + set_pte(dst_pte, entry); + dst->rss += (HPAGE_SIZE / PAGE_SIZE); + addr += HPAGE_SIZE; + } + return 0; +nomem: + return -ENOMEM; +} + +int +follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + struct page **pages, struct vm_area_struct **vmas, + unsigned long *st, int *length, int i) +{ + pte_t *ptep, pte; + unsigned long start = *st; + unsigned long pstart; + int len = *length; + struct page *page; + + do { + pstart = start; + ptep = huge_pte_offset(mm, start); + pte = *ptep; + +back1: + page = pte_page(pte); + if (pages) { + page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT); + pages[i] = page; + } + if (vmas) + vmas[i] = vma; + i++; + len--; + start += PAGE_SIZE; + if (((start & HPAGE_MASK) == pstart) && len && + (start < vma->vm_end)) + goto back1; + } while (len && start < vma->vm_end); + *length = len; + *st = start; + return i; +} + +void free_huge_page(struct page *page) +{ + BUG_ON(page_count(page)); + BUG_ON(page->mapping); + + INIT_LIST_HEAD(&page->list); + + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + htlbpagemem++; + spin_unlock(&htlbpage_lock); +} + +void huge_page_release(struct page *page) +{ + if (!put_page_testzero(page)) + return; + + free_huge_page(page); +} + +void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address; + pte_t *pte; + struct page *page; + + BUG_ON(start & (HPAGE_SIZE - 1)); + BUG_ON(end & (HPAGE_SIZE - 1)); + + for (address = start; address < end; address += HPAGE_SIZE) { + pte = huge_pte_offset(mm, address); + if (pte_none(*pte)) + continue; + page = pte_page(*pte); + huge_page_release(page); + pte_clear(pte); + } + mm->rss -= (end - start) >> PAGE_SHIFT; + flush_tlb_range(mm, start, end); +} + +void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long length) +{ + struct mm_struct *mm = vma->vm_mm; + spin_lock(&mm->page_table_lock); + unmap_hugepage_range(vma, start, start + length); + spin_unlock(&mm->page_table_lock); +} + +int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) +{ + struct mm_struct *mm = current->mm; + struct inode *inode = mapping->host; + unsigned long addr; + int ret = 0; + + BUG_ON(vma->vm_start & ~HPAGE_MASK); + BUG_ON(vma->vm_end & ~HPAGE_MASK); + + spin_lock(&mm->page_table_lock); + for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { + unsigned long idx; + pte_t *pte = huge_pte_alloc(mm, addr); + struct page *page; + + if (!pte) { + ret = -ENOMEM; + goto out; + } + if (!pte_none(*pte)) + continue; + + idx = ((addr - vma->vm_start) >> HPAGE_SHIFT) + + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); + page = find_get_page(mapping, idx); + if (!page) { + /* charge the fs quota first */ + if (hugetlb_get_quota(mapping)) { + ret = -ENOMEM; + goto out; + } + page = alloc_hugetlb_page(); + if (!page) { + hugetlb_put_quota(mapping); + ret = -ENOMEM; + goto out; + } + add_to_page_cache(page, mapping, idx); + unlock_page(page); + } + set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); + } +out: + spin_unlock(&mm->page_table_lock); + return ret; +} + +unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags) +{ + struct vm_area_struct *vmm; + + if (len > RGN_MAP_LIMIT) + return -ENOMEM; + if (len & ~HPAGE_MASK) + return -EINVAL; + /* This code assumes that REGION_HPAGE != 0. */ + if ((REGION_NUMBER(addr) != REGION_HPAGE) || (addr & (HPAGE_SIZE - 1))) + addr = TASK_HPAGE_BASE; + else + addr = COLOR_HALIGN(addr); + for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (REGION_OFFSET(addr) + len > RGN_MAP_LIMIT) + return -ENOMEM; + if (!vmm || (addr + len) <= vmm->vm_start) + return addr; + addr = COLOR_HALIGN(vmm->vm_end); + } +} +void update_and_free_page(struct page *page) +{ + int j; + struct page *map; + + map = page; + htlbzone_pages--; + for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) { + map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | + 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved); + set_page_count(map, 0); + map++; + } + set_page_count(page, 1); + __free_pages(page, HUGETLB_PAGE_ORDER); +} + +int try_to_free_low(int count) +{ + struct list_head *p; + struct page *page, *map; + + map = NULL; + spin_lock(&htlbpage_lock); + list_for_each(p, &htlbpage_freelist) { + if (map) { + list_del(&map->list); + update_and_free_page(map); + htlbpagemem--; + map = NULL; + if (++count == 0) + break; + } + page = list_entry(p, struct page, list); + if ((page_zone(page))->name[0] != 'H') //Look for non-Highmem zones. + map = page; + } + if (map) { + list_del(&map->list); + update_and_free_page(map); + htlbpagemem--; + count++; + } + spin_unlock(&htlbpage_lock); + return count; +} + +int set_hugetlb_mem_size(int count) +{ + int j, lcount; + struct page *page, *map; + + if (count < 0) + lcount = count; + else + lcount = count - htlbzone_pages; + + if (lcount == 0) + return (int)htlbzone_pages; + if (lcount > 0) { /* Increase the mem size. */ + while (lcount--) { + page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); + if (page == NULL) + break; + map = page; + for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) { + SetPageReserved(map); + map++; + } + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + htlbpagemem++; + htlbzone_pages++; + spin_unlock(&htlbpage_lock); + } + return (int) htlbzone_pages; + } + /* Shrink the memory size. */ + lcount = try_to_free_low(lcount); + while (lcount++ < 0) { + page = alloc_hugetlb_page(); + if (page == NULL) + break; + spin_lock(&htlbpage_lock); + update_and_free_page(page); + spin_unlock(&htlbpage_lock); + } + return (int) htlbzone_pages; +} + +int hugetlb_sysctl_handler(ctl_table *table, int write, struct file *file, void *buffer, size_t *length) +{ + proc_dointvec(table, write, file, buffer, length); + htlbpage_max = set_hugetlb_mem_size(htlbpage_max); + return 0; +} + +static int __init hugetlb_setup(char *s) +{ + if (sscanf(s, "%d", &htlbpage_max) <= 0) + htlbpage_max = 0; + return 1; +} +__setup("hugepages=", hugetlb_setup); + +static int __init hugetlb_init(void) +{ + int i, j; + struct page *page; + + for (i = 0; i < htlbpage_max; ++i) { + page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER); + if (!page) + break; + for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j) + SetPageReserved(&page[j]); + spin_lock(&htlbpage_lock); + list_add(&page->list, &htlbpage_freelist); + spin_unlock(&htlbpage_lock); + } + htlbpage_max = htlbpagemem = htlbzone_pages = i; + printk("Total HugeTLB memory allocated, %ld\n", htlbpagemem); + return 0; +} +module_init(hugetlb_init); + +int hugetlb_report_meminfo(char *buf) +{ + return sprintf(buf, + "HugePages_Total: %5lu\n" + "HugePages_Free: %5lu\n" + "Hugepagesize: %5lu kB\n", + htlbzone_pages, + htlbpagemem, + HPAGE_SIZE/1024); +} + +int is_hugepage_mem_enough(size_t size) +{ + if (size > (htlbpagemem << HPAGE_SHIFT)) + return 0; + return 1; +} + +static struct page *hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int unused) +{ + BUG(); + return NULL; +} + +struct vm_operations_struct hugetlb_vm_ops = { + .nopage = hugetlb_nopage, +}; diff -u -rN linux-2.4.24/arch/ia64/mm/init.c linux-2.4.24-ia64-040109/arch/ia64/mm/init.c --- linux-2.4.24/arch/ia64/mm/init.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/mm/init.c 2004-01-09 09:54:49.000000000 -0700 @@ -28,9 +28,6 @@ #include #include #include -#include - -mmu_gather_t mmu_gathers[NR_CPUS]; /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end; @@ -488,7 +485,8 @@ { char byte; - return __get_user(byte, (char *) page) == 0; + return (__get_user(byte, (char *) page) == 0) + && (__get_user(byte, (char *) (page + 1) - 1) == 0); } #define GRANULEROUNDDOWN(n) ((n) & ~(IA64_GRANULE_SIZE-1)) diff -u -rN linux-2.4.24/arch/ia64/mm/tlb.c linux-2.4.24-ia64-040109/arch/ia64/mm/tlb.c --- linux-2.4.24/arch/ia64/mm/tlb.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/mm/tlb.c 2004-01-09 09:54:49.000000000 -0700 @@ -75,7 +75,7 @@ * and because interrupts are disabled during context switch. */ for (i = 0; i < NR_CPUS; ++i) - if (i != smp_processor_id()) + if (cpu_online(i) && (i != smp_processor_id())) cpu_data(i)->need_tlb_flush = 1; local_flush_tlb_all(); } diff -u -rN linux-2.4.24/arch/ia64/tools/Makefile linux-2.4.24-ia64-040109/arch/ia64/tools/Makefile --- linux-2.4.24/arch/ia64/tools/Makefile 2002-11-28 16:53:09.000000000 -0700 +++ linux-2.4.24-ia64-040109/arch/ia64/tools/Makefile 2004-01-09 09:54:49.000000000 -0700 @@ -33,7 +33,7 @@ comma := , -print_offsets: print_offsets.c FORCE_RECOMPILE +print_offsets: emptyoffsets print_offsets.c FORCE_RECOMPILE $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) print_offsets.c -o $@ FORCE_RECOMPILE: @@ -43,9 +43,20 @@ offsets.h: print_offsets.s $(AWK) -f print_offsets.awk $^ > $@ -print_offsets.s: print_offsets.c +print_offsets.s: emptyoffsets print_offsets.c $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -S print_offsets.c -o $@ endif +# +# The TARGET offsets.h is included by ptrace.h, which is included by +# print_offsets.c, so can't compile print_offsets.c to create offsets.h +# until we already have offsets.h. Break the chicken-and-egg cycle by +# creating a dummy offsets.h with sufficient define's to bootstrap +# the first compilation of print_offsets.c. +# + +emptyoffsets: + test -f ${TARGET} || echo '#define IA64_TASK_THREAD_OFFSET 0' > ${TARGET} + .PHONY: all modules modules_install diff -u -rN linux-2.4.24/drivers/acpi/bus.c linux-2.4.24-ia64-040109/drivers/acpi/bus.c --- linux-2.4.24/drivers/acpi/bus.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/acpi/bus.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/acpi/pci_root.c linux-2.4.24-ia64-040109/drivers/acpi/pci_root.c --- linux-2.4.24/drivers/acpi/pci_root.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/acpi/pci_root.c 2004-01-09 09:54:49.000000000 -0700 @@ -61,8 +61,6 @@ acpi_handle handle; struct acpi_pci_id id; struct pci_bus *bus; - u64 mem_tra; - u64 io_tra; }; static LIST_HEAD(acpi_pci_roots); @@ -114,97 +112,6 @@ } } -void -acpi_pci_get_translations ( - struct acpi_pci_id *id, - u64 *mem_tra, - u64 *io_tra) -{ - struct list_head *node = NULL; - struct acpi_pci_root *entry; - - /* TBD: Locking */ - list_for_each(node, &acpi_pci_roots) { - entry = list_entry(node, struct acpi_pci_root, node); - if ((id->segment == entry->id.segment) - && (id->bus == entry->id.bus)) { - *mem_tra = entry->mem_tra; - *io_tra = entry->io_tra; - return; - } - } - - *mem_tra = 0; - *io_tra = 0; -} - - -static u64 -acpi_pci_root_bus_tra ( - struct acpi_resource *resource, - int type) -{ - struct acpi_resource_address16 *address16; - struct acpi_resource_address32 *address32; - struct acpi_resource_address64 *address64; - - while (1) { - switch (resource->id) { - case ACPI_RSTYPE_END_TAG: - return 0; - - case ACPI_RSTYPE_ADDRESS16: - address16 = (struct acpi_resource_address16 *) &resource->data; - if (type == address16->resource_type) { - return address16->address_translation_offset; - } - break; - - case ACPI_RSTYPE_ADDRESS32: - address32 = (struct acpi_resource_address32 *) &resource->data; - if (type == address32->resource_type) { - return address32->address_translation_offset; - } - break; - - case ACPI_RSTYPE_ADDRESS64: - address64 = (struct acpi_resource_address64 *) &resource->data; - if (type == address64->resource_type) { - return address64->address_translation_offset; - } - break; - } - resource = ACPI_PTR_ADD (struct acpi_resource, - resource, resource->length); - } - - return 0; -} - - -static int -acpi_pci_evaluate_crs ( - struct acpi_pci_root *root) -{ - acpi_status status; - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - - ACPI_FUNCTION_TRACE("acpi_pci_evaluate_crs"); - - status = acpi_get_current_resources (root->handle, &buffer); - if (ACPI_FAILURE(status)) - return_VALUE(-ENODEV); - - root->io_tra = acpi_pci_root_bus_tra ((struct acpi_resource *) - buffer.pointer, ACPI_IO_RANGE); - root->mem_tra = acpi_pci_root_bus_tra ((struct acpi_resource *) - buffer.pointer, ACPI_MEMORY_RANGE); - - acpi_os_free(buffer.pointer); - return_VALUE(0); -} - - static int acpi_pci_root_add ( struct acpi_device *device) @@ -245,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, @@ -289,10 +194,8 @@ root->id.function = device->pnp.bus_address & 0xFFFF; /* - * Evaluate _CRS to get root bridge resources * TBD: Need PCI interface for enumeration/configuration of roots. */ - acpi_pci_evaluate_crs(root); /* TBD: Locking */ list_add_tail(&root->node, &acpi_pci_roots); @@ -308,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 -rN linux-2.4.24/drivers/acpi/tables.c linux-2.4.24-ia64-040109/drivers/acpi/tables.c --- linux-2.4.24/drivers/acpi/tables.c 2003-11-28 11:26:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/acpi/tables.c 2004-01-09 09:54:49.000000000 -0700 @@ -262,10 +262,17 @@ /* Map the DSDT header via the pointer in the FADT */ if (id == ACPI_DSDT) { - struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header; + struct fadt_descriptor_rev2 *fadt = (struct fadt_descriptor_rev2 *) *header; + + if (fadt->revision == 3 && fadt->Xdsdt) { + *header = (void *) __acpi_map_table(fadt->Xdsdt, + sizeof(struct acpi_table_header)); + } else if (fadt->V1_dsdt) { + *header = (void *) __acpi_map_table(fadt->V1_dsdt, + sizeof(struct acpi_table_header)); + } else + *header = 0; - *header = (void *) __acpi_map_table(fadt->dsdt_addr, - sizeof(struct acpi_table_header)); if (!*header) { printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); return -ENODEV; diff -u -rN linux-2.4.24/drivers/char/Config.in linux-2.4.24-ia64-040109/drivers/char/Config.in --- linux-2.4.24/drivers/char/Config.in 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/Config.in 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/agp/agpgart_be.c linux-2.4.24-ia64-040109/drivers/char/agp/agpgart_be.c --- linux-2.4.24/drivers/char/agp/agpgart_be.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/agp/agpgart_be.c 2004-01-09 09:54:49.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); + pci_write_config_dword(agp_bridge.dev, agp_bridge.capndx + PCI_AGP_COMMAND, command); - /* - * PASS4: Go through 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, 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) @@ -6459,7 +6348,6 @@ "IGP9100/M", ati_generic_setup }, #endif /* CONFIG_AGP_ATI */ - { 0, }, /* dummy final entry, always present */ }; @@ -6542,7 +6430,6 @@ return -ENODEV; } - /* Supported Device Scanning routine */ static int __init agp_find_supported_device(void) @@ -6870,7 +6757,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 */ @@ -7088,7 +6975,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 -rN linux-2.4.24/drivers/char/drm/drmP.h linux-2.4.24-ia64-040109/drivers/char/drm/drmP.h --- linux-2.4.24/drivers/char/drm/drmP.h 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/drmP.h 2004-01-09 09:54:49.000000000 -0700 @@ -328,16 +328,16 @@ if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } /* Mapping helper macros */ -#define DRM_IOREMAP(map) \ - (map)->handle = DRM(ioremap)( (map)->offset, (map)->size ) +#define DRM_IOREMAP(map, dev) \ + (map)->handle = DRM(ioremap)((map)->offset, (map)->size, (dev) ) -#define DRM_IOREMAP_NOCACHE(map) \ - (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size) +#define DRM_IOREMAP_NOCACHE(map, dev) \ + (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size, (dev) ) -#define DRM_IOREMAPFREE(map) \ +#define DRM_IOREMAPFREE(map, dev) \ do { \ if ( (map)->handle && (map)->size ) \ - DRM(ioremapfree)( (map)->handle, (map)->size ); \ + DRM(ioremapfree)( (map)->handle, (map)->size, (dev) ); \ } while (0) #define DRM_FIND_MAP(_map, _o) \ @@ -789,9 +789,9 @@ extern unsigned long DRM(alloc_pages)(int order, int area); extern void DRM(free_pages)(unsigned long address, int order, int area); -extern void *DRM(ioremap)(unsigned long offset, unsigned long size); -extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size); -extern void DRM(ioremapfree)(void *pt, unsigned long size); +extern void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); #if __REALLY_HAVE_AGP extern agp_memory *DRM(alloc_agp)(int pages, u32 type); diff -u -rN linux-2.4.24/drivers/char/drm/drm_bufs.h linux-2.4.24-ia64-040109/drivers/char/drm/drm_bufs.h --- linux-2.4.24/drivers/char/drm/drm_bufs.h 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/drm_bufs.h 2004-01-09 09:54:49.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 ); @@ -123,7 +123,7 @@ MTRR_TYPE_WRCOMB, 1 ); } #endif - map->handle = DRM(ioremap)( map->offset, map->size ); + map->handle = DRM(ioremap)( map->offset, map->size, dev ); break; case _DRM_SHM: @@ -245,7 +245,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); diff -u -rN linux-2.4.24/drivers/char/drm/drm_drv.h linux-2.4.24-ia64-040109/drivers/char/drm/drm_drv.h --- linux-2.4.24/drivers/char/drm/drm_drv.h 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/drm_drv.h 2004-01-09 09:54:49.000000000 -0700 @@ -443,7 +443,7 @@ DRM_DEBUG( "mtrr_del=%d\n", retcode ); } #endif - DRM(ioremapfree)( map->handle, map->size ); + DRM(ioremapfree)( map->handle, map->size, dev ); break; case _DRM_SHM: vfree(map->handle); diff -u -rN linux-2.4.24/drivers/char/drm/drm_memory.h linux-2.4.24-ia64-040109/drivers/char/drm/drm_memory.h --- linux-2.4.24/drivers/char/drm/drm_memory.h 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/drm_memory.h 2004-01-09 09:54:49.000000000 -0700 @@ -290,9 +290,14 @@ } } -void *DRM(ioremap)(unsigned long offset, unsigned long size) +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; @@ -313,9 +356,14 @@ return pt; } -void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size) +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; @@ -336,7 +422,7 @@ return pt; } -void DRM(ioremapfree)(void *pt, unsigned long size) +void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) { int alloc_count; int free_count; @@ -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 -rN linux-2.4.24/drivers/char/drm/drm_vm.h linux-2.4.24-ia64-040109/drivers/char/drm/drm_vm.h --- linux-2.4.24/drivers/char/drm/drm_vm.h 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/drm_vm.h 2004-01-09 09:54:49.000000000 -0700 @@ -206,7 +206,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); @@ -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 -rN linux-2.4.24/drivers/char/drm/gamma_dma.c linux-2.4.24-ia64-040109/drivers/char/drm/gamma_dma.c --- linux-2.4.24/drivers/char/drm/gamma_dma.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/gamma_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -638,7 +638,7 @@ } else { DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->buffers, dev ); buf = dma->buflist[GLINT_DRI_BUF_COUNT]; pgt = buf->address; @@ -668,7 +668,7 @@ if ( dev->dev_private ) { drm_gamma_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t), DRM_MEM_DRIVER ); diff -u -rN linux-2.4.24/drivers/char/drm/i810_dma.c linux-2.4.24-ia64-040109/drivers/char/drm/i810_dma.c --- linux-2.4.24/drivers/char/drm/i810_dma.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/i810_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -276,7 +276,7 @@ if(dev_priv->ring.virtual_start) { DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } if(dev_priv->hw_status_page != 0UL) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -292,7 +292,7 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev); } } return 0; @@ -362,7 +362,7 @@ *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -415,7 +415,7 @@ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; diff -u -rN linux-2.4.24/drivers/char/drm/i830_dma.c linux-2.4.24-ia64-040109/drivers/char/drm/i830_dma.c --- linux-2.4.24/drivers/char/drm/i830_dma.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/i830_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -252,7 +252,7 @@ if(dev_priv->ring.virtual_start) { DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } if(dev_priv->hw_status_page != 0UL) { pci_free_consistent(dev->pdev, PAGE_SIZE, @@ -277,7 +277,7 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; - DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev); } } return 0; @@ -353,7 +353,7 @@ *buf_priv->in_use = I830_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -407,7 +407,7 @@ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; diff -u -rN linux-2.4.24/drivers/char/drm/mga_dma.c linux-2.4.24-ia64-040109/drivers/char/drm/mga_dma.c --- linux-2.4.24/drivers/char/drm/mga_dma.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/mga_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -556,9 +556,9 @@ (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->warp ); - DRM_IOREMAP( dev_priv->primary ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->warp, dev ); + DRM_IOREMAP( dev_priv->primary, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || @@ -644,9 +644,9 @@ if ( dev->dev_private ) { drm_mga_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->warp ); - DRM_IOREMAPFREE( dev_priv->primary ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->warp, dev ); + DRM_IOREMAPFREE( dev_priv->primary, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); if ( dev_priv->head != NULL ) { mga_freelist_cleanup( dev ); diff -u -rN linux-2.4.24/drivers/char/drm/r128_cce.c linux-2.4.24-ia64-040109/drivers/char/drm/r128_cce.c --- linux-2.4.24/drivers/char/drm/r128_cce.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/r128_cce.c 2004-01-09 09:54:49.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; @@ -542,9 +573,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cce_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -618,9 +649,9 @@ #if __REALLY_HAVE_SG if ( !dev_priv->is_pci ) { #endif - DRM_IOREMAPFREE( dev_priv->cce_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->cce_ring, dev ); + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); #if __REALLY_HAVE_SG } else { if (!DRM(ati_pcigart_cleanup)( dev, @@ -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 -rN linux-2.4.24/drivers/char/drm/radeon_cp.c linux-2.4.24-ia64-040109/drivers/char/drm/radeon_cp.c --- linux-2.4.24/drivers/char/drm/radeon_cp.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm/radeon_cp.c 2004-01-09 09:54:49.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; @@ -1145,9 +1161,9 @@ init->sarea_priv_offset); if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cp_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { @@ -1266,9 +1282,9 @@ drm_radeon_private_t *dev_priv = dev->dev_private; if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cp_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + DRM_IOREMAPFREE( dev_priv->cp_ring, dev ); + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DRM_IOREMAPFREE( dev_priv->buffers, dev ); } else { #if __REALLY_HAVE_SG if (!DRM(ati_pcigart_cleanup)( dev, @@ -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 -rN linux-2.4.24/drivers/char/drm-4.0/agpsupport.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/agpsupport.c --- linux-2.4.24/drivers/char/drm-4.0/agpsupport.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/agpsupport.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/drm-4.0/bufs.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/bufs.c --- linux-2.4.24/drivers/char/drm-4.0/bufs.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/bufs.c 2004-01-09 09:54:49.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); @@ -87,7 +87,7 @@ MTRR_TYPE_WRCOMB, 1); } #endif - map->handle = drm_ioremap(map->offset, map->size); + map->handle = drm_ioremap(map->offset, map->size, dev); break; diff -u -rN linux-2.4.24/drivers/char/drm-4.0/drmP.h linux-2.4.24-ia64-040109/drivers/char/drm-4.0/drmP.h --- linux-2.4.24/drivers/char/drm-4.0/drmP.h 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/drmP.h 2004-01-09 09:54:49.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 @@ -679,8 +681,8 @@ extern unsigned long drm_alloc_pages(int order, int area); extern void drm_free_pages(unsigned long address, int order, int area); -extern void *drm_ioremap(unsigned long offset, unsigned long size); -extern void drm_ioremapfree(void *pt, unsigned long size); +extern void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev); #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) extern agp_memory *drm_alloc_agp(int pages, u32 type); diff -u -rN linux-2.4.24/drivers/char/drm-4.0/ffb_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/ffb_drv.c --- linux-2.4.24/drivers/char/drm-4.0/ffb_drv.c 2002-11-28 16:53:12.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/ffb_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -158,7 +158,7 @@ switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: diff -u -rN linux-2.4.24/drivers/char/drm-4.0/gamma_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/gamma_drv.c --- linux-2.4.24/drivers/char/drm-4.0/gamma_drv.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/gamma_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -258,7 +258,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/i810_dma.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/i810_dma.c --- linux-2.4.24/drivers/char/drm-4.0/i810_dma.c 2003-06-13 08:51:32.000000000 -0600 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/i810_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -305,7 +305,7 @@ if(dev_priv->ring.virtual_start) { drm_ioremapfree((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } if(dev_priv->hw_status_page != 0UL) { i810_free_page(dev, dev_priv->hw_status_page); @@ -319,7 +319,7 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - drm_ioremapfree(buf_priv->kernel_virtual, buf->total); + drm_ioremapfree(buf_priv->kernel_virtual, buf->total, dev); } } return 0; @@ -393,7 +393,7 @@ *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -430,7 +430,7 @@ dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; diff -u -rN linux-2.4.24/drivers/char/drm-4.0/i810_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/i810_drv.c --- linux-2.4.24/drivers/char/drm-4.0/i810_drv.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/i810_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -286,7 +286,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/memory.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/memory.c --- linux-2.4.24/drivers/char/drm-4.0/memory.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/memory.c 2004-01-09 09:54:49.000000000 -0700 @@ -296,7 +296,7 @@ } } -void *drm_ioremap(unsigned long offset, unsigned long size) +void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) { void *pt; @@ -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; @@ -319,7 +351,7 @@ return pt; } -void drm_ioremapfree(void *pt, unsigned long size) +void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) { int alloc_count; int free_count; @@ -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 -rN linux-2.4.24/drivers/char/drm-4.0/mga_dma.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_dma.c --- linux-2.4.24/drivers/char/drm-4.0/mga_dma.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_dma.c 2004-01-09 09:54:49.000000000 -0700 @@ -308,7 +308,7 @@ temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, - temp); + temp, dev); if(dev_priv->ioremap == NULL) { DRM_ERROR("Ioremap failed\n"); return -ENOMEM; @@ -635,7 +635,7 @@ dev_priv->primary_size + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; - drm_ioremapfree((void *) dev_priv->ioremap, temp); + drm_ioremapfree((void *) dev_priv->ioremap, temp, dev); } if(dev_priv->status_page != NULL) { iounmap(dev_priv->status_page); @@ -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 -rN linux-2.4.24/drivers/char/drm-4.0/mga_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_drv.c --- linux-2.4.24/drivers/char/drm-4.0/mga_drv.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -286,7 +286,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/mga_drv.h linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_drv.h --- linux-2.4.24/drivers/char/drm-4.0/mga_drv.h 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/mga_drv.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/drm-4.0/r128_cce.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/r128_cce.c --- linux-2.4.24/drivers/char/drm-4.0/r128_cce.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/r128_cce.c 2004-01-09 09:54:49.000000000 -0700 @@ -86,12 +86,12 @@ }; -#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) +#define DO_REMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size, (_d)) -#define DO_REMAPFREE(_m) \ +#define DO_REMAPFREE(_m, _d) \ do { \ if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ + drm_ioremapfree((_m)->handle, (_m)->size, (_d)); \ } while (0) #define DO_FIND_MAP(_m, _o) \ @@ -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, @@ -481,12 +512,12 @@ (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_REMAP( dev_priv->cce_ring ); - DO_REMAP( dev_priv->ring_rptr ); - DO_REMAP( dev_priv->buffers ); + DO_REMAP( dev_priv->cce_ring, dev ); + DO_REMAP( dev_priv->ring_rptr, dev ); + DO_REMAP( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_REMAP( dev_priv->agp_textures ); + DO_REMAP( dev_priv->agp_textures, dev ); } #endif @@ -521,15 +552,28 @@ if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; - DO_REMAPFREE( dev_priv->cce_ring ); - DO_REMAPFREE( dev_priv->ring_rptr ); - DO_REMAPFREE( dev_priv->buffers ); + DO_REMAPFREE( dev_priv->cce_ring, dev ); + DO_REMAPFREE( dev_priv->ring_rptr, dev ); + DO_REMAPFREE( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_REMAPFREE( dev_priv->agp_textures ); + DO_REMAPFREE( dev_priv->agp_textures, dev ); } #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 -rN linux-2.4.24/drivers/char/drm-4.0/r128_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/r128_drv.c --- linux-2.4.24/drivers/char/drm-4.0/r128_drv.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/r128_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -296,7 +296,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/radeon_cp.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_cp.c --- linux-2.4.24/drivers/char/drm-4.0/radeon_cp.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_cp.c 2004-01-09 09:54:49.000000000 -0700 @@ -300,12 +300,12 @@ }; -#define DO_IOREMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) +#define DO_IOREMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size, (_d)) -#define DO_IOREMAPFREE(_m) \ +#define DO_IOREMAPFREE(_m, _d) \ do { \ if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ + drm_ioremapfree((_m)->handle, (_m)->size, (_d));\ } while (0) #define DO_FIND_MAP(_m, _o) \ @@ -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 ); @@ -757,12 +776,12 @@ (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_IOREMAP( dev_priv->cp_ring ); - DO_IOREMAP( dev_priv->ring_rptr ); - DO_IOREMAP( dev_priv->buffers ); + DO_IOREMAP( dev_priv->cp_ring, dev ); + DO_IOREMAP( dev_priv->ring_rptr, dev ); + DO_IOREMAP( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAP( dev_priv->agp_textures ); + DO_IOREMAP( dev_priv->agp_textures, dev ); } #endif @@ -828,15 +847,28 @@ if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; - DO_IOREMAPFREE( dev_priv->cp_ring ); - DO_IOREMAPFREE( dev_priv->ring_rptr ); - DO_IOREMAPFREE( dev_priv->buffers ); + DO_IOREMAPFREE( dev_priv->cp_ring, dev ); + DO_IOREMAPFREE( dev_priv->ring_rptr, dev ); + DO_IOREMAPFREE( dev_priv->buffers, dev ); #if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAPFREE( dev_priv->agp_textures ); + DO_IOREMAPFREE( dev_priv->agp_textures, dev ); } #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 -rN linux-2.4.24/drivers/char/drm-4.0/radeon_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_drv.c --- linux-2.4.24/drivers/char/drm-4.0/radeon_drv.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -294,7 +294,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/radeon_drv.h linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_drv.h --- linux-2.4.24/drivers/char/drm-4.0/radeon_drv.h 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/radeon_drv.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/drm-4.0/tdfx_drv.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/tdfx_drv.c --- linux-2.4.24/drivers/char/drm-4.0/tdfx_drv.c 2002-11-28 16:53:12.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/tdfx_drv.c 2004-01-09 09:54:49.000000000 -0700 @@ -264,7 +264,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - drm_ioremapfree(map->handle, map->size); + drm_ioremapfree(map->handle, map->size, dev); break; case _DRM_SHM: drm_free_pages((unsigned long)map->handle, diff -u -rN linux-2.4.24/drivers/char/drm-4.0/vm.c linux-2.4.24-ia64-040109/drivers/char/drm-4.0/vm.c --- linux-2.4.24/drivers/char/drm-4.0/vm.c 2002-02-25 12:37:57.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/drm-4.0/vm.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/mem.c linux-2.4.24-ia64-040109/drivers/char/mem.c --- linux-2.4.24/drivers/char/mem.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/mem.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/char/serial.c linux-2.4.24-ia64-040109/drivers/char/serial.c --- linux-2.4.24/drivers/char/serial.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/char/serial.c 2004-01-09 09:54:49.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 @@ -4286,6 +4359,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; } @@ -4589,6 +4668,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, @@ -5550,6 +5752,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 @@ -5727,6 +5932,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 -rN linux-2.4.24/drivers/net/tulip/media.c linux-2.4.24-ia64-040109/drivers/net/tulip/media.c --- linux-2.4.24/drivers/net/tulip/media.c 2003-06-13 08:51:35.000000000 -0600 +++ linux-2.4.24-ia64-040109/drivers/net/tulip/media.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/pci/pci.c linux-2.4.24-ia64-040109/drivers/pci/pci.c --- linux-2.4.24/drivers/pci/pci.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/pci/pci.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/megaraid.c linux-2.4.24-ia64-040109/drivers/scsi/megaraid.c --- linux-2.4.24/drivers/scsi/megaraid.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/megaraid.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/qla1280.c linux-2.4.24-ia64-040109/drivers/scsi/qla1280.c --- linux-2.4.24/drivers/scsi/qla1280.c 2003-11-28 11:26:20.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/qla1280.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/scsi_dma.c linux-2.4.24-ia64-040109/drivers/scsi/scsi_dma.c --- linux-2.4.24/drivers/scsi/scsi_dma.c 2002-02-25 12:38:04.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/scsi_dma.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/scsi_ioctl.c linux-2.4.24-ia64-040109/drivers/scsi/scsi_ioctl.c --- linux-2.4.24/drivers/scsi/scsi_ioctl.c 2003-08-25 05:44:42.000000000 -0600 +++ linux-2.4.24-ia64-040109/drivers/scsi/scsi_ioctl.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/scsi_merge.c linux-2.4.24-ia64-040109/drivers/scsi/scsi_merge.c --- linux-2.4.24/drivers/scsi/scsi_merge.c 2002-11-28 16:53:14.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/scsi_merge.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/sym53c8xx.c linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx.c --- linux-2.4.24/drivers/scsi/sym53c8xx.c 2003-06-13 08:51:36.000000000 -0600 +++ linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/sym53c8xx_2/sym_glue.c linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx_2/sym_glue.c --- linux-2.4.24/drivers/scsi/sym53c8xx_2/sym_glue.c 2002-11-28 16:53:14.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx_2/sym_glue.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/drivers/scsi/sym53c8xx_comm.h linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx_comm.h --- linux-2.4.24/drivers/scsi/sym53c8xx_comm.h 2002-11-28 16:53:14.000000000 -0700 +++ linux-2.4.24-ia64-040109/drivers/scsi/sym53c8xx_comm.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/Config.in linux-2.4.24-ia64-040109/fs/Config.in --- linux-2.4.24/fs/Config.in 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/Config.in 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/Makefile linux-2.4.24-ia64-040109/fs/Makefile --- linux-2.4.24/fs/Makefile 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/fs/Makefile 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/binfmt_misc.c linux-2.4.24-ia64-040109/fs/binfmt_misc.c --- linux-2.4.24/fs/binfmt_misc.c 2002-08-02 18:39:45.000000000 -0600 +++ linux-2.4.24-ia64-040109/fs/binfmt_misc.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/hugetlbfs/Makefile linux-2.4.24-ia64-040109/fs/hugetlbfs/Makefile --- linux-2.4.24/fs/hugetlbfs/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/hugetlbfs/Makefile 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/hugetlbfs/inode.c linux-2.4.24-ia64-040109/fs/hugetlbfs/inode.c --- linux-2.4.24/fs/hugetlbfs/inode.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/hugetlbfs/inode.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/inode.c linux-2.4.24-ia64-040109/fs/inode.c --- linux-2.4.24/fs/inode.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/inode.c 2004-01-09 09:54:49.000000000 -0700 @@ -56,7 +56,7 @@ */ static LIST_HEAD(inode_in_use); -static LIST_HEAD(inode_unused); +LIST_HEAD(inode_unused); static struct list_head *inode_hashtable; static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */ diff -u -rN linux-2.4.24/fs/proc/array.c linux-2.4.24-ia64-040109/fs/proc/array.c --- linux-2.4.24/fs/proc/array.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/proc/array.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/fs/proc/proc_misc.c linux-2.4.24-ia64-040109/fs/proc/proc_misc.c --- linux-2.4.24/fs/proc/proc_misc.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/fs/proc/proc_misc.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/acpi/acpi_drivers.h linux-2.4.24-ia64-040109/include/acpi/acpi_drivers.h --- linux-2.4.24/include/acpi/acpi_drivers.h 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/acpi/acpi_drivers.h 2004-01-09 09:54:49.000000000 -0700 @@ -162,7 +162,6 @@ int acpi_pci_root_init (void); void acpi_pci_root_exit (void); -void acpi_pci_get_translations (struct acpi_pci_id* id, u64* mem_tra, u64* io_tra); /* ACPI PCI Interrupt Link (pci_link.c) */ diff -u -rN linux-2.4.24/include/asm-generic/tlb.h linux-2.4.24-ia64-040109/include/asm-generic/tlb.h --- linux-2.4.24/include/asm-generic/tlb.h 2002-08-02 18:39:45.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-generic/tlb.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-generic/xor.h linux-2.4.24-ia64-040109/include/asm-generic/xor.h --- linux-2.4.24/include/asm-generic/xor.h 2000-11-12 20:39:51.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-generic/xor.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-i386/hw_irq.h linux-2.4.24-ia64-040109/include/asm-i386/hw_irq.h --- linux-2.4.24/include/asm-i386/hw_irq.h 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-i386/hw_irq.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-i386/page.h linux-2.4.24-ia64-040109/include/asm-i386/page.h --- linux-2.4.24/include/asm-i386/page.h 2002-08-02 18:39:45.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-i386/page.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-i386/pgtable.h linux-2.4.24-ia64-040109/include/asm-i386/pgtable.h --- linux-2.4.24/include/asm-i386/pgtable.h 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-i386/pgtable.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-i386/ptrace.h linux-2.4.24-ia64-040109/include/asm-i386/ptrace.h --- linux-2.4.24/include/asm-i386/ptrace.h 2001-09-14 15:04:08.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-i386/ptrace.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-ia64/kmap_types.h linux-2.4.24-ia64-040109/include/asm-ia64/kmap_types.h --- linux-2.4.24/include/asm-ia64/kmap_types.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/kmap_types.h 2004-01-09 09:54:49.000000000 -0700 @@ -0,0 +1,31 @@ +#ifndef _ASM_IA64_KMAP_TYPES_H +#define _ASM_IA64_KMAP_TYPES_H + +#include + +#ifdef CONFIG_DEBUG_HIGHMEM +# define D(n) __KM_FENCE_##n , +#else +# define D(n) +#endif + +enum km_type { +D(0) KM_BOUNCE_READ, +D(1) KM_SKB_SUNRPC_DATA, +D(2) KM_SKB_DATA_SOFTIRQ, +D(3) KM_USER0, +D(4) KM_USER1, +D(5) KM_BIO_SRC_IRQ, +D(6) KM_BIO_DST_IRQ, +D(7) KM_PTE0, +D(8) KM_PTE1, +D(9) KM_IRQ0, +D(10) KM_IRQ1, +D(11) KM_SOFTIRQ0, +D(12) KM_SOFTIRQ1, +D(13) KM_TYPE_NR +}; + +#undef D + +#endif /* _ASM_IA64_KMAP_TYPES_H */ diff -u -rN linux-2.4.24/include/asm-ia64/machvec.h linux-2.4.24-ia64-040109/include/asm-ia64/machvec.h --- linux-2.4.24/include/asm-ia64/machvec.h 2003-06-13 08:51:38.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/machvec.h 2004-01-09 09:54:49.000000000 -0700 @@ -24,7 +24,6 @@ typedef void ia64_mv_cpu_init_t(void); typedef void ia64_mv_irq_init_t (void); typedef void ia64_mv_pci_fixup_t (int); -typedef void ia64_mv_pci_enable_device_t (struct pci_dev *); typedef unsigned long ia64_mv_map_nr_t (void *); typedef void ia64_mv_mca_init_t (void); typedef void ia64_mv_mca_handler_t (void); @@ -91,7 +90,6 @@ # define platform_cmci_handler ia64_mv.cmci_handler # define platform_log_print ia64_mv.log_print # define platform_pci_fixup ia64_mv.pci_fixup -# define platform_pci_enable_device ia64_mv.pci_enable_device # define platform_send_ipi ia64_mv.send_ipi # define platform_global_tlb_purge ia64_mv.global_tlb_purge # define platform_pci_dma_init ia64_mv.dma_init @@ -121,7 +119,6 @@ ia64_mv_cpu_init_t *cpu_init; ia64_mv_irq_init_t *irq_init; ia64_mv_pci_fixup_t *pci_fixup; - ia64_mv_pci_enable_device_t *pci_enable_device; ia64_mv_map_nr_t *map_nr; ia64_mv_mca_init_t *mca_init; ia64_mv_mca_handler_t *mca_handler; @@ -157,7 +154,6 @@ platform_cpu_init, \ platform_irq_init, \ platform_pci_fixup, \ - platform_pci_enable_device, \ platform_map_nr, \ platform_mca_init, \ platform_mca_handler, \ @@ -235,9 +231,6 @@ #ifndef platform_pci_fixup # define platform_pci_fixup ((ia64_mv_pci_fixup_t *) machvec_noop) #endif -#ifndef platform_pci_enable_device -# define platform_pci_enable_device ((ia64_mv_pci_enable_device_t *) machvec_noop) -#endif #ifndef platform_send_ipi # define platform_send_ipi ia64_send_ipi /* default to architected version */ #endif diff -u -rN linux-2.4.24/include/asm-ia64/machvec_hpzx1.h linux-2.4.24-ia64-040109/include/asm-ia64/machvec_hpzx1.h --- linux-2.4.24/include/asm-ia64/machvec_hpzx1.h 2003-06-13 08:51:38.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/machvec_hpzx1.h 2004-01-09 09:54:49.000000000 -0700 @@ -3,10 +3,9 @@ extern ia64_mv_setup_t dig_setup; extern ia64_mv_pci_fixup_t hpzx1_pci_fixup; -extern ia64_mv_pci_enable_device_t sba_enable_device; extern ia64_mv_map_nr_t map_nr_dense; -extern ia64_mv_pci_alloc_consistent sba_alloc_consistent; -extern ia64_mv_pci_free_consistent sba_free_consistent; +extern ia64_mv_pci_alloc_consistent sba_alloc_coherent; +extern ia64_mv_pci_free_consistent sba_free_coherent; extern ia64_mv_pci_map_single sba_map_single; extern ia64_mv_pci_unmap_single sba_unmap_single; extern ia64_mv_pci_map_sg sba_map_sg; @@ -20,14 +19,13 @@ * platform's machvec structure. When compiling a non-generic kernel, * the macros are used directly. */ -#define platform_name "hpzx1" +#define platform_name "hp" #define platform_setup dig_setup #define platform_pci_fixup hpzx1_pci_fixup -#define platform_pci_enable_device sba_enable_device #define platform_map_nr map_nr_dense #define platform_pci_dma_init ((ia64_mv_pci_dma_init *) machvec_noop) -#define platform_pci_alloc_consistent sba_alloc_consistent -#define platform_pci_free_consistent sba_free_consistent +#define platform_pci_alloc_consistent sba_alloc_coherent +#define platform_pci_free_consistent sba_free_coherent #define platform_pci_map_single sba_map_single #define platform_pci_unmap_single sba_unmap_single #define platform_pci_map_sg sba_map_sg diff -u -rN linux-2.4.24/include/asm-ia64/mca.h linux-2.4.24-ia64-040109/include/asm-ia64/mca.h --- linux-2.4.24/include/asm-ia64/mca.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/mca.h 2004-01-09 09:54:49.000000000 -0700 @@ -140,7 +140,6 @@ extern int ia64_log_print(int,prfunc_t); extern void ia64_mca_cmc_vector_setup(void); extern int ia64_mca_check_errors(void); -extern u64 ia64_log_get(int, prfunc_t); #define PLATFORM_CALL(fn, args) printk("Platform call TBD\n") diff -u -rN linux-2.4.24/include/asm-ia64/mca_asm.h linux-2.4.24-ia64-040109/include/asm-ia64/mca_asm.h --- linux-2.4.24/include/asm-ia64/mca_asm.h 2003-06-13 08:51:38.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/mca_asm.h 2004-01-09 09:54:49.000000000 -0700 @@ -212,7 +212,8 @@ * saved onto the new stack frame. * * +-----------------------+ - * |NDIRTY [BSP - BSPSTORE]| + * |NDIRTY_WORDS | + * | [BSP - BSPSTORE]| * +-----------------------+ * | RNAT | * +-----------------------+ @@ -230,7 +231,7 @@ #define rse_ifs_offset (rse_pfs_offset+0x08) #define rse_bspstore_offset (rse_ifs_offset+0x08) #define rse_rnat_offset (rse_bspstore_offset+0x08) -#define rse_ndirty_offset (rse_rnat_offset+0x08) +#define rse_ndirty_words_offset (rse_rnat_offset+0x08) /* * rse_switch_context @@ -243,7 +244,8 @@ * 6. Save the old RNAT on the new stack frame * 7. Write BSPSTORE with the new backing store pointer * 8. Read and save the new BSP to calculate the #dirty registers - * NOTE: Look at pages 11-10, 11-11 in PRM Vol 2 + * NOTE: Look at section 6.11 in Intel IA-64 Architecture Software Developer's + * Manual, Volume 2, System Architecture. */ #define rse_switch_context(temp,p_stackframe,p_bspstore) \ ;; \ @@ -280,12 +282,12 @@ #define rse_return_context(psr_mask_reg,temp,p_stackframe) \ ;; \ alloc temp=ar.pfs,0,0,0,0; \ - add p_stackframe=rse_ndirty_offset,p_stackframe;; \ + add p_stackframe=rse_ndirty_words_offset,p_stackframe;; \ ld8 temp=[p_stackframe];; \ shl temp=temp,16;; \ mov ar.rsc=temp;; \ loadrs;; \ - add p_stackframe=-rse_ndirty_offset+rse_bspstore_offset,p_stackframe;;\ + add p_stackframe=-rse_ndirty_words_offset+rse_bspstore_offset,p_stackframe;;\ ld8 temp=[p_stackframe];; \ mov ar.bspstore=temp;; \ add p_stackframe=-rse_bspstore_offset+rse_rnat_offset,p_stackframe;;\ diff -u -rN linux-2.4.24/include/asm-ia64/mmu_context.h linux-2.4.24-ia64-040109/include/asm-ia64/mmu_context.h --- linux-2.4.24/include/asm-ia64/mmu_context.h 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/mmu_context.h 2004-01-09 09:54:49.000000000 -0700 @@ -114,6 +114,10 @@ rr2 = rr0 + 2*rid_incr; rr3 = rr0 + 3*rid_incr; rr4 = rr0 + 4*rid_incr; +#ifdef CONFIG_HUGETLB_PAGE + rr4 = (rr4 & (~(0xfcUL))) | (HPAGE_SHIFT << 2); +#endif + ia64_set_rr(0x0000000000000000, rr0); ia64_set_rr(0x2000000000000000, rr1); ia64_set_rr(0x4000000000000000, rr2); diff -u -rN linux-2.4.24/include/asm-ia64/page.h linux-2.4.24-ia64-040109/include/asm-ia64/page.h --- linux-2.4.24/include/asm-ia64/page.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/page.h 2004-01-09 09:54:49.000000000 -0700 @@ -30,8 +30,36 @@ #define PAGE_MASK (~(PAGE_SIZE - 1)) #define PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) & PAGE_MASK) +#ifdef CONFIG_HUGETLB_PAGE +#if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB) +#define HPAGE_SHIFT 32 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1GB) +#define HPAGE_SHIFT 30 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256MB) +#define HPAGE_SHIFT 28 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) +#define HPAGE_SHIFT 26 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_16MB) +#define HPAGE_SHIFT 24 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) +#define HPAGE_SHIFT 22 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +#define HPAGE_SHIFT 20 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256KB) +#define HPAGE_SHIFT 18 +#else +# error Unsupported IA-64 HugeTLB Page Size! +#endif + +#define REGION_HPAGE (4UL) +#define REGION_SHIFT 61 +#define HPAGE_SIZE (__IA64_UL_CONST(1) << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) +#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA +#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) @@ -85,6 +113,14 @@ #define REGION_SIZE REGION_NUMBER(1) #define REGION_KERNEL 7 +#ifdef CONFIG_HUGETLB_PAGE +#define htlbpage_to_page(x) ((REGION_NUMBER(x) << 61) | (REGION_OFFSET(x) >> (HPAGE_SHIFT-PAGE_SHIFT))) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +extern int is_invalid_hugepage_range(unsigned long addr, unsigned long len); +#else +#define is_invalid_hugepage_range(addr, len) 0 +#endif + #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) #define PAGE_BUG(page) do { BUG(); } while (0) diff -u -rN linux-2.4.24/include/asm-ia64/pal.h linux-2.4.24-ia64-040109/include/asm-ia64/pal.h --- linux-2.4.24/include/asm-ia64/pal.h 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/pal.h 2004-01-09 09:54:49.000000000 -0700 @@ -407,10 +407,11 @@ * generated. * (Trap Lost ) */ - op : 3, /* Operation that - * caused the machine - * check + mi : 1, /* More information available + * call PAL_MC_ERROR_INFO */ + pi : 1, /* Precise instruction pointer */ + pm : 1, /* Precise min-state save area */ dy : 1, /* Processor dynamic * state valid @@ -452,32 +453,23 @@ * by the processor */ - reserved2 : 12, + reserved2 : 11, cc : 1, /* Cache check */ tc : 1, /* TLB check */ bc : 1, /* Bus check */ - uc : 1; /* Unknown check */ + rc : 1, /* Register file check */ + uc : 1; /* Uarch check */ } pal_processor_state_info_t; typedef struct pal_cache_check_info_s { - u64 reserved1 : 16, - way : 5, /* Way in which the - * error occurred - */ - reserved2 : 1, - mc : 1, /* Machine check corrected */ - tv : 1, /* Target address - * structure is valid - */ - - wv : 1, /* Way field valid */ - op : 3, /* Type of cache + u64 op : 4, /* Type of cache * operation that * caused the machine * check. */ - + level : 2, /* Cache level */ + reserved1 : 2, dl : 1, /* Failure in data part * of cache line */ @@ -486,11 +478,34 @@ */ dc : 1, /* Failure in dcache */ ic : 1, /* Failure in icache */ - index : 24, /* Cache line index */ - mv : 1, /* mesi valid */ mesi : 3, /* Cache line state */ - level : 4; /* Cache level */ + mv : 1, /* mesi valid */ + way : 5, /* Way in which the + * error occurred + */ + wiv : 1, /* Way field valid */ + reserved2 : 10, + + index : 20, /* Cache line index */ + reserved3 : 2, + is : 1, /* instruction set (1 == ia32) */ + iv : 1, /* instruction set field valid */ + pl : 2, /* privilege level */ + pv : 1, /* privilege level field valid */ + mcc : 1, /* Machine check corrected */ + tv : 1, /* Target address + * structure is valid + */ + rq : 1, /* Requester identifier + * structure is valid + */ + rp : 1, /* Responder identifier + * structure is valid + */ + pi : 1; /* Precise instruction pointer + * structure is valid + */ } pal_cache_check_info_t; typedef struct pal_tlb_check_info_s { @@ -498,18 +513,38 @@ u64 tr_slot : 8, /* Slot# of TR where * error occurred */ - reserved2 : 8, + trv : 1, /* tr_slot field is valid */ + reserved1 : 1, + level : 2, /* TLB level where failure occurred */ + reserved2 : 4, dtr : 1, /* Fail in data TR */ itr : 1, /* Fail in inst TR */ dtc : 1, /* Fail in data TC */ itc : 1, /* Fail in inst. TC */ - mc : 1, /* Machine check corrected */ - reserved1 : 43; + op : 4, /* Cache operation */ + reserved3 : 30, + is : 1, /* instruction set (1 == ia32) */ + iv : 1, /* instruction set field valid */ + pl : 2, /* privilege level */ + pv : 1, /* privilege level field valid */ + mcc : 1, /* Machine check corrected */ + tv : 1, /* Target address + * structure is valid + */ + rq : 1, /* Requester identifier + * structure is valid + */ + rp : 1, /* Responder identifier + * structure is valid + */ + pi : 1; /* Precise instruction pointer + * structure is valid + */ } pal_tlb_check_info_t; typedef struct pal_bus_check_info_s { - u64 size : 5, /* Xaction size*/ + u64 size : 5, /* Xaction size */ ib : 1, /* Internal bus error */ eb : 1, /* External bus error */ cc : 1, /* Error occurred @@ -518,22 +553,99 @@ */ type : 8, /* Bus xaction type*/ sev : 5, /* Bus error severity*/ - tv : 1, /* Targ addr valid */ - rp : 1, /* Resp addr valid */ - rq : 1, /* Req addr valid */ + hier : 2, /* Bus hierarchy level */ + reserved1 : 1, bsi : 8, /* Bus error status * info */ - mc : 1, /* Machine check corrected */ - reserved1 : 31; + reserved2 : 22, + + is : 1, /* instruction set (1 == ia32) */ + iv : 1, /* instruction set field valid */ + pl : 2, /* privilege level */ + pv : 1, /* privilege level field valid */ + mcc : 1, /* Machine check corrected */ + tv : 1, /* Target address + * structure is valid + */ + rq : 1, /* Requester identifier + * structure is valid + */ + rp : 1, /* Responder identifier + * structure is valid + */ + pi : 1; /* Precise instruction pointer + * structure is valid + */ } pal_bus_check_info_t; +typedef struct pal_reg_file_check_info_s { + u64 id : 4, /* Register file identifier */ + op : 4, /* Type of register + * operation that + * caused the machine + * check. + */ + reg_num : 7, /* Register number */ + rnv : 1, /* reg_num valid */ + reserved2 : 38, + + is : 1, /* instruction set (1 == ia32) */ + iv : 1, /* instruction set field valid */ + pl : 2, /* privilege level */ + pv : 1, /* privilege level field valid */ + mcc : 1, /* Machine check corrected */ + reserved3 : 3, + pi : 1; /* Precise instruction pointer + * structure is valid + */ +} pal_reg_file_check_info_t; + +typedef struct pal_uarch_check_info_s { + u64 sid : 5, /* Structure identification */ + level : 3, /* Level of failure */ + array_id : 4, /* Array identification */ + op : 4, /* Type of + * operation that + * caused the machine + * check. + */ + way : 6, /* Way of structure */ + wv : 1, /* way valid */ + xv : 1, /* index valid */ + reserved1 : 8, + index : 8, /* Index or set of the uarch + * structure that failed. + */ + reserved2 : 24, + + is : 1, /* instruction set (1 == ia32) */ + iv : 1, /* instruction set field valid */ + pl : 2, /* privilege level */ + pv : 1, /* privilege level field valid */ + mcc : 1, /* Machine check corrected */ + tv : 1, /* Target address + * structure is valid + */ + rq : 1, /* Requester identifier + * structure is valid + */ + rp : 1, /* Responder identifier + * structure is valid + */ + pi : 1; /* Precise instruction pointer + * structure is valid + */ +} pal_uarch_check_info_t; + typedef union pal_mc_error_info_u { u64 pmei_data; pal_processor_state_info_t pme_processor; pal_cache_check_info_t pme_cache; pal_tlb_check_info_t pme_tlb; pal_bus_check_info_t pme_bus; + pal_reg_file_check_info_t pme_reg_file; + pal_uarch_check_info_t pme_uarch; } pal_mc_error_info_t; #define pmci_proc_unknown_check pme_processor.uc diff -u -rN linux-2.4.24/include/asm-ia64/param.h linux-2.4.24-ia64-040109/include/asm-ia64/param.h --- linux-2.4.24/include/asm-ia64/param.h 2001-04-05 13:51:47.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/param.h 2004-01-09 09:54:49.000000000 -0700 @@ -4,22 +4,10 @@ /* * Fundamental kernel parameters. * - * Copyright (C) 1998, 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2002-2003 Hewlett-Packard Co + * David Mosberger-Tang */ -#include - -#ifdef CONFIG_IA64_HP_SIM -/* - * Yeah, simulating stuff is slow, so let us catch some breath between - * timer interrupts... - */ -# define HZ 32 -#else -# define HZ 1024 -#endif - #define EXEC_PAGESIZE 65536 #ifndef NGROUPS @@ -33,7 +21,24 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ #ifdef __KERNEL__ +# include /* mustn't include outside of #ifdef __KERNEL__ */ +# ifdef CONFIG_IA64_HP_SIM + /* + * Yeah, simulating stuff is slow, so let us catch some breath between + * timer interrupts... + */ +# define HZ 32 +# else +# define HZ 1024 +# endif +# define USER_HZ HZ # define CLOCKS_PER_SEC HZ /* frequency at which times() counts */ +#else + /* + * Technically, this is wrong, but some old apps still refer to it. The proper way to + * get the HZ value is via sysconf(_SC_CLK_TCK). + */ +# define HZ 1024 #endif #endif /* _ASM_IA64_PARAM_H */ diff -u -rN linux-2.4.24/include/asm-ia64/processor.h linux-2.4.24-ia64-040109/include/asm-ia64/processor.h --- linux-2.4.24/include/asm-ia64/processor.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/processor.h 2004-01-09 09:54:49.000000000 -0700 @@ -172,6 +172,7 @@ __u32 ptce_count[2]; __u32 ptce_stride[2]; struct task_struct *ksoftirqd; /* kernel softirq daemon for this CPU */ + void *mmu_gathers; # ifdef CONFIG_PERFMON unsigned long pfm_syst_info; # endif diff -u -rN linux-2.4.24/include/asm-ia64/sal.h linux-2.4.24-ia64-040109/include/asm-ia64/sal.h --- linux-2.4.24/include/asm-ia64/sal.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/sal.h 2004-01-09 09:54:49.000000000 -0700 @@ -806,6 +806,8 @@ extern unsigned long sal_platform_features; +extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *); + #endif /* __ASSEMBLY__ */ -#endif /* _ASM_IA64_PAL_H */ +#endif /* _ASM_IA64_SAL_H */ diff -u -rN linux-2.4.24/include/asm-ia64/tlb.h linux-2.4.24-ia64-040109/include/asm-ia64/tlb.h --- linux-2.4.24/include/asm-ia64/tlb.h 2001-09-14 09:41:04.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ia64/tlb.h 2004-01-09 09:54:49.000000000 -0700 @@ -1 +1,3 @@ +#define local_mmu_gathers local_cpu_data->mmu_gathers + #include diff -u -rN linux-2.4.24/include/asm-ia64/uaccess.h linux-2.4.24-ia64-040109/include/asm-ia64/uaccess.h --- linux-2.4.24/include/asm-ia64/uaccess.h 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/uaccess.h 2004-01-09 09:54:49.000000000 -0700 @@ -8,7 +8,7 @@ * addresses. Thus, we need to be careful not to let the user to * trick us into accessing kernel memory that would normally be * inaccessible. This code is also fairly performance sensitive, - * so we want to spend as little time doing saftey checks as + * so we want to spend as little time doing safety checks as * possible. * * To make matters a bit more interesting, these macros sometimes also @@ -26,8 +26,8 @@ * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and * then resumes execution at the continuation point. * - * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co - * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang + * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co + * David Mosberger-Tang */ #include @@ -56,8 +56,10 @@ * address TASK_SIZE is never valid. We also need to make sure that the address doesn't * point inside the virtually mapped linear page table. */ -#define __access_ok(addr,size,segment) (((unsigned long) (addr)) <= (segment).seg \ - && ((segment).seg == KERNEL_DS.seg || rgn_offset((unsigned long) (addr)) < RGN_MAP_LIMIT)) +#define __access_ok(addr,size,segment) \ + likely(((unsigned long) (addr)) <= (segment).seg \ + && ((segment).seg == KERNEL_DS.seg \ + || REGION_OFFSET((unsigned long) (addr)) < RGN_MAP_LIMIT)) #define access_ok(type,addr,size) __access_ok((addr),(size),get_fs()) static inline int diff -u -rN linux-2.4.24/include/asm-ia64/xor.h linux-2.4.24-ia64-040109/include/asm-ia64/xor.h --- linux-2.4.24/include/asm-ia64/xor.h 2000-11-12 20:39:51.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ia64/xor.h 2004-01-09 09:54:49.000000000 -0700 @@ -13,6 +13,7 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include extern void xor_ia64_2(unsigned long, unsigned long *, unsigned long *); extern void xor_ia64_3(unsigned long, unsigned long *, unsigned long *, @@ -22,256 +23,6 @@ extern void xor_ia64_5(unsigned long, unsigned long *, unsigned long *, unsigned long *, unsigned long *, unsigned long *); -asm (" - .text - - // Assume L2 memory latency of 6 cycles. - - .proc xor_ia64_2 -xor_ia64_2: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 3, 0, 13, 16 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov ar.lc = in0 - mov pr.rot = 1 << 16 - ;; - } - .rotr s1[6+1], s2[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mfb -(p[6+1]) st8.nta [r8] = d[1], 8 - nop.f 0 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_2 - - .proc xor_ia64_3 -xor_ia64_3: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 4, 0, 20, 24 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - ;; - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], s3[6] - } - { .bbb - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_3 - - .proc xor_ia64_4 -xor_ia64_4: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 5, 0, 27, 32 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - } - { .mfb - mov r19 = in4 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[0]) ld8.nta s4[0] = [r19], 8 -(p[6]) xor r20 = s3[6], s4[6] - ;; - } - { .mib -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], r20 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_4 - - .proc xor_ia64_5 -xor_ia64_5: - .prologue - .fframe 0 - { .mii - .save ar.pfs, r31 - alloc r31 = ar.pfs, 6, 0, 34, 40 - .save ar.lc, r30 - mov r30 = ar.lc - .save pr, r29 - mov r29 = pr - ;; - } - .body - { .mii - mov r8 = in1 - mov ar.ec = 6 + 2 - shr in0 = in0, 3 - ;; - } - { .mmi - adds in0 = -1, in0 - mov r16 = in1 - mov r17 = in2 - ;; - } - { .mii - mov r18 = in3 - mov ar.lc = in0 - mov pr.rot = 1 << 16 - } - { .mib - mov r19 = in4 - mov r20 = in5 - ;; - } - .rotr s1[6+1], s2[6+1], s3[6+1], s4[6+1], s5[6+1], d[2] - .rotp p[6+2] -0: { .mmi -(p[0]) ld8.nta s1[0] = [r16], 8 -(p[0]) ld8.nta s2[0] = [r17], 8 -(p[6]) xor d[0] = s1[6], s2[6] - } - { .mmi -(p[0]) ld8.nta s3[0] = [r18], 8 -(p[0]) ld8.nta s4[0] = [r19], 8 -(p[6]) xor r21 = s3[6], s4[6] - ;; - } - { .mmi -(p[0]) ld8.nta s5[0] = [r20], 8 -(p[6+1]) st8.nta [r8] = d[1], 8 -(p[6]) xor d[0] = d[0], r21 - ;; - } - { .mfb -(p[6]) xor d[0] = d[0], s5[6] - nop.f 0 - br.ctop.dptk.few 0b - ;; - } - { .mii - mov ar.lc = r30 - mov pr = r29, -1 - } - { .bbb - br.ret.sptk.few rp - } - .endp xor_ia64_5 -"); - static struct xor_block_template xor_block_ia64 = { name: "ia64", do_2: xor_ia64_2, @@ -280,4 +31,11 @@ do_5: xor_ia64_5, }; -#define XOR_TRY_TEMPLATES xor_speed(&xor_block_ia64) +#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); \ + xor_speed(&xor_block_ia64); \ + } while(0) + diff -u -rN linux-2.4.24/include/asm-m68k/pgtable.h linux-2.4.24-ia64-040109/include/asm-m68k/pgtable.h --- linux-2.4.24/include/asm-m68k/pgtable.h 2003-08-25 05:44:43.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-m68k/pgtable.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-ppc/pgtable.h linux-2.4.24-ia64-040109/include/asm-ppc/pgtable.h --- linux-2.4.24/include/asm-ppc/pgtable.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/asm-ppc/pgtable.h 2004-01-09 09:54:49.000000000 -0700 @@ -574,6 +574,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)) diff -u -rN linux-2.4.24/include/asm-ppc64/pgtable.h linux-2.4.24-ia64-040109/include/asm-ppc64/pgtable.h --- linux-2.4.24/include/asm-ppc64/pgtable.h 2003-08-25 05:44:44.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-ppc64/pgtable.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/asm-x86_64/pgtable.h linux-2.4.24-ia64-040109/include/asm-x86_64/pgtable.h --- linux-2.4.24/include/asm-x86_64/pgtable.h 2003-08-25 05:44:44.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/asm-x86_64/pgtable.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/agp_backend.h linux-2.4.24-ia64-040109/include/linux/agp_backend.h --- linux-2.4.24/include/linux/agp_backend.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/agp_backend.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/fs.h linux-2.4.24-ia64-040109/include/linux/fs.h --- linux-2.4.24/include/linux/fs.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/fs.h 2004-01-09 09:54:49.000000000 -0700 @@ -246,7 +246,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 -rN linux-2.4.24/include/linux/highmem.h linux-2.4.24-ia64-040109/include/linux/highmem.h --- linux-2.4.24/include/linux/highmem.h 2003-08-25 05:44:44.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/linux/highmem.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/hugetlb.h linux-2.4.24-ia64-040109/include/linux/hugetlb.h --- linux-2.4.24/include/linux/hugetlb.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/hugetlb.h 2004-01-09 09:54:49.000000000 -0700 @@ -0,0 +1,99 @@ +#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); + +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 + +#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 -rN linux-2.4.24/include/linux/irq.h linux-2.4.24-ia64-040109/include/linux/irq.h --- linux-2.4.24/include/linux/irq.h 2002-08-02 18:39:45.000000000 -0600 +++ linux-2.4.24-ia64-040109/include/linux/irq.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/irq_cpustat.h linux-2.4.24-ia64-040109/include/linux/irq_cpustat.h --- linux-2.4.24/include/linux/irq_cpustat.h 2001-11-22 12:46:18.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/irq_cpustat.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/mm.h linux-2.4.24-ia64-040109/include/linux/mm.h --- linux-2.4.24/include/linux/mm.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/mm.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/mmzone.h linux-2.4.24-ia64-040109/include/linux/mmzone.h --- linux-2.4.24/include/linux/mmzone.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/mmzone.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/shm.h linux-2.4.24-ia64-040109/include/linux/shm.h --- linux-2.4.24/include/linux/shm.h 2001-11-22 12:46:18.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/shm.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/smp.h linux-2.4.24-ia64-040109/include/linux/smp.h --- linux-2.4.24/include/linux/smp.h 2001-11-22 12:46:19.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/smp.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/include/linux/sysctl.h linux-2.4.24-ia64-040109/include/linux/sysctl.h --- linux-2.4.24/include/linux/sysctl.h 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/include/linux/sysctl.h 2004-01-09 09:54:49.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 -rN linux-2.4.24/init/main.c linux-2.4.24-ia64-040109/init/main.c --- linux-2.4.24/init/main.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/init/main.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/ipc/shm.c linux-2.4.24-ia64-040109/ipc/shm.c --- linux-2.4.24/ipc/shm.c 2002-08-02 18:39:46.000000000 -0600 +++ linux-2.4.24-ia64-040109/ipc/shm.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/printk.c linux-2.4.24-ia64-040109/kernel/printk.c --- linux-2.4.24/kernel/printk.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/kernel/printk.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/signal.c linux-2.4.24-ia64-040109/kernel/signal.c --- linux-2.4.24/kernel/signal.c 2003-06-13 08:51:39.000000000 -0600 +++ linux-2.4.24-ia64-040109/kernel/signal.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/softirq.c linux-2.4.24-ia64-040109/kernel/softirq.c --- linux-2.4.24/kernel/softirq.c 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/kernel/softirq.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/sysctl.c linux-2.4.24-ia64-040109/kernel/sysctl.c --- linux-2.4.24/kernel/sysctl.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/kernel/sysctl.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/time.c linux-2.4.24-ia64-040109/kernel/time.c --- linux-2.4.24/kernel/time.c 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/kernel/time.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/kernel/timer.c linux-2.4.24-ia64-040109/kernel/timer.c --- linux-2.4.24/kernel/timer.c 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/kernel/timer.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/mm/bootmem.c linux-2.4.24-ia64-040109/mm/bootmem.c --- linux-2.4.24/mm/bootmem.c 2002-11-28 16:53:15.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/bootmem.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/mm/memory.c linux-2.4.24-ia64-040109/mm/memory.c --- linux-2.4.24/mm/memory.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/memory.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/mm/mmap.c linux-2.4.24-ia64-040109/mm/mmap.c --- linux-2.4.24/mm/mmap.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/mmap.c 2004-01-09 09:54:49.000000000 -0700 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -594,7 +595,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; @@ -644,10 +648,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; } @@ -941,6 +961,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; @@ -994,7 +1020,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. @@ -1154,7 +1183,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 -rN linux-2.4.24/mm/mprotect.c linux-2.4.24-ia64-040109/mm/mprotect.c --- linux-2.4.24/mm/mprotect.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/mprotect.c 2004-01-09 09:54:49.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 -rN linux-2.4.24/mm/mremap.c linux-2.4.24-ia64-040109/mm/mremap.c --- linux-2.4.24/mm/mremap.c 2004-01-05 06:53:56.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/mremap.c 2004-01-09 09:54:49.000000000 -0700 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -279,6 +280,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 -rN linux-2.4.24/mm/page_alloc.c linux-2.4.24-ia64-040109/mm/page_alloc.c --- linux-2.4.24/mm/page_alloc.c 2003-11-28 11:26:21.000000000 -0700 +++ linux-2.4.24-ia64-040109/mm/page_alloc.c 2004-01-09 09:54:49.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)) \ ) /* @@ -574,7 +574,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; @@ -606,13 +606,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)); @@ -624,33 +655,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 @@ -693,6 +723,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)) /* @@ -714,10 +769,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++) @@ -726,7 +779,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 @@ -739,7 +792,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; @@ -756,7 +809,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]; @@ -767,6 +820,7 @@ zone->nr_active_pages = zone->nr_inactive_pages = 0; + pgdat->node_size += realsize; if (!size) continue; @@ -827,16 +881,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++) { @@ -877,7 +925,6 @@ (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size); } } - build_zonelists(pgdat); } void __init free_area_init(unsigned long *zones_size)