diff -Nru a/Documentation/firmware_class/README b/Documentation/firmware_class/README --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/firmware_class/README Sun Jun 15 07:28:28 2003 @@ -0,0 +1,58 @@ + + request_firmware() hotplug interface: + ------------------------------------ + Copyright (C) 2003 Manuel Estrada Sainz + + Why: + --- + + Today, the most extended way to use firmware in the Linux kernel is linking + it statically in a header file. Which has political and technical issues: + + 1) Some firmware is not legal to redistribute. + 2) The firmware occupies memory permanently, even though it often is just + used once. + 3) Some people, like the Debian crowd, don't consider some firmware free + enough and remove entire drivers (e.g.: keyspan). + + about in-kernel persistence: + --------------------------- + Under some circumstances, as explained below, it would be interesting to keep + firmware images in non-swappable kernel memory or even in the kernel image + (probably within initramfs). + + Note that this functionality has not been implemented. + + - Why OPTIONAL in-kernel persistence may be a good idea sometimes: + + - If the device that needs the firmware is needed to access the + filesystem. When upon some error the device has to be reset and the + firmware reloaded, it won't be possible to get it from userspace. + e.g.: + - A diskless client with a network card that needs firmware. + - The filesystem is stored in a disk behind an scsi device + that needs firmware. + - Replacing buggy DSDT/SSDT ACPI tables on boot. + Note: this would require the persistent objects to be included + within the kernel image, probably within initramfs. + + And the same device can be needed to access the filesystem or not depending + on the setup, so I think that the choice on what firmware to make + persistent should be left to userspace. + + - Why register_firmware()+__init can be useful: + - For boot devices needing firmware. + - To make the transition easier: + The firmware can be declared __init and register_firmware() + called on module_init. Then the firmware is warranted to be + there even if "firmware hotplug userspace" is not there yet or + it doesn't yet provide the needed firmware. + Once the firmware is widely available in userspace, it can be + removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE). + + In either case, if firmware hotplug support is there, it can move the + firmware out of kernel memory into the real filesystem for later + usage. + + Note: If persistence is implemented on top of initramfs, + register_firmware() may not be appropriate. diff -Nru a/Documentation/firmware_class/firmware_sample_driver.c b/Documentation/firmware_class/firmware_sample_driver.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/firmware_class/firmware_sample_driver.c Sun Jun 15 04:48:03 2003 @@ -0,0 +1,126 @@ +/* + * firmware_sample_driver.c - + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Sample code on how to use request_firmware() from drivers. + * + * Note that register_firmware() is currently useless. + * + */ + +#include +#include +#include +#include + +#include "linux/firmware.h" + +#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE +#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE +char __init inkernel_firmware[] = "let's say that this is firmware\n"; +#endif + +static struct device ghost_device = { + .name = "Ghost Device", + .bus_id = "ghost0", +}; + + +static void sample_firmware_load(char *firmware, int size) +{ + u8 buf[size+1]; + memcpy(buf, firmware, size); + buf[size] = '\0'; + printk("firmware_sample_driver: firmware: %s\n", buf); +} + +static void sample_probe_default(void) +{ + /* uses the default method to get the firmware */ + const struct firmware *fw_entry; + printk("firmware_sample_driver: a ghost device got inserted :)\n"); + + if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0) + { + printk(KERN_ERR + "firmware_sample_driver: Firmware not available\n"); + return; + } + + sample_firmware_load(fw_entry->data, fw_entry->size); + + release_firmware(fw_entry); + + /* finish setting up the device */ +} +static void sample_probe_specific(void) +{ + /* Uses some specific hotplug support to get the firmware from + * userspace directly into the hardware, or via some sysfs file */ + + /* NOTE: This currently doesn't work */ + + printk("firmware_sample_driver: a ghost device got inserted :)\n"); + + if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0) + { + printk(KERN_ERR + "firmware_sample_driver: Firmware load failed\n"); + return; + } + + /* request_firmware blocks until userspace finished, so at + * this point the firmware should be already in the device */ + + /* finish setting up the device */ +} +static void sample_probe_async_cont(const struct firmware *fw, void *context) +{ + if(!fw){ + printk(KERN_ERR + "firmware_sample_driver: firmware load failed\n"); + return; + } + + printk("firmware_sample_driver: device pointer \"%s\"\n", + (char *)context); + sample_firmware_load(fw->data, fw->size); +} +static void sample_probe_async(void) +{ + /* Let's say that I can't sleep */ + int error; + error = request_firmware_nowait (THIS_MODULE, + "sample_driver_fw", &ghost_device, + "my device pointer", + sample_probe_async_cont); + if(error){ + printk(KERN_ERR + "firmware_sample_driver:" + " request_firmware_nowait failed\n"); + } +} + +static int sample_init(void) +{ +#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE + register_firmware("sample_driver_fw", inkernel_firmware, + sizeof(inkernel_firmware)); +#endif + device_initialize(&ghost_device); + /* since there is no real hardware insertion I just call the + * sample probe functions here */ + sample_probe_specific(); + sample_probe_default(); + sample_probe_async(); + return 0; +} +static void __exit sample_exit(void) +{ +} + +module_init (sample_init); +module_exit (sample_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/Documentation/firmware_class/firmware_sample_firmware_class.c b/Documentation/firmware_class/firmware_sample_firmware_class.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/firmware_class/firmware_sample_firmware_class.c Sun Jun 15 04:11:53 2003 @@ -0,0 +1,205 @@ +/* + * firmware_sample_firmware_class.c - + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * NOTE: This is just a probe of concept, if you think that your driver would + * be well served by this mechanism please contact me first. + * + * DON'T USE THIS CODE AS IS + * + */ + +#include +#include +#include +#include +#include + +#include "linux/firmware.h" + +MODULE_AUTHOR("Manuel Estrada Sainz "); +MODULE_DESCRIPTION("Hackish sample for using firmware class directly"); +MODULE_LICENSE("GPL"); + +static inline struct class_device *to_class_dev(struct kobject *obj) +{ + return container_of(obj,struct class_device,kobj); +} +static inline +struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) +{ + return container_of(_attr,struct class_device_attribute,attr); +} + +int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); +int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); + +struct firmware_priv { + char fw_id[FIRMWARE_NAME_MAX]; + s32 loading:2; + u32 abort:1; +}; + +extern struct class firmware_class; + +static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + return sprintf(buf, "%d\n", fw_priv->loading); +} +static ssize_t firmware_loading_store(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int prev_loading = fw_priv->loading; + + fw_priv->loading = simple_strtol(buf, NULL, 10); + + switch(fw_priv->loading){ + case -1: + /* abort load an panic */ + break; + case 1: + /* setup load */ + break; + case 0: + if(prev_loading==1){ + /* finish load and get the device back to working + * state */ + } + break; + } + + return count; +} +static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + +static ssize_t firmware_data_read(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + /* read from the devices firmware memory */ + + return count; +} +static ssize_t firmware_data_write(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + /* write to the devices firmware memory */ + + return count; +} +static struct bin_attribute firmware_attr_data = { + .attr = {.name = "data", .mode = 0644}, + .size = 0, + .read = firmware_data_read, + .write = firmware_data_write, +}; +static int fw_setup_class_device(struct class_device *class_dev, + const char *fw_name, + struct device *device) +{ + int retval = 0; + struct firmware_priv *fw_priv = kmalloc(sizeof(struct firmware_priv), + GFP_KERNEL); + + if(!fw_priv){ + retval = -ENOMEM; + goto out; + } + memset(fw_priv, 0, sizeof(*fw_priv)); + memset(class_dev, 0, sizeof(*class_dev)); + + strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0'; + + strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE); + class_dev->class_id[BUS_ID_SIZE-1] = '\0'; + class_dev->dev = device; + + class_dev->class = &firmware_class, + class_set_devdata(class_dev, fw_priv); + retval = class_device_register(class_dev); + if (retval){ + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + goto error_free_fw_priv; + } + + retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data); + if (retval){ + printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", + __FUNCTION__); + goto error_unreg_class_dev; + } + + retval = class_device_create_file(class_dev, + &class_device_attr_loading); + if (retval){ + printk(KERN_ERR "%s: class_device_create_file failed\n", + __FUNCTION__); + goto error_remove_data; + } + + goto out; + +error_remove_data: + sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); +error_unreg_class_dev: + class_device_unregister(class_dev); +error_free_fw_priv: + kfree(fw_priv); +out: + return retval; +} +static void fw_remove_class_device(struct class_device *class_dev) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + class_device_remove_file(class_dev, &class_device_attr_loading); + sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data); + class_device_unregister(class_dev); +} + +static struct class_device *class_dev; + +static struct device my_device = { + .name = "Sample Device", + .bus_id = "my_dev0", +}; + +static int __init firmware_sample_init(void) +{ + int error; + + device_initialize(&my_device); + class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); + if(!class_dev) + return -ENOMEM; + + error = fw_setup_class_device(class_dev, "my_firmware_image", + &my_device); + if(error){ + kfree(class_dev); + return error; + } + return 0; + +} +static void __exit firmware_sample_exit(void) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + fw_remove_class_device(class_dev); + kfree(fw_priv); + kfree(class_dev); +} +module_init(firmware_sample_init); +module_exit(firmware_sample_exit); + diff -Nru a/Documentation/firmware_class/hotplug-script b/Documentation/firmware_class/hotplug-script --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/firmware_class/hotplug-script Sun Jun 15 04:45:00 2003 @@ -0,0 +1,16 @@ +#!/bin/sh + +# Simple hotplug script sample: +# +# Both $DEVPATH and $FIRMWARE are already provided in the environment. + +HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ + +echo 1 > /sysfs/$DEVPATH/loading +cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data +echo 0 > /sysfs/$DEVPATH/loading + +# To cancel the load in case of error: +# +# echo -1 > /sysfs/$DEVPATH/loading +# diff -Nru a/Documentation/kobject.txt b/Documentation/kobject.txt --- a/Documentation/kobject.txt Tue Jun 3 16:15:33 2003 +++ b/Documentation/kobject.txt Tue Jun 17 15:59:07 2003 @@ -5,15 +5,8 @@ Updated: 3 June 2003 -Copyright (c) Patrick Mochel -Copyright (c) Open Source Development Labs -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.2 -or any later version published by the Free Software Foundation; -with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -A copy of the license is included in the section entitled "GNU -Free Documentation License". - +Copyright (c) 2003 Patrick Mochel +Copyright (c) 2003 Open Source Development Labs 0. Introduction diff -Nru a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt --- a/Documentation/usb/dma.txt Tue Dec 24 05:41:22 2002 +++ b/Documentation/usb/dma.txt Thu Jun 12 07:28:01 2003 @@ -15,10 +15,12 @@ manage dma mappings for existing dma-ready buffers (see below). - URBs have an additional "transfer_dma" field, as well as a transfer_flags - bit saying if it's valid. (Control requests also needed "setup_dma".) + bit saying if it's valid. (Control requests also have "setup_dma" and a + corresponding transfer_flags bit.) -- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do it - first and set URB_NO_DMA_MAP. HCDs don't manage dma mappings for urbs. +- "usbcore" will map those DMA addresses, if a DMA-aware driver didn't do + it first and set URB_NO_TRANSFER_DMA_MAP or URB_NO_SETUP_DMA_MAP. HCDs + don't manage dma mappings for URBs. - There's a new "generic DMA API", parts of which are usable by USB device drivers. Never use dma_set_mask() on any USB interface or device; that @@ -33,8 +35,9 @@ - When you're allocating a buffer for DMA purposes anyway, use the buffer primitives. Think of them as kmalloc and kfree that give you the right kind of addresses to store in urb->transfer_buffer and urb->transfer_dma, - while guaranteeing that hidden copies through DMA "bounce" buffers won't - slow things down. You'd also set URB_NO_DMA_MAP in urb->transfer_flags: + while guaranteeing that no hidden copies through DMA "bounce" buffers will + slow things down. You'd also set URB_NO_TRANSFER_DMA_MAP in + urb->transfer_flags: void *usb_buffer_alloc (struct usb_device *dev, size_t size, int mem_flags, dma_addr_t *dma); @@ -42,10 +45,18 @@ void usb_buffer_free (struct usb_device *dev, size_t size, void *addr, dma_addr_t dma); + For control transfers you can use the buffer primitives or not for each + of the transfer buffer and setup buffer independently. Set the flag bits + URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which + buffers you have prepared. For non-control transfers URB_NO_SETUP_DMA_MAP + is ignored. + The memory buffer returned is "dma-coherent"; sometimes you might need to force a consistent memory access ordering by using memory barriers. It's not using a streaming DMA mapping, so it's good for small transfers on - systems where the I/O would otherwise tie up an IOMMU mapping. + systems where the I/O would otherwise tie up an IOMMU mapping. (See + Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming" + DMA mappings.) Asking for 1/Nth of a page (as well as asking for N pages) is reasonably space-efficient. @@ -91,7 +102,8 @@ These calls all work with initialized urbs: urb->dev, urb->pipe, urb->transfer_buffer, and urb->transfer_buffer_length must all be - valid when these calls are used: + valid when these calls are used (urb->setup_packet must be valid too + if urb is a control request): struct urb *usb_buffer_map (struct urb *urb); @@ -99,6 +111,6 @@ void usb_buffer_unmap (struct urb *urb); - The calls manage urb->transfer_dma for you, and set URB_NO_DMA_MAP so that - usbcore won't map or unmap the buffer. - + The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP + so that usbcore won't map or unmap the buffer. The same goes for + urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests. diff -Nru a/Makefile b/Makefile --- a/Makefile Mon Jun 16 21:04:35 2003 +++ b/Makefile Mon Jun 23 04:37:07 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 72 -EXTRAVERSION = +EXTRAVERSION = -bk4 # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -Nru a/arch/alpha/Kconfig b/arch/alpha/Kconfig --- a/arch/alpha/Kconfig Mon Jun 16 13:04:32 2003 +++ b/arch/alpha/Kconfig Thu Jun 19 10:23:30 2003 @@ -647,107 +647,13 @@ This driver is also available as a module and will be called srm_env then. -config BINFMT_AOUT - tristate "Kernel support for a.out (ECOFF) binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config OSF4_COMPAT - bool "OSF/1 v4 readv/writev compatibility" - depends on BINFMT_AOUT - help - Say Y if you are using OSF/1 binaries (like Netscape and Acrobat) - with v4 shared libraries freely available from Compaq. If you're - going to use shared libraries from Tru64 version 5.0 or later, say N. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. - -config BINFMT_EM86 - tristate "Kernel support for Linux/Intel ELF binaries" - ---help--- - Say Y here if you want to be able to execute Linux/Intel ELF - binaries just like native Alpha binaries on your Alpha machine. For - this to work, you need to have the emulator /usr/bin/em86 in place. - - You can get the same functionality by saying N here and saying Y to - "Kernel support for MISC binaries". - - You may answer M to compile the emulation support as a module and - later load the module when you want to use a Linux/Intel binary. The - module will be called binfmt_em86. If unsure, say Y. +source "fs/Kconfig.binfmt" source "drivers/parport/Kconfig" endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c --- a/arch/alpha/kernel/alpha_ksyms.c Mon Mar 31 14:29:49 2003 +++ b/arch/alpha/kernel/alpha_ksyms.c Thu Jun 19 10:20:02 2003 @@ -156,7 +156,7 @@ EXPORT_SYMBOL(sys_write); EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(__kernel_execve); +EXPORT_SYMBOL(execve); EXPORT_SYMBOL(sys_setsid); EXPORT_SYMBOL(sys_wait4); diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S --- a/arch/alpha/kernel/entry.S Mon May 12 18:59:21 2003 +++ b/arch/alpha/kernel/entry.S Thu Jun 19 10:20:02 2003 @@ -606,7 +606,8 @@ .globl kernel_thread .ent kernel_thread kernel_thread: - ldgp $gp, 0($27) /* we can be called from a module */ + /* We can be called from a module. */ + ldgp $gp, 0($27) .prologue 1 subq $sp, SP_OFF+6*8, $sp br $1, 2f /* load start address */ @@ -654,26 +655,56 @@ .end kernel_thread /* - * __kernel_execve(path, argv, envp, regs) + * execve(path, argv, envp) */ .align 4 - .globl __kernel_execve - .ent __kernel_execve -__kernel_execve: - ldgp $gp, 0($27) /* we can be called from modules. */ - subq $sp, 16, $sp - .frame $sp, 16, $26, 0 + .globl execve + .ent execve +execve: + /* We can be called from a module. */ + ldgp $gp, 0($27) + lda $sp, -(32+SIZEOF_PT_REGS+8)($sp) + .frame $sp, 32+SIZEOF_PT_REGS+8, $26, 0 stq $26, 0($sp) - stq $19, 8($sp) + stq $16, 8($sp) + stq $17, 16($sp) + stq $18, 24($sp) .prologue 1 - jsr $26, do_execve - bne $0, 1f /* error! */ - ldq $sp, 8($sp) + + lda $16, 32($sp) + lda $17, 0 + lda $18, SIZEOF_PT_REGS + bsr $26, memset !samegp + + /* Avoid the HAE being gratuitously wrong, which would cause us + to do the whole turn off interrupts thing and restore it. */ + ldq $2, alpha_mv+HAE_CACHE + stq $2, 152+32($sp) + + ldq $16, 8($sp) + ldq $17, 16($sp) + ldq $18, 24($sp) + lda $19, 32($sp) + bsr $26, do_execve !samegp + + ldq $26, 0($sp) + bne $0, 1f /* error! */ + + /* Move the temporary pt_regs struct from its current location + to the top of the kernel stack frame. See copy_thread for + details for a normal process. */ + lda $16, 0x4000 - SIZEOF_PT_REGS($8) + lda $17, 32($sp) + lda $18, SIZEOF_PT_REGS + bsr $26, memmove !samegp + + /* Take that over as our new stack frame and visit userland! */ + lda $sp, 0x4000 - SIZEOF_PT_REGS($8) br $31, ret_from_sys_call -1: ldq $26, 0($sp) - addq $sp, 16, $sp + +1: lda $sp, 32+SIZEOF_PT_REGS+8($sp) ret -.end __kernel_execve +.end execve /* diff -Nru a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c --- a/arch/alpha/kernel/srmcons.c Wed Jun 11 12:33:05 2003 +++ b/arch/alpha/kernel/srmcons.c Mon Jun 16 09:13:17 2003 @@ -291,6 +291,7 @@ driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_SYSCONS; driver->init_termios = tty_std_termios; + tty_set_operations(driver, &srmcons_ops); err = tty_register_driver(driver); if (err) { put_tty_driver(driver); diff -Nru a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S --- a/arch/alpha/lib/memmove.S Sun Jun 8 15:29:43 2003 +++ b/arch/alpha/lib/memmove.S Thu Jun 19 10:17:25 2003 @@ -15,15 +15,23 @@ .globl bcopy .ent bcopy bcopy: + ldgp $29, 0($27) + .prologue 1 mov $16,$0 mov $17,$16 mov $0,$17 + br $31, memmove !samegp .end bcopy .align 4 .globl memmove .ent memmove memmove: + ldgp $29, 0($27) + unop + nop + .prologue 1 + addq $16,$18,$4 addq $17,$18,$5 cmpule $4,$17,$1 /* dest + n <= src */ @@ -32,7 +40,7 @@ bis $1,$2,$1 mov $16,$0 xor $16,$17,$2 - bne $1,memcpy + bne $1,memcpy !samegp and $2,7,$2 /* Test for src/dest co-alignment. */ and $16,7,$1 diff -Nru a/arch/alpha/oprofile/common.c b/arch/alpha/oprofile/common.c --- a/arch/alpha/oprofile/common.c Mon Apr 28 17:18:48 2003 +++ b/arch/alpha/oprofile/common.c Mon Jun 16 13:14:45 2003 @@ -188,7 +188,7 @@ } -void __exit +void oprofile_arch_exit(void) { } diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/arm/Kconfig Thu Jun 19 10:23:30 2003 @@ -483,6 +483,16 @@ depends on PCI && ARCH_SHARK default y +config ICST525 + bool + depends on ARCH_INTEGRATOR + default y + +config ARM_AMBA + bool + depends on ARCH_INTEGRATOR + default y + config ISA bool depends on FOOTBRIDGE_HOST || ARCH_SHARK || ARCH_CLPS7500 || ARCH_EBSA110 || ARCH_CDB89712 || ARCH_EDB7211 || ARCH_SA1100 @@ -582,7 +592,7 @@ config CPU_FREQ_INTEGRATOR tristate "CPUfreq driver for ARM Integrator CPUs" - depends on ARCH_INTEGRATOR && CPU_FREQ + depends on ARCH_INTEGRATOR && ICST525 && CPU_FREQ default y help This enables the CPUfreq driver for ARM Integrator CPUs. @@ -691,81 +701,9 @@ endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. +source "fs/Kconfig.binfmt" -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "drivers/base/Kconfig" config PM bool "Power Management support" diff -Nru a/arch/arm/common/Makefile b/arch/arm/common/Makefile --- a/arch/arm/common/Makefile Wed Jun 4 15:17:11 2003 +++ b/arch/arm/common/Makefile Wed Jun 18 15:23:20 2003 @@ -3,6 +3,8 @@ # obj-y += platform.o +obj-$(CONFIG_ARM_AMBA) += amba.o +obj-$(CONFIG_ICST525) += icst525.o obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff -Nru a/arch/arm/common/amba.c b/arch/arm/common/amba.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/common/amba.c Wed Jun 18 15:23:20 2003 @@ -0,0 +1,243 @@ +/* + * linux/arch/arm/common/amba.c + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + +#define to_amba_device(d) container_of(d, struct amba_device, dev) +#define to_amba_driver(d) container_of(d, struct amba_driver, drv) + +static struct amba_id * +amba_lookup(struct amba_id *table, struct amba_device *dev) +{ + int ret = 0; + + while (table->mask) { + ret = (dev->periphid & table->mask) == table->id; + if (ret) + break; + table++; + } + + return ret ? table : NULL; +} + +static int amba_match(struct device *dev, struct device_driver *drv) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(drv); + + return amba_lookup(pcdrv->id_table, pcdev) != NULL; +} + +/* + * Primecells are part of the Advanced Microcontroller Bus Architecture, + * so we call the bus "amba". + */ +struct bus_type amba_bustype = { + .name = "amba", + .match = amba_match, +}; + +static int __init amba_init(void) +{ + return bus_register(&amba_bustype); +} + +postcore_initcall(amba_init); + +/* + * These are the device model conversion veneers; they convert the + * device model structures to our more specific structures. + */ +static int amba_probe(struct device *dev) +{ + struct amba_device *pcdev = to_amba_device(dev); + struct amba_driver *pcdrv = to_amba_driver(dev->driver); + struct amba_id *id; + + id = amba_lookup(pcdrv->id_table, pcdev); + + return pcdrv->probe(pcdev, id); +} + +static int amba_remove(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->remove(to_amba_device(dev)); +} + +static void amba_shutdown(struct device *dev) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + drv->shutdown(to_amba_device(dev)); +} + +static int amba_suspend(struct device *dev, u32 state, u32 level) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->suspend(to_amba_device(dev), state, level); +} + +static int amba_resume(struct device *dev, u32 level) +{ + struct amba_driver *drv = to_amba_driver(dev->driver); + return drv->resume(to_amba_device(dev), level); +} + +/** + * amba_driver_register - register an AMBA device driver + * @drv: amba device driver structure + * + * Register an AMBA device driver with the Linux device model + * core. If devices pre-exist, the drivers probe function will + * be called. + */ +int amba_driver_register(struct amba_driver *drv) +{ + drv->drv.bus = &amba_bustype; + +#define SETFN(fn) if (drv->fn) drv->drv.fn = amba_##fn + SETFN(probe); + SETFN(remove); + SETFN(shutdown); + SETFN(suspend); + SETFN(resume); + + return driver_register(&drv->drv); +} + +/** + * amba_driver_unregister - remove an AMBA device driver + * @drv: AMBA device driver structure to remove + * + * Unregister an AMBA device driver from the Linux device + * model. The device model will call the drivers remove function + * for each device the device driver is currently handling. + */ +void amba_driver_unregister(struct amba_driver *drv) +{ + driver_unregister(&drv->drv); +} + + +static void amba_device_release(struct device *dev) +{ + struct amba_device *d = to_amba_device(dev); + + if (d->res.parent) + release_resource(&d->res); + kfree(d); +} + +static ssize_t show_id(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "%08x\n", dev->periphid); +} +static DEVICE_ATTR(id, S_IRUGO, show_id, NULL); + +static ssize_t show_irq(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "%u\n", dev->irq); +} +static DEVICE_ATTR(irq, S_IRUGO, show_irq, NULL); + +static ssize_t show_res(struct device *_dev, char *buf) +{ + struct amba_device *dev = to_amba_device(_dev); + return sprintf(buf, "\t%08lx\t%08lx\t%08lx\n", + dev->res.start, dev->res.end, dev->res.flags); +} +static DEVICE_ATTR(resource, S_IRUGO, show_res, NULL); + +/** + * amba_device_register - register an AMBA device + * @dev: AMBA device to register + * @parent: parent memory resource + * + * Setup the AMBA device, reading the cell ID if present. + * Claim the resource, and register the AMBA device with + * the Linux device manager. + */ +int amba_device_register(struct amba_device *dev, struct resource *parent) +{ + u32 pid, cid; + void *tmp; + int i, ret; + + dev->dev.release = amba_device_release; + dev->dev.bus = &amba_bustype; + dev->res.name = dev->dev.name; + + ret = request_resource(parent, &dev->res); + if (ret == 0) { + tmp = ioremap(dev->res.start, SZ_4K); + if (!tmp) { + ret = -ENOMEM; + goto out; + } + + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + 0xfe0 + 4 * i) & 255) << (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + 0xff0 + 4 * i) & 255) << (i * 8); + + iounmap(tmp); + + if (cid == 0xb105f00d) + dev->periphid = pid; + + if (dev->periphid) + snprintf(dev->dev.name, sizeof(dev->dev.name), + "AMBA PL%03X", + dev->periphid & 0xfff); + else + strlcpy(dev->dev.name, "AMBA unknown", + sizeof(dev->dev.name)); + + ret = device_register(&dev->dev); + if (ret == 0) { + device_create_file(&dev->dev, &dev_attr_id); + device_create_file(&dev->dev, &dev_attr_irq); + device_create_file(&dev->dev, &dev_attr_resource); + } else { + out: + release_resource(&dev->res); + } + } + return ret; +} + +/** + * amba_device_unregister - unregister an AMBA device + * @dev: AMBA device to remove + * + * Remove the specified AMBA device from the Linux device + * manager. All files associated with this object will be + * destroyed, and device drivers notified that the device has + * been removed. The AMBA device's resources including + * the amba_device structure will be freed once all + * references to it have been dropped. + */ +void amba_device_unregister(struct amba_device *dev) +{ + device_unregister(&dev->dev); +} + +EXPORT_SYMBOL(amba_driver_register); +EXPORT_SYMBOL(amba_driver_unregister); +EXPORT_SYMBOL(amba_device_register); +EXPORT_SYMBOL(amba_device_unregister); diff -Nru a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/common/icst525.c Wed Jun 18 14:59:40 2003 @@ -0,0 +1,160 @@ +/* + * linux/arch/arm/common/icst525.c + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST525 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + */ +#include +#include + +#include + +/* + * Divisors for each OD setting. + */ +static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; + +unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco) +{ + return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); +} + +EXPORT_SYMBOL(icst525_khz); + +/* + * Ascending divisor S values. + */ +static unsigned char idx2s[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; + +struct icst525_vco +icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq) +{ + struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f; + unsigned int i = 0, rd, best = (unsigned int)-1; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = freq * s2div[idx2s[i]]; + + /* + * f must be between 10MHz and + * 320MHz (5V) or 200MHz (3V) + */ + if (f > 10000 && f <= p->vco_max) + break; + } while (i < ARRAY_SIZE(idx2s)); + + if (i > ARRAY_SIZE(idx2s)) + return vco; + + vco.s = idx2s[i]; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long fref_div, f_pll; + unsigned int vd; + int f_diff; + + fref_div = (2 * p->ref) / rd; + + vd = (f + fref_div / 2) / fref_div; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = fref_div * vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst525_khz_to_vco); + +struct icst525_vco +icst525_ps_to_vco(const struct icst525_params *p, unsigned long period) +{ + struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f, ps; + unsigned int i = 0, rd, best = (unsigned int)-1; + + ps = 1000000000UL / p->vco_max; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = period / s2div[idx2s[i]]; + + /* + * f must be between 10MHz and + * 320MHz (5V) or 200MHz (3V) + */ + if (f >= ps && f < 100000) + break; + } while (i < ARRAY_SIZE(idx2s)); + + if (i > ARRAY_SIZE(idx2s)) + return vco; + + vco.s = idx2s[i]; + + ps = 500000000UL / p->ref; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long f_in_div, f_pll; + unsigned int vd; + int f_diff; + + f_in_div = ps * rd; + + vd = (f_in_div + f / 2) / f; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = (f_in_div + vd / 2) / vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst525_ps_to_vco); diff -Nru a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c --- a/arch/arm/mach-integrator/core.c Wed Jun 4 15:54:24 2003 +++ b/arch/arm/mach-integrator/core.c Wed Jun 18 15:44:25 2003 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -104,7 +106,7 @@ .mask = sc_mask_irq, .unmask = sc_unmask_irq, }; - + static void __init integrator_init_irq(void) { unsigned int i; @@ -125,6 +127,52 @@ } } } + +static struct amba_device kmi0_device = { + .dev = { + .bus_id = "mb:18", + }, + .res = { + .start = KMI0_BASE, + .end = KMI0_BASE + KMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = IRQ_KMIINT0, + .periphid = 0x00041050, +}; + +static struct amba_device kmi1_device = { + .dev = { + .bus_id = "mb:19", + }, + .res = { + .start = KMI1_BASE, + .end = KMI1_BASE + KMI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + .irq = IRQ_KMIINT1, + .periphid = 0x00041050, +}; + +static struct amba_device *amba_devs[] __initdata = { + &kmi0_device, + &kmi1_device, +}; + +static int __init register_devices(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { + struct amba_device *d = amba_devs[i]; + + amba_device_register(d, &iomem_resource); + } + + return 0; +} + +arch_initcall(register_devices); MACHINE_START(INTEGRATOR, "ARM-Integrator") MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c --- a/arch/arm/mach-integrator/cpu.c Sun Apr 27 09:04:43 2003 +++ b/arch/arm/mach-integrator/cpu.c Wed Jun 18 14:59:40 2003 @@ -23,6 +23,7 @@ #include #include +#include static struct cpufreq_driver integrator_driver; @@ -31,75 +32,40 @@ #define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) -struct vco { - unsigned char vdw; - unsigned char od; +static const struct icst525_params lclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 8, + .vd_max = 132, + .rd_min = 24, + .rd_max = 24, }; -/* - * Divisors for each OD setting. - */ -static unsigned char cc_divisor[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; - -static unsigned int vco_to_freq(struct vco vco, int factor) -{ - return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor; -} - -/* - * Divisor indexes in ascending divisor order - */ -static unsigned char s2od[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; - -static struct vco freq_to_vco(unsigned int freq_khz, int factor) -{ - struct vco vco = {0, 0}; - unsigned int i, f; - - freq_khz *= factor; - - for (i = 0; i < 8; i++) { - f = freq_khz * cc_divisor[s2od[i]]; - /* f must be between 10MHz and 320MHz */ - if (f > 10000 && f <= 320000) - break; - } - - vco.od = s2od[i]; - vco.vdw = f / 2000 - 8; - - return vco; -} - +static const struct icst525_params cclk_params = { + .ref = 24000, + .vco_max = 320000, + .vd_min = 12, + .vd_max = 160, + .rd_min = 24, + .rd_max = 24, +}; /* * Validate the speed policy. */ static int integrator_verify_policy(struct cpufreq_policy *policy) { - struct vco vco; + struct icst525_vco vco; cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); - vco = freq_to_vco(policy->max, 1); - - if (vco.vdw < 4) - vco.vdw = 4; - if (vco.vdw > 152) - vco.vdw = 152; - - policy->max = vco_to_freq(vco, 1); - - vco = freq_to_vco(policy->min, 1); - - if (vco.vdw < 4) - vco.vdw = 4; - if (vco.vdw > 152) - vco.vdw = 152; + vco = icst525_khz_to_vco(&cclk_params, policy->max); + policy->max = icst525_khz(&cclk_params, vco); - policy->min = vco_to_freq(vco, 1); + vco = icst525_khz_to_vco(&cclk_params, policy->min); + policy->min = icst525_khz(&cclk_params, vco); cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, @@ -115,7 +81,7 @@ { unsigned long cpus_allowed; int cpu = policy->cpu; - struct vco vco; + struct icst525_vco vco; struct cpufreq_freqs freqs; u_int cm_osc; @@ -133,19 +99,20 @@ /* get current setting */ cm_osc = __raw_readl(CM_OSC); - vco.od = (cm_osc >> 8) & 7; - vco.vdw = cm_osc & 255; - freqs.old = vco_to_freq(vco, 1); + vco.s = (cm_osc >> 8) & 7; + vco.v = cm_osc & 255; + vco.r = 22; + freqs.old = icst525_khz(&cclk_params, vco); - /* freq_to_vco rounds down -- so we need the next larger freq in - * case of CPUFREQ_RELATION_L. + /* icst525_khz_to_vco rounds down -- so we need the next + * larger freq in case of CPUFREQ_RELATION_L. */ if (relation == CPUFREQ_RELATION_L) target_freq += 1999; if (target_freq > policy->max) target_freq = policy->max; - vco = freq_to_vco(target_freq, 1); - freqs.new = vco_to_freq(vco, 1); + vco = icst525_khz_to_vco(&cclk_params, target_freq); + freqs.new = icst525_khz(&cclk_params, vco); freqs.cpu = policy->cpu; @@ -158,7 +125,7 @@ cm_osc = __raw_readl(CM_OSC); cm_osc &= 0xfffff800; - cm_osc |= vco.vdw | vco.od << 8; + cm_osc |= vco.v | vco.s << 8; __raw_writel(0xa05f, CM_LOCK); __raw_writel(cm_osc, CM_OSC); @@ -179,7 +146,7 @@ unsigned long cpus_allowed; unsigned int cpu = policy->cpu; u_int cm_osc, cm_stat, mem_freq_khz; - struct vco vco; + struct icst525_vco vco; cpus_allowed = current->cpus_allowed; @@ -189,23 +156,26 @@ /* detect memory etc. */ cm_stat = __raw_readl(CM_STAT); cm_osc = __raw_readl(CM_OSC); - vco.od = (cm_osc >> 20) & 7; - vco.vdw = (cm_osc >> 12) & 255; - mem_freq_khz = vco_to_freq(vco, 2); + vco.s = (cm_osc >> 20) & 7; + vco.v = (cm_osc >> 12) & 255; + vco.r = 22; + mem_freq_khz = icst525_khz(&lclk_params, vco) / 2; printk(KERN_INFO "CPU%d: Module id: %d\n", cpu, cm_stat & 255); printk(KERN_INFO "CPU%d: Memory clock = %d.%03d MHz\n", cpu, mem_freq_khz / 1000, mem_freq_khz % 1000); - vco.od = (cm_osc >> 8) & 7; - vco.vdw = cm_osc & 255; + vco.s = (cm_osc >> 8) & 7; + vco.v = cm_osc & 255; + vco.r = 22; /* set default policy and cpuinfo */ policy->policy = CPUFREQ_POLICY_PERFORMANCE; policy->cpuinfo.max_freq = 160000; policy->cpuinfo.min_freq = 12000; policy->cpuinfo.transition_latency = 1000; /* 1 ms, assumed */ - policy->cur = policy->min = policy->max = vco_to_freq(vco, 1); /* current freq */ + policy->cur = policy->min = policy->max = + icst525_khz(&cclk_params, vco); /* current freq */ set_cpus_allowed(current, cpus_allowed); diff -Nru a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c --- a/arch/arm/mach-sa1100/irq.c Wed Jun 11 08:52:06 2003 +++ b/arch/arm/mach-sa1100/irq.c Wed Jun 18 16:17:54 2003 @@ -211,14 +211,14 @@ .end = 0x9005ffff, }; -static struct { +static struct sa1100irq_state { unsigned int saved; unsigned int icmr; unsigned int iclr; unsigned int iccr; } sa1100irq_state; -static int sa1100irq_suspend(struct device *dev, u32 state, u32 level) +static int sa1100irq_suspend(struct sys_device *dev, u32 state) { struct sa1100irq_state *st = &sa1100irq_state; diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c --- a/arch/arm/mm/fault-armv.c Sun Apr 27 16:46:31 2003 +++ b/arch/arm/mm/fault-armv.c Wed Jun 18 16:23:06 2003 @@ -213,7 +213,7 @@ if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT) continue; - flush_cache_page(mpnt, off); + flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT)); } } diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c --- a/arch/arm/mm/mm-armv.c Sun Apr 27 09:49:42 2003 +++ b/arch/arm/mm/mm-armv.c Wed Jun 18 16:27:49 2003 @@ -309,9 +309,9 @@ const char *policy; /* - * ARMv5 can use ECC memory. + * ARMv5 and higher can use ECC memory. */ - if (cpu_arch == CPU_ARCH_ARMv5) { + if (cpu_arch >= CPU_ARCH_ARMv5) { mem_types[MT_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_MEMORY].prot_sect |= ecc_mask; } else { diff -Nru a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in --- a/arch/arm/vmlinux-armv.lds.in Wed Jun 11 17:40:04 2003 +++ b/arch/arm/vmlinux-armv.lds.in Wed Jun 18 16:33:31 2003 @@ -53,7 +53,9 @@ __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; - SECURITY_INIT + __security_initcall_start = .; + *(.security_initcall.init) + __security_initcall_end = .; . = ALIGN(32); __initramfs_start = .; usr/built-in.o(.init.ramfs) diff -Nru a/arch/arm26/Kconfig b/arch/arm26/Kconfig --- a/arch/arm26/Kconfig Wed Jun 4 04:15:45 2003 +++ b/arch/arm26/Kconfig Thu Jun 19 10:23:30 2003 @@ -297,6 +297,8 @@ endmenu +source "drivers/base/Kconfig" + source "drivers/parport/Kconfig" source "drivers/pnp/Kconfig" diff -Nru a/arch/cris/Kconfig b/arch/cris/Kconfig --- a/arch/cris/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/cris/Kconfig Thu Jun 19 10:23:30 2003 @@ -25,34 +25,7 @@ menu "General setup" -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. +source "fs/Kconfig.binfmt" config ETRAX_KGDB bool "Use kernel gdb debugger" @@ -541,6 +514,8 @@ Configure where power button is connected. endmenu + +source "drivers/base/Kconfig" # bring in Etrax built-in drivers source "arch/cris/drivers/Kconfig" diff -Nru a/arch/h8300/Kconfig b/arch/h8300/Kconfig --- a/arch/h8300/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/h8300/Kconfig Thu Jun 19 10:23:30 2003 @@ -141,12 +141,11 @@ config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. +source "fs/Kconfig.binfmt" endmenu + +source "drivers/base/Kconfig" source "drivers/block/Kconfig" diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Sat Jun 14 16:15:56 2003 +++ b/arch/i386/Kconfig Thu Jun 19 10:06:56 2003 @@ -1190,83 +1190,11 @@ endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile --- a/arch/i386/kernel/acpi/Makefile Thu Feb 13 09:51:14 2003 +++ b/arch/i386/kernel/acpi/Makefile Fri Jun 13 12:58:20 2003 @@ -1,3 +1,4 @@ +obj-$(CONFIG_ACPI_HT_ONLY) := acpitable.o obj-$(CONFIG_ACPI_BOOT) := boot.o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o diff -Nru a/arch/i386/kernel/acpi/acpitable.c b/arch/i386/kernel/acpi/acpitable.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/kernel/acpi/acpitable.c Fri Jun 13 12:58:20 2003 @@ -0,0 +1,553 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * $Id: acpitable.c,v 1.7 2001/11/04 12:21:18 fenrus Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpitable.h" + +static acpi_table_handler acpi_boot_ops[ACPI_TABLE_COUNT]; + +int acpi_lapic; + +static unsigned char __init +acpi_checksum(void *buffer, int length) +{ + int i; + unsigned char *bytebuffer; + unsigned char sum = 0; + + if (!buffer || length <= 0) + return 0; + + bytebuffer = (unsigned char *) buffer; + + for (i = 0; i < length; i++) + sum += *(bytebuffer++); + + return sum; +} + +static void __init +acpi_print_table_header(acpi_table_header * header) +{ + if (!header) + return; + + printk(KERN_INFO "ACPI table found: %.4s v%d [%.6s %.8s %d.%d]\n", + header->signature, header->revision, header->oem_id, + header->oem_table_id, header->oem_revision >> 16, + header->oem_revision & 0xffff); + + return; +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_scan_memory_for_rsdp + * + * PARAMETERS: address - Starting pointer for search + * length - Maximum length to search + * + * RETURN: Pointer to the RSDP if found and valid, otherwise NULL. + * + * DESCRIPTION: Search a block of memory for the RSDP signature + * + ******************************************************************************/ + +static void *__init +acpi_tb_scan_memory_for_rsdp(void *address, int length) +{ + u32 offset; + + if (length <= 0) + return NULL; + + /* Search from given start addr for the requested length */ + + offset = 0; + + while (offset < length) { + /* The signature must match and the checksum must be correct */ + if (strncmp(address, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0 && + acpi_checksum(address, RSDP_CHECKSUM_LENGTH) == 0) { + /* If so, we have found the RSDP */ + printk(KERN_INFO "ACPI: RSDP located at physical address %p\n", + address); + return address; + } + offset += RSDP_SCAN_STEP; + address += RSDP_SCAN_STEP; + } + + /* Searched entire block, no RSDP was found */ + printk(KERN_INFO "ACPI: Searched entire block, no RSDP was found.\n"); + return NULL; +} + +/******************************************************************************* + * + * FUNCTION: acpi_find_root_pointer + * + * PARAMETERS: none + * + * RETURN: physical address of the RSDP + * + * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor + * pointer structure. If it is found, set *RSDP to point to it. + * + * NOTE: The RSDP must be either in the first 1_k of the Extended + * BIOS Data Area or between E0000 and FFFFF (ACPI 1.0 section + * 5.2.2; assertion #421). + * + ******************************************************************************/ + +static struct acpi_table_rsdp * __init +acpi_find_root_pointer(void) +{ + struct acpi_table_rsdp * rsdp; + + /* + * Physical address is given + */ + /* + * Region 1) Search EBDA (low memory) paragraphs + */ + rsdp = acpi_tb_scan_memory_for_rsdp(__va(LO_RSDP_WINDOW_BASE), + LO_RSDP_WINDOW_SIZE); + + if (rsdp) + return rsdp; + + /* + * Region 2) Search upper memory: 16-byte boundaries in E0000h-F0000h + */ + rsdp = acpi_tb_scan_memory_for_rsdp(__va(HI_RSDP_WINDOW_BASE), + HI_RSDP_WINDOW_SIZE); + + + + if (rsdp) + return rsdp; + + printk(KERN_ERR "ACPI: System description tables not found\n"); + return NULL; +} + + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. + */ +static __init char * +__va_range(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size; + int idx; + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(FIX_IO_APIC_BASE_END, phys); + base = fix_to_virt(FIX_IO_APIC_BASE_END); + dprintk("__va_range(0x%lx, 0x%lx): idx=%d mapped at %lx\n", phys, size, + FIX_IO_APIC_BASE_END, base); + + /* + * Most cases can be covered by the below. + */ + idx = FIX_IO_APIC_BASE_END; + while (mapped_size < size) { + if (--idx < FIX_IO_APIC_BASE_0) + return 0; /* cannot handle this */ + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } + + return ((unsigned char *) base + offset); +} + +static int __init acpi_tables_init(void) +{ + int result = -ENODEV; + acpi_table_header *header = NULL; + struct acpi_table_rsdp *rsdp = NULL; + struct acpi_table_rsdt *rsdt = NULL; + struct acpi_table_rsdt saved_rsdt; + int tables = 0; + int type = 0; + int i = 0; + + + rsdp = (struct acpi_table_rsdp *) acpi_find_root_pointer(); + + if (!rsdp) + return -ENODEV; + + printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision, + rsdp->oem_id); + + if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) { + printk(KERN_WARNING "RSDP table signature incorrect\n"); + return -EINVAL; + } + + rsdt = (struct acpi_table_rsdt *) + __va_range(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt)); + + if (!rsdt) { + printk(KERN_WARNING "ACPI: Invalid root system description tables (RSDT)\n"); + return -ENODEV; + } + + header = & rsdt->header; + acpi_print_table_header(header); + + if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) { + printk(KERN_WARNING "ACPI: RSDT signature incorrect\n"); + return -ENODEV; + } + + /* + * The number of tables is computed by taking the + * size of all entries (header size minus total + * size of RSDT) divided by the size of each entry + * (4-byte table pointers). + */ + tables = (header->length - sizeof(acpi_table_header)) / 4; + + memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt)); + + if (saved_rsdt.header.length > sizeof(saved_rsdt)) { + printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n", saved_rsdt.header.length); + return -ENODEV; + } + + for (i = 0; i < tables; i++) { + /* Map in header, then map in full table length. */ + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], + sizeof(acpi_table_header)); + if (!header) + break; + header = (acpi_table_header *) + __va_range(saved_rsdt.entry[i], header->length); + if (!header) + break; + + acpi_print_table_header(header); + + if (acpi_checksum(header,header->length)) { + printk(KERN_WARNING "ACPI %s has invalid checksum\n", + acpi_table_signatures[i]); + continue; + } + + for (type = 0; type < ACPI_TABLE_COUNT; type++) + if (!strncmp((char *) &header->signature, + acpi_table_signatures[type],strlen(acpi_table_signatures[type]))) + break; + + if (type >= ACPI_TABLE_COUNT) { + printk(KERN_WARNING "ACPI: Unsupported table %.4s\n", + header->signature); + continue; + } + + + if (!acpi_boot_ops[type]) + continue; + + result = acpi_boot_ops[type] (header, + (unsigned long) saved_rsdt. + entry[i]); + } + + return result; +} + +static int total_cpus __initdata = 0; +int have_acpi_tables; + +extern void __init MP_processor_info(struct mpc_config_processor *); + +static void __init +acpi_parse_lapic(struct acpi_table_lapic *local_apic) +{ + struct mpc_config_processor proc_entry; + int ix = 0; + + if (!local_apic) + return; + + printk(KERN_INFO "LAPIC (acpi_id[0x%04x] id[0x%x] enabled[%d])\n", + local_apic->acpi_id, local_apic->id, local_apic->flags.enabled); + + printk(KERN_INFO "CPU %d (0x%02x00)", total_cpus, local_apic->id); + + if (local_apic->flags.enabled) { + printk(" enabled"); + ix = local_apic->id; + if (ix >= MAX_APICS) { + printk(KERN_WARNING + "Processor #%d INVALID - (Max ID: %d).\n", ix, + MAX_APICS); + return; + } + /* + * Fill in the info we want to save. Not concerned about + * the processor ID. Processor features aren't present in + * the table. + */ + proc_entry.mpc_type = MP_PROCESSOR; + proc_entry.mpc_apicid = local_apic->id; + proc_entry.mpc_cpuflag = CPU_ENABLED; + if (proc_entry.mpc_apicid == boot_cpu_physical_apicid) { + printk(" (BSP)"); + proc_entry.mpc_cpuflag |= CPU_BOOTPROCESSOR; + } + proc_entry.mpc_cpufeature = + (boot_cpu_data.x86 << 8) | + (boot_cpu_data.x86_model << 4) | + boot_cpu_data.x86_mask; + proc_entry.mpc_featureflag = boot_cpu_data.x86_capability[0]; + proc_entry.mpc_reserved[0] = 0; + proc_entry.mpc_reserved[1] = 0; + proc_entry.mpc_apicver = 0x10; /* integrated APIC */ + MP_processor_info(&proc_entry); + } else { + printk(" disabled"); + } + printk("\n"); + + total_cpus++; + return; +} + +static void __init +acpi_parse_ioapic(struct acpi_table_ioapic *ioapic) +{ + + if (!ioapic) + return; + + printk(KERN_INFO + "IOAPIC (id[0x%x] address[0x%x] global_irq_base[0x%x])\n", + ioapic->id, ioapic->address, ioapic->global_irq_base); + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_WARNING + "Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IO_APICS, nr_ioapics); +/* panic("Recompile kernel with bigger MAX_IO_APICS!\n"); */ + } +} + + +/* Interrupt source overrides inform the machine about exceptions + to the normal "PIC" mode interrupt routing */ + +static void __init +acpi_parse_int_src_ovr(struct acpi_table_int_src_ovr *intsrc) +{ + if (!intsrc) + return; + + printk(KERN_INFO + "INT_SRC_OVR (bus[%d] irq[0x%x] global_irq[0x%x] polarity[0x%x] trigger[0x%x])\n", + intsrc->bus, intsrc->bus_irq, intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); +} + +/* + * At this point, we look at the interrupt assignment entries in the MPS + * table. + */ + +static void __init acpi_parse_nmi_src(struct acpi_table_nmi_src *nmisrc) +{ + if (!nmisrc) + return; + + printk(KERN_INFO + "NMI_SRC (polarity[0x%x] trigger[0x%x] global_irq[0x%x])\n", + nmisrc->flags.polarity, nmisrc->flags.trigger, + nmisrc->global_irq); + +} +static void __init +acpi_parse_lapic_nmi(struct acpi_table_lapic_nmi *localnmi) +{ + if (!localnmi) + return; + + printk(KERN_INFO + "LAPIC_NMI (acpi_id[0x%04x] polarity[0x%x] trigger[0x%x] lint[0x%x])\n", + localnmi->acpi_id, localnmi->flags.polarity, + localnmi->flags.trigger, localnmi->lint); +} +static void __init +acpi_parse_lapic_addr_ovr(struct acpi_table_lapic_addr_ovr *lapic_addr_ovr) +{ + if (!lapic_addr_ovr) + return; + + printk(KERN_INFO "LAPIC_ADDR_OVR (address[0x%lx])\n", + (unsigned long) lapic_addr_ovr->address); + +} + +static void __init +acpi_parse_plat_int_src(struct acpi_table_plat_int_src *plintsrc) +{ + if (!plintsrc) + return; + + printk(KERN_INFO + "PLAT_INT_SRC (polarity[0x%x] trigger[0x%x] type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", + plintsrc->flags.polarity, plintsrc->flags.trigger, + plintsrc->type, plintsrc->id, plintsrc->eid, + plintsrc->iosapic_vector, plintsrc->global_irq); +} +static int __init +acpi_parse_madt(acpi_table_header * header, unsigned long phys) +{ + + struct acpi_table_madt *madt; + acpi_madt_entry_header *entry_header; + int table_size; + + madt = (struct acpi_table_madt *) __va_range(phys, header->length); + + if (!madt) + return -EINVAL; + + table_size = (int) (header->length - sizeof(*madt)); + entry_header = + (acpi_madt_entry_header *) ((void *) madt + sizeof(*madt)); + + while (entry_header && (table_size > 0)) { + switch (entry_header->type) { + case ACPI_MADT_LAPIC: + acpi_parse_lapic((struct acpi_table_lapic *) + entry_header); + break; + case ACPI_MADT_IOAPIC: + acpi_parse_ioapic((struct acpi_table_ioapic *) + entry_header); + break; + case ACPI_MADT_INT_SRC_OVR: + acpi_parse_int_src_ovr((struct acpi_table_int_src_ovr *) + entry_header); + break; + case ACPI_MADT_NMI_SRC: + acpi_parse_nmi_src((struct acpi_table_nmi_src *) + entry_header); + break; + case ACPI_MADT_LAPIC_NMI: + acpi_parse_lapic_nmi((struct acpi_table_lapic_nmi *) + entry_header); + break; + case ACPI_MADT_LAPIC_ADDR_OVR: + acpi_parse_lapic_addr_ovr((struct + acpi_table_lapic_addr_ovr *) + entry_header); + break; + case ACPI_MADT_PLAT_INT_SRC: + acpi_parse_plat_int_src((struct acpi_table_plat_int_src + *) entry_header); + break; + default: + printk(KERN_WARNING + "Unsupported MADT entry type 0x%x\n", + entry_header->type); + break; + } + table_size -= entry_header->length; + entry_header = + (acpi_madt_entry_header *) ((void *) entry_header + + entry_header->length); + } + + if (!total_cpus) { + printk("ACPI: No Processors found in the APCI table.\n"); + return -EINVAL; + } + + printk(KERN_INFO "%d CPUs total\n", total_cpus); + + if (madt->lapic_address) + mp_lapic_addr = madt->lapic_address; + else + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + + printk(KERN_INFO "Local APIC address %x\n", madt->lapic_address); + + return 0; +} + + +/* + * Configure the processor info using MADT in the ACPI tables. If we fail to + * configure that, then we use the MPS tables. + */ +void __init +acpi_boot_init(void) +{ + + memset(&acpi_boot_ops, 0, sizeof(acpi_boot_ops)); + acpi_boot_ops[ACPI_APIC] = acpi_parse_madt; + + /* + * Only do this when requested, either because of CPU/Bios type or from the command line + */ + + if (!acpi_tables_init()) + acpi_lapic = 1; +} + diff -Nru a/arch/i386/kernel/acpi/acpitable.h b/arch/i386/kernel/acpi/acpitable.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/kernel/acpi/acpitable.h Fri Jun 13 12:58:21 2003 @@ -0,0 +1,260 @@ +/* + * acpitable.c - IA32-specific ACPI boot-time initialization (Revision: 1) + * + * Copyright (C) 1999 Andrew Henroid + * Copyright (C) 2001 Richard Schaal + * Copyright (C) 2001 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Arjan van de Ven + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * $Id: acpitable.h,v 1.3 2001/11/03 22:41:34 fenrus Exp $ + */ + +/* + * The following codes are cut&pasted from drivers/acpi. Part of the code + * there can be not updated or delivered yet. + * To avoid conflicts when CONFIG_ACPI is defined, the following codes are + * modified so that they are self-contained in this file. + * -- jun + */ + +#ifndef _HEADER_ACPITABLE_H_ +#define _HEADER_ACPITABLE_H_ + +#define dprintk printk +typedef unsigned int ACPI_TBLPTR; + +typedef struct { /* ACPI common table header */ + char signature[4]; /* identifies type of table */ + u32 length; /* length of table, + in bytes, * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_table_header __attribute__ ((packed));; + +enum { + ACPI_APIC = 0, + ACPI_BOOT, + ACPI_DBGP, + ACPI_DSDT, + ACPI_ECDT, + ACPI_ETDT, + ACPI_FACP, + ACPI_FACS, + ACPI_OEMX, + ACPI_PSDT, + ACPI_SBST, + ACPI_SLIT, + ACPI_SPCR, + ACPI_SRAT, + ACPI_SSDT, + ACPI_SPMI, + ACPI_XSDT, + ACPI_TABLE_COUNT +}; + +static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { + "APIC", + "BOOT", + "DBGP", + "DSDT", + "ECDT", + "ETDT", + "FACP", + "FACS", + "OEM", + "PSDT", + "SBST", + "SLIT", + "SPCR", + "SRAT", + "SSDT", + "SPMI", + "XSDT" +}; + +struct acpi_table_madt { + acpi_table_header header; + u32 lapic_address; + struct { + u32 pcat_compat:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed));; + +enum { + ACPI_MADT_LAPIC = 0, + ACPI_MADT_IOAPIC, + ACPI_MADT_INT_SRC_OVR, + ACPI_MADT_NMI_SRC, + ACPI_MADT_LAPIC_NMI, + ACPI_MADT_LAPIC_ADDR_OVR, + ACPI_MADT_IOSAPIC, + ACPI_MADT_LSAPIC, + ACPI_MADT_PLAT_INT_SRC, + ACPI_MADT_ENTRY_COUNT +}; + +#define RSDP_SIG "RSD PTR " +#define RSDT_SIG "RSDT" + +#define ACPI_DEBUG_PRINT(pl) + +#define ACPI_MEMORY_MODE 0x01 +#define ACPI_LOGICAL_ADDRESSING 0x00 +#define ACPI_PHYSICAL_ADDRESSING 0x01 + +#define LO_RSDP_WINDOW_BASE 0 /* Physical Address */ +#define HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 +#define RSDP_CHECKSUM_LENGTH 20 + +typedef int (*acpi_table_handler) (acpi_table_header * header, unsigned long); + +struct acpi_table_rsdp { + char signature[8]; + u8 checksum; + char oem_id[6]; + u8 revision; + u32 rsdt_address; +} __attribute__ ((packed)); + +struct acpi_table_rsdt { + acpi_table_header header; + u32 entry[ACPI_TABLE_COUNT]; +} __attribute__ ((packed)); + +typedef struct { + u8 type; + u8 length; +} acpi_madt_entry_header __attribute__ ((packed)); + +typedef struct { + u16 polarity:2; + u16 trigger:2; + u16 reserved:12; +} acpi_madt_int_flags __attribute__ ((packed)); + +struct acpi_table_lapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + struct { + u32 enabled:1; + u32 reserved:31; + } flags __attribute__ ((packed)); +} __attribute__ ((packed)); + +struct acpi_table_ioapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 address; + u32 global_irq_base; +} __attribute__ ((packed)); + +struct acpi_table_int_src_ovr { + acpi_madt_entry_header header; + u8 bus; + u8 bus_irq; + u32 global_irq; + acpi_madt_int_flags flags; +} __attribute__ ((packed)); + +struct acpi_table_nmi_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u32 global_irq; +} __attribute__ ((packed)); + +struct acpi_table_lapic_nmi { + acpi_madt_entry_header header; + u8 acpi_id; + acpi_madt_int_flags flags; + u8 lint; +} __attribute__ ((packed)); + +struct acpi_table_lapic_addr_ovr { + acpi_madt_entry_header header; + u8 reserved[2]; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_iosapic { + acpi_madt_entry_header header; + u8 id; + u8 reserved; + u32 global_irq_base; + u64 address; +} __attribute__ ((packed)); + +struct acpi_table_lsapic { + acpi_madt_entry_header header; + u8 acpi_id; + u8 id; + u8 eid; + u8 reserved[3]; + struct { + u32 enabled:1; + u32 reserved:31; + } flags; +} __attribute__ ((packed)); + +struct acpi_table_plat_int_src { + acpi_madt_entry_header header; + acpi_madt_int_flags flags; + u8 type; + u8 id; + u8 eid; + u8 iosapic_vector; + u32 global_irq; + u32 reserved; +} __attribute__ ((packed)); + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc { + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + acpi_table_header *pointer; + void *base_pointer; + u8 *aml_pointer; + u64 physical_address; + u32 aml_length; + u32 length; + u32 count; + u16 table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} acpi_table_desc __attribute__ ((packed));; + +#endif diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c Tue Jun 10 12:04:01 2003 +++ b/arch/i386/kernel/nmi.c Sun Jun 15 11:00:08 2003 @@ -23,17 +23,27 @@ #include #include #include +#include #include #include #include #include +#include unsigned int nmi_watchdog = NMI_NONE; static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); +/* nmi_active: + * +1: the lapic NMI watchdog is active, but can be disabled + * 0: the lapic NMI watchdog has not been set up, and cannot + * be enabled + * -1: the lapic NMI watchdog is disabled, but can be enabled + */ +static int nmi_active; + #define K7_EVNTSEL_ENABLE (1 << 22) #define K7_EVNTSEL_INT (1 << 20) #define K7_EVNTSEL_OS (1 << 17) @@ -91,6 +101,7 @@ continue; if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck!\n", cpu); + nmi_active = 0; return -1; } } @@ -131,21 +142,15 @@ * We can enable the IO-APIC watchdog * unconditionally. */ - if (nmi == NMI_IO_APIC) + if (nmi == NMI_IO_APIC) { + nmi_active = 1; nmi_watchdog = nmi; + } return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); -/* nmi_active: - * +1: the lapic NMI watchdog is active, but can be disabled - * 0: the lapic NMI watchdog has not been set up, and cannot - * be enabled - * -1: the lapic NMI watchdog is disabled, but can be enabled - */ -static int nmi_active; - void disable_lapic_nmi_watchdog(void) { if (nmi_active <= 0) @@ -179,6 +184,27 @@ } } +void disable_timer_nmi_watchdog(void) +{ + if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0)) + return; + + disable_irq(0); + unset_nmi_callback(); + nmi_active = -1; + nmi_watchdog = NMI_NONE; +} + +void enable_timer_nmi_watchdog(void) +{ + if (nmi_active < 0) { + nmi_watchdog = NMI_IO_APIC; + touch_nmi_watchdog(); + nmi_active = 1; + enable_irq(0); + } +} + #ifdef CONFIG_PM static int nmi_pm_active; /* nmi_active before suspend */ @@ -429,3 +455,5 @@ EXPORT_SYMBOL(nmi_watchdog); EXPORT_SYMBOL(disable_lapic_nmi_watchdog); EXPORT_SYMBOL(enable_lapic_nmi_watchdog); +EXPORT_SYMBOL(disable_timer_nmi_watchdog); +EXPORT_SYMBOL(enable_timer_nmi_watchdog); diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Sat Jun 7 15:17:53 2003 +++ b/arch/i386/kernel/setup.c Thu Jun 19 17:51:40 2003 @@ -61,7 +61,12 @@ unsigned long mmu_cr4_features; EXPORT_SYMBOL_GPL(mmu_cr4_features); -int acpi_disabled __initdata = 0; +#ifdef CONFIG_ACPI_HT_ONLY +int acpi_disabled = 1; +#else +int acpi_disabled = 0; +#endif +EXPORT_SYMBOL(acpi_disabled); int MCA_bus; /* for MCA, but anyone else can use it if they want */ @@ -96,7 +101,6 @@ extern void generic_apic_probe(char *); extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern int blk_nohighio; unsigned long saved_videomode; @@ -515,6 +519,10 @@ if (c == ' ' && !memcmp(from, "acpi=off", 8)) acpi_disabled = 1; + /* "acpismp=force" turns on ACPI again */ + else if (!memcmp(from, "acpismp=force", 14)) + acpi_disabled = 0; + /* * highmem=size forces highmem to be exactly 'size' bytes. * This works even on boxes that have no highmem otherwise. @@ -994,15 +1002,6 @@ #endif #endif } - -static int __init highio_setup(char *str) -{ - printk("i386: disabling HIGHMEM block I/O\n"); - blk_nohighio = 1; - return 1; -} -__setup("nohighio", highio_setup); - #include "setup_arch_post.h" /* diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c Sat Jun 14 16:15:58 2003 +++ b/arch/i386/kernel/time.c Mon Jun 16 12:48:20 2003 @@ -281,19 +281,19 @@ return retval; } -static struct sysdev_class rtc_sysclass = { - set_kset_name("rtc"), +static struct sysdev_class pit_sysclass = { + set_kset_name("pit"), }; /* XXX this driverfs stuff should probably go elsewhere later -john */ static struct sys_device device_i8253 = { - .id = 0, - .cls = &rtc_sysclass, + .id = 0, + .cls = &pit_sysclass, }; static int time_init_device(void) { - int error = sysdev_class_register(&rtc_sysclass); + int error = sysdev_class_register(&pit_sysclass); if (!error) error = sys_device_register(&device_i8253); return error; diff -Nru a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile --- a/arch/i386/oprofile/Makefile Mon Apr 28 17:11:32 2003 +++ b/arch/i386/oprofile/Makefile Sun Jun 15 11:00:08 2003 @@ -9,3 +9,4 @@ oprofile-y := $(DRIVER_OBJS) init.o oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \ op_model_ppro.o op_model_p4.o +oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o diff -Nru a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c --- a/arch/i386/oprofile/init.c Mon May 12 21:23:26 2003 +++ b/arch/i386/oprofile/init.c Sun Jun 15 11:05:04 2003 @@ -16,15 +16,21 @@ */ extern int nmi_init(struct oprofile_operations ** ops); +extern int nmi_timer_init(struct oprofile_operations **ops); extern void nmi_exit(void); int __init oprofile_arch_init(struct oprofile_operations ** ops) { + int ret = -ENODEV; #ifdef CONFIG_X86_LOCAL_APIC - return nmi_init(ops); -#else - return -ENODEV; + ret = nmi_init(ops); #endif + +#ifdef CONFIG_X86_IO_APIC + if (ret < 0) + ret = nmi_timer_init(ops); +#endif + return ret; } diff -Nru a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c --- a/arch/i386/oprofile/nmi_int.c Tue Jun 10 12:06:36 2003 +++ b/arch/i386/oprofile/nmi_int.c Sat Jun 14 18:10:08 2003 @@ -182,8 +182,8 @@ static void nmi_shutdown(void) { nmi_enabled = 0; - unset_nmi_callback(); on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); + unset_nmi_callback(); enable_lapic_nmi_watchdog(); } diff -Nru a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/nmi_timer_int.c Sun Jun 15 11:04:34 2003 @@ -0,0 +1,57 @@ +/** + * @file nmi_timer_int.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + */ + +#include +#include +#include +#include +#include + + +#include +#include +#include + +static int nmi_timer_callback(struct pt_regs * regs, int cpu) +{ + unsigned long eip = instruction_pointer(regs); + + oprofile_add_sample(eip, !user_mode(regs), 0, cpu); + return 1; +} + +static int timer_start(void) +{ + disable_timer_nmi_watchdog(); + set_nmi_callback(nmi_timer_callback); + return 0; +} + + +static void timer_stop(void) +{ + enable_timer_nmi_watchdog(); + unset_nmi_callback(); + synchronize_kernel(); +} + + +static struct oprofile_operations nmi_timer_ops = { + .start = timer_start, + .stop = timer_stop, + .cpu_type = "timer" +}; + + +int __init nmi_timer_init(struct oprofile_operations ** ops) +{ + *ops = &nmi_timer_ops; + printk(KERN_INFO "oprofile: using NMI timer interrupt.\n"); + return 0; +} diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/ia64/Kconfig Thu Jun 19 10:23:30 2003 @@ -26,6 +26,10 @@ bool default y +config TIME_INTERPOLATION + bool + default y + choice prompt "IA-64 processor type" default ITANIUM @@ -63,7 +67,7 @@ HP-simulator For the HP simulator (). HP-zx1 For HP zx1-based systems. - SN1-simulator For the SGI SN1 simulator. + SGI-SN2 For SGI Altix systems DIG-compliant For DIG ("Developer's Interface Guide") compliant systems. @@ -82,9 +86,6 @@ for the zx1 I/O MMU and makes root bus bridges appear in PCI config space (required for zx1 agpgart support). -config IA64_SGI_SN1 - bool "SGI-SN1" - config IA64_SGI_SN2 bool "SGI-SN2" @@ -190,8 +191,8 @@ # align cache-sensitive data to 128 bytes config IA64_L1_CACHE_SHIFT int - default "7" if MCKINLEY || ITANIUM && IA64_SGI_SN1 - default "6" if ITANIUM && !IA64_SGI_SN1 + default "7" if MCKINLEY + default "6" if ITANIUM # align cache-sensitive data to 64 bytes config MCKINLEY_ASTEP_SPECIFIC @@ -210,7 +211,7 @@ config NUMA bool "Enable NUMA support" if IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y if IA64_SGI_SN1 || IA64_SGI_SN2 + default y if IA64_SGI_SN2 help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor @@ -234,7 +235,7 @@ config DISCONTIGMEM bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 || (IA64_GENERIC || IA64_DIG || IA64_HP_ZX1) && NUMA + depends on IA64_SGI_SN2 || (IA64_GENERIC || IA64_DIG || IA64_HP_ZX1) && NUMA default y help Say Y to support efficient handling of discontiguous physical memory, @@ -259,7 +260,7 @@ config IA64_MCA bool "Enable IA-64 Machine Check Abort" if IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y if IA64_SGI_SN1 || IA64_SGI_SN2 + default y if IA64_SGI_SN2 help Say Y here to enable machine check support for IA-64. If you're unsure, answer Y. @@ -288,17 +289,12 @@ config IOSAPIC bool - depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 - default y - -config IA64_SGI_SN - bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1 || IA64_SGI_SN2 default y config IA64_SGI_SN_DEBUG bool "Enable extra debugging code" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Turns on extra debugging code in the SGI SN (Scalable NUMA) platform for IA-64. Unless you are debugging problems on an SGI SN IA-64 box, @@ -306,14 +302,14 @@ config IA64_SGI_SN_SIM bool "Enable SGI Medusa Simulator Support" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help If you are compiling a kernel that will run under SGI's IA-64 simulator (Medusa) then say Y, otherwise say N. config IA64_SGI_AUTOTEST bool "Enable autotest (llsc). Option to run cache test instead of booting" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Build a kernel used for hardware validation. If you include the keyword "autotest" on the boot command line, the kernel does NOT boot. @@ -323,7 +319,7 @@ config SERIAL_SGI_L1_PROTOCOL bool "Enable protocol mode for the L1 console" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 help Uses protocol mode instead of raw mode for the level 1 console on the SGI SN (Scalable NUMA) platform for IA-64. If you are compiling for @@ -331,17 +327,9 @@ config PERCPU_IRQ bool - depends on IA64_SGI_SN1 || IA64_SGI_SN2 + depends on IA64_SGI_SN2 default y -config PCIBA - tristate "PCIBA support" - depends on IA64_SGI_SN1 || IA64_SGI_SN2 - help - IRIX PCIBA-inspired user mode PCI interface for the SGI SN (Scalable - NUMA) platform for IA-64. Unless you are compiling a kernel for an - SGI SN IA-64 box, say N. - # On IA-64, we always want an ELF /proc/kcore. config KCORE_ELF bool @@ -493,38 +481,7 @@ depends on SMP default "64" -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries. - - Information about ELF is contained in the ELF HOWTO available from - . - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. Once you have registered such a binary class with the - kernel, you can start one of those programs simply by typing in its - name at a shell prompt; Linux will automatically feed it to the - correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" if !IA64_HP_SIM @@ -577,6 +534,8 @@ endmenu +source "drivers/base/Kconfig" + if !IA64_HP_SIM source "drivers/mtd/Kconfig" @@ -729,20 +688,18 @@ source "drivers/usb/Kconfig" -source "lib/Kconfig" source "net/bluetooth/Kconfig" endif +source "lib/Kconfig" + source "arch/ia64/hp/sim/Kconfig" menu "Kernel hacking" -config FSYS - bool "Light-weight system-call support (via epc)" - choice prompt "Physical memory granularity" default IA64_GRANULE_64MB @@ -809,7 +766,7 @@ config IA64_EARLY_PRINTK bool "Early printk support" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && !IA64_GENERIC help Selecting this option uses the VGA screen or serial console for printk() output before the consoles are initialised. It is useful diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile --- a/arch/ia64/Makefile Tue May 6 10:56:53 2003 +++ b/arch/ia64/Makefile Sat Jun 14 00:38:59 2003 @@ -18,8 +18,8 @@ AFLAGS_KERNEL := -mconstant-gp EXTRA := -cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ - -falign-functions=32 +cflags-y := -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f12-f15,f32-f127 \ + -falign-functions=32 -frename-registers CFLAGS_KERNEL := -mconstant-gp GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') @@ -27,6 +27,10 @@ GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP)) +arch-cppflags := $(shell arch/ia64/scripts/toolchain-flags $(CC) $(LD) $(OBJDUMP)) +cflags-y += $(arch-cppflags) +AFLAGS += $(arch-cppflags) + ifeq ($(GAS_STATUS),buggy) $(error Sorry, you need a newer version of the assember, one that is built from \ a source-tree that post-dates 18-Dec-2002. You can find a pre-compiled \ @@ -35,19 +39,18 @@ ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifneq ($(GCC_VERSION),2) - cflags-$(CONFIG_ITANIUM) += -frename-registers +ifeq ($(GCC_VERSION),2) +$(error Sorry, your compiler is too old. GCC v2.96 is known to generate bad code.) endif ifeq ($(GCC_VERSION),3) ifeq ($(GCC_MINOR_VERSION),4) - cflags-$(CONFIG_ITANIUM) += -mtune=merced - cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley + cflags-$(CONFIG_ITANIUM) += -mtune=merced + cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley endif endif cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC) += -mb-step -cflags-$(CONFIG_IA64_SGI_SN) += -DBRINGUP CFLAGS += $(cflags-y) head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o @@ -58,7 +61,7 @@ core-$(CONFIG_IA64_DIG) += arch/ia64/dig/ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/ -core-$(CONFIG_IA64_SGI_SN) += arch/ia64/sn/ +core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/ drivers-$(CONFIG_PCI) += arch/ia64/pci/ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/ @@ -66,33 +69,37 @@ drivers-$(CONFIG_IA64_GENERIC) += arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/ boot := arch/ia64/boot -tools := arch/ia64/tools - -.PHONY: boot compressed include/asm-ia64/offsets.h -all: prepare vmlinux +.PHONY: boot compressed check compressed: vmlinux.gz vmlinux.gz: vmlinux - $(Q)$(MAKE) $(build)=$(boot) vmlinux.gz + $(Q)$(MAKE) $(build)=$(boot) $@ check: vmlinux - arch/ia64/scripts/unwcheck.sh vmlinux + arch/ia64/scripts/unwcheck.sh $< archclean: $(Q)$(MAKE) $(clean)=$(boot) - $(Q)$(MAKE) $(clean)=$(tools) -CLEAN_FILES += include/asm-ia64/offsets.h vmlinux.gz bootloader +CLEAN_FILES += include/asm-ia64/.offsets.h.stamp include/asm-ia64/offsets.h vmlinux.gz bootloader prepare: include/asm-ia64/offsets.h +include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s + $(call filechk,gen-asm-offsets) + +arch/ia64/kernel/asm-offsets.s: include/asm-ia64/.offsets.h.stamp + +include/asm-ia64/.offsets.h.stamp: + [ -s include/asm-ia64/offsets.h ] \ + || echo "#define IA64_TASK_SIZE 0" > include/asm-ia64/offsets.h + touch $@ + boot: lib/lib.a vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -include/asm-ia64/offsets.h: include/asm include/linux/version.h include/config/MARKER - $(Q)$(MAKE) $(build)=$(tools) $@ define archhelp echo ' compressed - Build compressed kernel image' diff -Nru a/arch/ia64/boot/bootloader.c b/arch/ia64/boot/bootloader.c --- a/arch/ia64/boot/bootloader.c Wed Dec 4 23:53:05 2002 +++ b/arch/ia64/boot/bootloader.c Tue Jun 17 23:50:16 2003 @@ -55,6 +55,9 @@ #include "../kernel/fw-emu.c" +/* This needs to be defined because lib/string.c:strlcat() calls it in case of error... */ +asm (".global printk; printk = 0"); + /* * Set a break point on this function so that symbols are available to set breakpoints in * the kernel being debugged. @@ -181,10 +184,10 @@ continue; req.len = elf_phdr->p_filesz; - req.addr = __pa(elf_phdr->p_vaddr); + req.addr = __pa(elf_phdr->p_paddr); ssc(fd, 1, (long) &req, elf_phdr->p_offset, SSC_READ); ssc((long) &stat, 0, 0, 0, SSC_WAIT_COMPLETION); - memset((char *)__pa(elf_phdr->p_vaddr) + elf_phdr->p_filesz, 0, + memset((char *)__pa(elf_phdr->p_paddr) + elf_phdr->p_filesz, 0, elf_phdr->p_memsz - elf_phdr->p_filesz); } ssc(fd, 0, 0, 0, SSC_CLOSE); diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Tue Jun 10 03:25:19 2003 +++ b/arch/ia64/hp/common/sba_iommu.c Tue Jun 17 23:50:16 2003 @@ -1682,6 +1682,10 @@ ioc_resource_init(ioc); ioc_sac_init(ioc); + if ((long) ~IOVP_MASK > (long) ia64_max_iommu_merge_mask) + ia64_max_iommu_merge_mask = ~IOVP_MASK; + MAX_DMA_ADDRESS = ~0UL; + printk(KERN_INFO PFX "%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n", ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF, @@ -1898,22 +1902,26 @@ struct ioc *ioc; acpi_status status; u64 hpa, length; - struct acpi_device_info dev_info; + struct acpi_buffer buffer; + struct acpi_device_info *dev_info; status = hp_acpi_csr_space(device->handle, &hpa, &length); if (ACPI_FAILURE(status)) return 1; - status = acpi_get_object_info(device->handle, &dev_info); + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_get_object_info(device->handle, &buffer); if (ACPI_FAILURE(status)) return 1; + dev_info = buffer.pointer; /* * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI * root bridges, and its CSR space includes the IOC function. */ - if (strncmp("HWP0001", dev_info.hardware_id, 7) == 0) + if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) hpa += ZX1_IOC_OFFSET; + ACPI_MEM_FREE(dev_info); ioc = ioc_init(hpa, device->handle); if (!ioc) @@ -1933,8 +1941,6 @@ static int __init sba_init(void) { - MAX_DMA_ADDRESS = ~0UL; - acpi_bus_register_driver(&acpi_sba_ioc_driver); #ifdef CONFIG_PCI diff -Nru a/arch/ia64/hp/sim/Kconfig b/arch/ia64/hp/sim/Kconfig --- a/arch/ia64/hp/sim/Kconfig Tue Oct 29 17:16:56 2002 +++ b/arch/ia64/hp/sim/Kconfig Tue Jun 3 04:24:27 2003 @@ -8,6 +8,10 @@ config HP_SIMSERIAL bool "Simulated serial driver support" +config HP_SIMSERIAL_CONSOLE + bool "Console for HP simulator" + depends on HP_SIMSERIAL + config HP_SIMSCSI bool "Simulated SCSI disk" depends on SCSI diff -Nru a/arch/ia64/hp/sim/Makefile b/arch/ia64/hp/sim/Makefile --- a/arch/ia64/hp/sim/Makefile Mon Dec 16 15:41:30 2002 +++ b/arch/ia64/hp/sim/Makefile Tue Jun 3 04:24:27 2003 @@ -7,9 +7,10 @@ # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) # -obj-y := hpsim_console.o hpsim_irq.o hpsim_setup.o +obj-y := hpsim_irq.o hpsim_setup.o obj-$(CONFIG_IA64_GENERIC) += hpsim_machvec.o obj-$(CONFIG_HP_SIMETH) += simeth.o obj-$(CONFIG_HP_SIMSERIAL) += simserial.o +obj-$(CONFIG_HP_SIMSERIAL_CONSOLE) += hpsim_console.o obj-$(CONFIG_HP_SIMSCSI) += simscsi.o diff -Nru a/arch/ia64/hp/sim/hpsim_setup.c b/arch/ia64/hp/sim/hpsim_setup.c --- a/arch/ia64/hp/sim/hpsim_setup.c Thu Aug 1 00:44:11 2002 +++ b/arch/ia64/hp/sim/hpsim_setup.c Tue Jun 3 04:24:27 2003 @@ -5,6 +5,7 @@ * David Mosberger-Tang * Copyright (C) 1999 Vijay Chander */ +#include #include #include #include @@ -24,8 +25,6 @@ #include "hpsim_ssc.h" -extern struct console hpsim_cons; - /* * Simulator system call. */ @@ -56,5 +55,11 @@ { ROOT_DEV = Root_SDA1; /* default to first SCSI drive */ - register_console(&hpsim_cons); +#ifdef CONFIG_HP_SIMSERIAL_CONSOLE + { + extern struct console hpsim_cons; + if (ia64_platform_is("hpsim")) + register_console(&hpsim_cons); + } +#endif } diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c Wed Jun 11 12:32:46 2003 +++ b/arch/ia64/hp/sim/simserial.c Mon Jun 16 17:15:40 2003 @@ -1031,6 +1031,9 @@ int i; struct serial_state *state; + if (!ia64_platform_is("hpsim")) + return -ENODEV; + hp_simserial_driver = alloc_tty_driver(1); if (!hp_simserial_driver) return -ENOMEM; diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c --- a/arch/ia64/ia32/binfmt_elf32.c Wed May 14 23:43:46 2003 +++ b/arch/ia64/ia32/binfmt_elf32.c Mon Jun 16 17:03:24 2003 @@ -16,7 +16,8 @@ #include #include -#include + +#include "ia32priv.h" #define CONFIG_BINFMT_ELF32 diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S --- a/arch/ia64/ia32/ia32_entry.S Tue May 6 13:42:08 2003 +++ b/arch/ia64/ia32/ia32_entry.S Tue Jun 17 23:50:16 2003 @@ -44,14 +44,8 @@ br.call.sptk.many rp=do_fork .ret0: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(ia32_clone) @@ -183,14 +177,8 @@ br.call.sptk.few rp=do_fork .ret5: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys32_fork) @@ -439,8 +427,8 @@ data8 sys_ni_syscall data8 sys_ni_syscall data8 compat_sys_futex /* 240 */ - data8 compat_sys_setaffinity - data8 compat_sys_getaffinity + data8 compat_sys_sched_setaffinity + data8 compat_sys_sched_getaffinity data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall /* 245 */ diff -Nru a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c --- a/arch/ia64/ia32/ia32_ioctl.c Sat May 10 02:28:45 2003 +++ b/arch/ia64/ia32/ia32_ioctl.c Wed Jun 18 00:37:28 2003 @@ -11,36 +11,107 @@ #include #include /* argh, msdos_fs.h isn't self-contained... */ #include /* argh, msdos_fs.h isn't self-contained... */ +#include -#include +#include "ia32priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include /* Ugly hack. */ -#undef __KERNEL__ +#undef __KERNEL__ #include -#define __KERNEL__ +#define __KERNEL__ #include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + #include <../drivers/char/drm/drm.h> #include <../drivers/char/drm/mga_drm.h> #include <../drivers/char/drm/i810_drm.h> - #define IOCTL_NR(a) ((a) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) #define DO_IOCTL(fd, cmd, arg) ({ \ @@ -57,6 +128,9 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); +#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct linux32_dirent[2]) +#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct linux32_dirent[2]) + static long put_dirent32 (struct dirent *d, struct linux32_dirent *d32) { @@ -67,6 +141,23 @@ || put_user(d->d_reclen, &d32->d_reclen) || copy_to_user(d32->d_name, d->d_name, namelen + 1)); } + +static int vfat_ioctl32(unsigned fd, unsigned cmd, void *ptr) +{ + int ret; + mm_segment_t oldfs = get_fs(); + struct dirent d[2]; + + set_fs(KERNEL_DS); + ret = sys_ioctl(fd,cmd,(unsigned long)&d); + set_fs(oldfs); + if (!ret) { + ret |= put_dirent32(&d[0], (struct linux32_dirent *)ptr); + ret |= put_dirent32(&d[1], ((struct linux32_dirent *)ptr) + 1); + } + return ret; +} + /* * The transform code for the SG_IO ioctl was brazenly lifted from * the Sparc64 port in the file `arch/sparc64/kernel/ioctl32.c'. @@ -294,3 +385,83 @@ } return err; } + +static __inline__ void *alloc_user_space(long len) +{ + struct pt_regs *regs = ((struct pt_regs *)((unsigned long) current + + IA64_STK_OFFSET)) - 1; + return (void *)regs->r12 - len; +} + +struct ifmap32 { + u32 mem_start; + u32 mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + compat_caddr_t ifru_data; + } ifr_ifru; +}; + +int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq *u_ifreq64; + struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg; + char tmp_buf[IFNAMSIZ]; + void *data64; + u32 data32; + + if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), + IFNAMSIZ)) + return -EFAULT; + if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + return -EFAULT; + data64 = (void *) P(data32); + + u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64)); + + /* Don't check these user accesses, just let that get trapped + * in the ioctl handler instead. + */ + copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); + __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); + + return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); +} + +typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *); + +#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl) +#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl32_handler_t)(handler), NULL }, +#define IOCTL_TABLE_START \ + struct ioctl_trans ioctl_start[] = { +#define IOCTL_TABLE_END \ + }; struct ioctl_trans ioctl_end[0]; + +IOCTL_TABLE_START +#include +HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) +HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) +HANDLE_IOCTL(SG_IO,sg_ioctl_trans) +IOCTL_TABLE_END diff -Nru a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c --- a/arch/ia64/ia32/ia32_ldt.c Mon Feb 4 23:55:06 2002 +++ b/arch/ia64/ia32/ia32_ldt.c Thu Jun 12 00:29:37 2003 @@ -14,7 +14,8 @@ #include #include -#include + +#include "ia32priv.h" #define P(p) ((void *) (unsigned long) (p)) diff -Nru a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c --- a/arch/ia64/ia32/ia32_signal.c Wed Apr 9 11:51:33 2003 +++ b/arch/ia64/ia32/ia32_signal.c Thu Jun 12 00:29:37 2003 @@ -28,7 +28,8 @@ #include #include #include -#include + +#include "ia32priv.h" #include "../kernel/sigframe.h" @@ -179,8 +180,10 @@ * datasel ar.fdr(32:47) * * _st[(0+TOS)%8] f8 - * _st[(1+TOS)%8] f9 (f8, f9 from ptregs) - * : : : (f10..f15 from live reg) + * _st[(1+TOS)%8] f9 + * _st[(2+TOS)%8] f10 + * _st[(3+TOS)%8] f11 (f8..f11 from ptregs) + * : : : (f12..f15 from live reg) * : : : * _st[(7+TOS)%8] f15 TOS=sw.top(bits11:13) * @@ -262,8 +265,8 @@ __put_user( 0, &save->magic); //#define X86_FXSR_MAGIC 0x0000 /* - * save f8 and f9 from pt_regs - * save f10..f15 from live register set + * save f8..f11 from pt_regs + * save f12..f15 from live register set */ /* * Find the location where f8 has to go in fp reg stack. This depends on @@ -278,11 +281,11 @@ copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); ia64f2ia32f(fpregp, &ptp->f9); copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); - - __stfe(fpregp, 10); + ia64f2ia32f(fpregp, &ptp->f10); copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); - __stfe(fpregp, 11); + ia64f2ia32f(fpregp, &ptp->f11); copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); + __stfe(fpregp, 12); copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32)); __stfe(fpregp, 13); @@ -394,8 +397,8 @@ asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr)); /* - * restore f8, f9 onto pt_regs - * restore f10..f15 onto live registers + * restore f8..f11 onto pt_regs + * restore f12..f15 onto live registers */ /* * Find the location where f8 has to go in fp reg stack. This depends on @@ -411,11 +414,11 @@ ia32f2ia64f(&ptp->f8, fpregp); copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); ia32f2ia64f(&ptp->f9, fpregp); - copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); - __ldfe(10, fpregp); + ia32f2ia64f(&ptp->f10, fpregp); copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); - __ldfe(11, fpregp); + ia32f2ia64f(&ptp->f11, fpregp); + copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); __ldfe(12, fpregp); copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32)); @@ -738,11 +741,11 @@ #define COPY(ia64x, ia32x) err |= __get_user(regs->ia64x, &sc->ia32x) -#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) tmp << 48) -#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) tmp << 32) +#define copyseg_gs(tmp) (regs->r16 |= (unsigned long) (tmp) << 48) +#define copyseg_fs(tmp) (regs->r16 |= (unsigned long) (tmp) << 32) #define copyseg_cs(tmp) (regs->r17 |= tmp) -#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) tmp << 16) -#define copyseg_es(tmp) (regs->r16 |= (unsigned long) tmp << 16) +#define copyseg_ss(tmp) (regs->r17 |= (unsigned long) (tmp) << 16) +#define copyseg_es(tmp) (regs->r16 |= (unsigned long) (tmp) << 16) #define copyseg_ds(tmp) (regs->r16 |= tmp) #define COPY_SEG(seg) \ diff -Nru a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c --- a/arch/ia64/ia32/ia32_support.c Thu Jan 30 06:14:13 2003 +++ b/arch/ia64/ia32/ia32_support.c Thu Jun 12 00:29:37 2003 @@ -22,7 +22,8 @@ #include #include #include -#include + +#include "ia32priv.h" extern void die_if_kernel (char *str, struct pt_regs *regs, long err); @@ -60,30 +61,26 @@ regs->r27 = load_desc(regs->r16 >> 0); /* DSD */ regs->r28 = load_desc(regs->r16 >> 32); /* FSD */ regs->r29 = load_desc(regs->r16 >> 48); /* GSD */ - task->thread.csd = load_desc(regs->r17 >> 0); /* CSD */ - task->thread.ssd = load_desc(regs->r17 >> 16); /* SSD */ + regs->ar_csd = load_desc(regs->r17 >> 0); /* CSD */ + regs->ar_ssd = load_desc(regs->r17 >> 16); /* SSD */ } void ia32_save_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; + unsigned long eflag, fsr, fcr, fir, fdr; asm ("mov %0=ar.eflag;" "mov %1=ar.fsr;" "mov %2=ar.fcr;" "mov %3=ar.fir;" "mov %4=ar.fdr;" - "mov %5=ar.csd;" - "mov %6=ar.ssd;" - : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd)); + : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr)); t->thread.eflag = eflag; t->thread.fsr = fsr; t->thread.fcr = fcr; t->thread.fir = fir; t->thread.fdr = fdr; - t->thread.csd = csd; - t->thread.ssd = ssd; ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob); ia64_set_kr(IA64_KR_TSSD, t->thread.old_k1); } @@ -91,7 +88,7 @@ void ia32_load_state (struct task_struct *t) { - unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd, tssd; + unsigned long eflag, fsr, fcr, fir, fdr, tssd; struct pt_regs *regs = ia64_task_regs(t); int nr = get_cpu(); /* LDT and TSS depend on CPU number: */ @@ -100,8 +97,6 @@ fcr = t->thread.fcr; fir = t->thread.fir; fdr = t->thread.fdr; - csd = t->thread.csd; - ssd = t->thread.ssd; tssd = load_desc(_TSS(nr)); /* TSSD */ asm volatile ("mov ar.eflag=%0;" @@ -109,9 +104,7 @@ "mov ar.fcr=%2;" "mov ar.fir=%3;" "mov ar.fdr=%4;" - "mov ar.csd=%5;" - "mov ar.ssd=%6;" - :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); + :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr)); current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); current->thread.old_k1 = ia64_get_kr(IA64_KR_TSSD); ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); @@ -179,6 +172,13 @@ siginfo.si_imm = 0; siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); +} + +void +ia32_cpu_init (void) +{ + /* initialize global ia32 state - CR0 and CR4 */ + asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); } static int __init diff -Nru a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c --- a/arch/ia64/ia32/ia32_traps.c Tue Apr 22 19:45:53 2003 +++ b/arch/ia64/ia32/ia32_traps.c Thu Jun 12 00:29:37 2003 @@ -12,7 +12,8 @@ #include #include -#include +#include "ia32priv.h" + #include int diff -Nru a/arch/ia64/ia32/ia32priv.h b/arch/ia64/ia32/ia32priv.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/ia32/ia32priv.h Thu Jun 12 00:29:38 2003 @@ -0,0 +1,477 @@ +#ifndef _ASM_IA64_IA32_H +#define _ASM_IA64_IA32_H + +#include + +#include + +#ifdef CONFIG_IA32_SUPPORT + +#include +#include + +/* + * 32 bit structures for IA32 support. + */ + +#define IA32_PAGE_SHIFT 12 /* 4KB pages */ +#define IA32_PAGE_SIZE (1UL << IA32_PAGE_SHIFT) +#define IA32_PAGE_MASK (~(IA32_PAGE_SIZE - 1)) +#define IA32_PAGE_ALIGN(addr) (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK) +#define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ + +/* sigcontext.h */ +/* + * As documented in the iBCS2 standard.. + * + * The first part of "struct _fpstate" is just the + * normal i387 hardware setup, the extra "status" + * word is used to save the coprocessor status word + * before entering the handler. + */ +struct _fpreg_ia32 { + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _fpxreg_ia32 { + unsigned short significand[4]; + unsigned short exponent; + unsigned short padding[3]; +}; + +struct _xmmreg_ia32 { + unsigned int element[4]; +}; + + +struct _fpstate_ia32 { + unsigned int cw, + sw, + tag, + ipoff, + cssel, + dataoff, + datasel; + struct _fpreg_ia32 _st[8]; + unsigned short status; + unsigned short magic; /* 0xffff = regular FPU data only */ + + /* FXSR FPU environment */ + unsigned int _fxsr_env[6]; /* FXSR FPU env is ignored */ + unsigned int mxcsr; + unsigned int reserved; + struct _fpxreg_ia32 _fxsr_st[8]; /* FXSR FPU reg data is ignored */ + struct _xmmreg_ia32 _xmm[8]; + unsigned int padding[56]; +}; + +struct sigcontext_ia32 { + unsigned short gs, __gsh; + unsigned short fs, __fsh; + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int esp; + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned int trapno; + unsigned int err; + unsigned int eip; + unsigned short cs, __csh; + unsigned int eflags; + unsigned int esp_at_signal; + unsigned short ss, __ssh; + unsigned int fpstate; /* really (struct _fpstate_ia32 *) */ + unsigned int oldmask; + unsigned int cr2; +}; + +/* user.h */ +/* + * IA32 (Pentium III/4) FXSR, SSE support + * + * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for + * interacting with the FXSR-format floating point environment. Floating + * point data can be accessed in the regular format in the usual manner, + * and both the standard and SIMD floating point data can be accessed via + * the new ptrace requests. In either case, changes to the FPU environment + * will be reflected in the task's state as expected. + */ +struct ia32_user_i387_struct { + int cwd; + int swd; + int twd; + int fip; + int fcs; + int foo; + int fos; + /* 8*10 bytes for each FP-reg = 80 bytes */ + struct _fpreg_ia32 st_space[8]; +}; + +struct ia32_user_fxsr_struct { + unsigned short cwd; + unsigned short swd; + unsigned short twd; + unsigned short fop; + int fip; + int fcs; + int foo; + int fos; + int mxcsr; + int reserved; + int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ + int xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ + int padding[56]; +}; + +/* signal.h */ +#define IA32_SET_SA_HANDLER(ka,handler,restorer) \ + ((ka)->sa.sa_handler = (__sighandler_t) \ + (((unsigned long)(restorer) << 32) \ + | ((handler) & 0xffffffff))) +#define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) +#define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) + +struct sigaction32 { + unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ + unsigned int sa_flags; + unsigned int sa_restorer; /* Another 32 bit pointer */ + compat_sigset_t sa_mask; /* A 32 bit mask */ +}; + +struct old_sigaction32 { + unsigned int sa_handler; /* Really a pointer, but need to deal + with 32 bits */ + compat_old_sigset_t sa_mask; /* A 32 bit mask */ + unsigned int sa_flags; + unsigned int sa_restorer; /* Another 32 bit pointer */ +}; + +typedef struct sigaltstack_ia32 { + unsigned int ss_sp; + int ss_flags; + unsigned int ss_size; +} stack_ia32_t; + +struct ucontext_ia32 { + unsigned int uc_flags; + unsigned int uc_link; + stack_ia32_t uc_stack; + struct sigcontext_ia32 uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +struct stat64 { + unsigned short st_dev; + unsigned char __pad0[10]; + unsigned int __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned short st_rdev; + unsigned char __pad3[10]; + unsigned int st_size_lo; + unsigned int st_size_hi; + unsigned int st_blksize; + unsigned int st_blocks; /* Number 512-byte blocks allocated. */ + unsigned int __pad4; /* future possible st_blocks high bits */ + unsigned int st_atime; + unsigned int st_atime_nsec; + unsigned int st_mtime; + unsigned int st_mtime_nsec; + unsigned int st_ctime; + unsigned int st_ctime_nsec; + unsigned int st_ino_lo; + unsigned int st_ino_hi; +}; + +typedef union sigval32 { + int sival_int; + unsigned int sival_ptr; +} sigval_t32; + +typedef struct siginfo32 { + int si_signo; + int si_errno; + int si_code; + + union { + int _pad[((128/sizeof(int)) - 3)]; + + /* kill() */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + } _kill; + + /* POSIX.1b timers */ + struct { + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + char _pad[sizeof(unsigned int) - sizeof(int)]; + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ + } _timer; + + /* POSIX.1b signals */ + struct { + unsigned int _pid; /* sender's pid */ + unsigned int _uid; /* sender's uid */ + sigval_t32 _sigval; + } _rt; + + /* SIGCHLD */ + struct { + unsigned int _pid; /* which child */ + unsigned int _uid; /* sender's uid */ + int _status; /* exit code */ + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + unsigned int _addr; /* faulting insn/memory ref. */ + } _sigfault; + + /* SIGPOLL */ + struct { + int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + int _fd; + } _sigpoll; + } _sifields; +} siginfo_t32; + +struct linux32_dirent { + u32 d_ino; + u32 d_off; + u16 d_reclen; + char d_name[256]; +}; + +struct old_linux32_dirent { + u32 d_ino; + u32 d_offset; + u16 d_namlen; + char d_name[1]; +}; + +/* + * IA-32 ELF specific definitions for IA-64. + */ + +#define _ASM_IA64_ELF_H /* Don't include elf.h */ + +#include +#include + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_386) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#define IA32_PAGE_OFFSET 0xc0000000 +#define IA32_STACK_TOP IA32_PAGE_OFFSET + +/* + * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can + * access them. + */ +#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) +#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) +#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE + +/* + * This is the location that an ET_DYN program is loaded if exec'ed. + * Typical use of this is to invoke "./ld.so someprog" to test out a + * new version of the loader. We need to make sure that it is out of + * the way of the program that it will "exec", and that there is + * sufficient room for the brk. + */ +#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) + +void ia64_elf32_init(struct pt_regs *regs); +#define ELF_PLAT_INIT(_r, load_addr) ia64_elf32_init(_r) + +#define elf_addr_t u32 + +/* ELF register definitions. This is needed for core dump support. */ + +#define ELF_NGREG 128 /* XXX fix me */ +#define ELF_NFPREG 128 /* XXX fix me */ + +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct { + unsigned long w0; + unsigned long w1; +} elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +/* This macro yields a bitmask that programs can use to figure out + what instruction set this CPU supports. */ +#define ELF_HWCAP 0 + +/* This macro yields a string that ld.so will use to load + implementation specific libraries for optimization. Not terribly + relevant until we have real hardware to play with... */ +#define ELF_PLATFORM 0 + +#ifdef __KERNEL__ +# define SET_PERSONALITY(EX,IBCS2) \ + (current->personality = (IBCS2) ? PER_SVR4 : PER_LINUX) +#endif + +#define IA32_EFLAG 0x200 + +/* + * IA-32 ELF specific definitions for IA-64. + */ + +#define __USER_CS 0x23 +#define __USER_DS 0x2B + +#define FIRST_TSS_ENTRY 6 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) + +#define IA32_SEGSEL_RPL (0x3 << 0) +#define IA32_SEGSEL_TI (0x1 << 2) +#define IA32_SEGSEL_INDEX_SHIFT 3 + +#define IA32_SEG_BASE 16 +#define IA32_SEG_TYPE 40 +#define IA32_SEG_SYS 44 +#define IA32_SEG_DPL 45 +#define IA32_SEG_P 47 +#define IA32_SEG_HIGH_LIMIT 48 +#define IA32_SEG_AVL 52 +#define IA32_SEG_DB 54 +#define IA32_SEG_G 55 +#define IA32_SEG_HIGH_BASE 56 + +#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran) \ + (((limit) & 0xffff) \ + | (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE) \ + | ((unsigned long) (segtype) << IA32_SEG_TYPE) \ + | ((unsigned long) (nonsysseg) << IA32_SEG_SYS) \ + | ((unsigned long) (dpl) << IA32_SEG_DPL) \ + | ((unsigned long) (segpresent) << IA32_SEG_P) \ + | ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT) \ + | ((unsigned long) (avl) << IA32_SEG_AVL) \ + | ((unsigned long) (segdb) << IA32_SEG_DB) \ + | ((unsigned long) (gran) << IA32_SEG_G) \ + | ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE)) + +#define SEG_LIM 32 +#define SEG_TYPE 52 +#define SEG_SYS 56 +#define SEG_DPL 57 +#define SEG_P 59 +#define SEG_AVL 60 +#define SEG_DB 62 +#define SEG_G 63 + +/* Unscramble an IA-32 segment descriptor into the IA-64 format. */ +#define IA32_SEG_UNSCRAMBLE(sd) \ + ( (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \ + | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM) \ + | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE) \ + | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS) \ + | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL) \ + | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P) \ + | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL) \ + | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB) \ + | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G)) + +#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ + +#define IA32_CR0 0x80000001 /* Enable PG and PE bits */ +#define IA32_CR4 0x600 /* MMXEX and FXSR on */ + +/* + * IA32 floating point control registers starting values + */ + +#define IA32_FSR_DEFAULT 0x55550000 /* set all tag bits */ +#define IA32_FCR_DEFAULT 0x17800000037fUL /* extended precision, all masks */ + +#define IA32_PTRACE_GETREGS 12 +#define IA32_PTRACE_SETREGS 13 +#define IA32_PTRACE_GETFPREGS 14 +#define IA32_PTRACE_SETFPREGS 15 +#define IA32_PTRACE_GETFPXREGS 18 +#define IA32_PTRACE_SETFPXREGS 19 + +#define ia32_start_thread(regs,new_ip,new_sp) do { \ + set_fs(USER_DS); \ + ia64_psr(regs)->cpl = 3; /* set user mode */ \ + ia64_psr(regs)->ri = 0; /* clear return slot number */ \ + ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \ + regs->cr_iip = new_ip; \ + regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \ + regs->ar_rnat = 0; \ + regs->loadrs = 0; \ + regs->r12 = new_sp; \ +} while (0) + +/* + * Local Descriptor Table (LDT) related declarations. + */ + +#define IA32_LDT_ENTRIES 8192 /* Maximum number of LDT entries supported. */ +#define IA32_LDT_ENTRY_SIZE 8 /* The size of each LDT entry. */ + +struct ia32_modify_ldt_ldt_s { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +}; + +struct linux_binprm; + +extern void ia32_init_addr_space (struct pt_regs *regs); +extern int ia32_setup_arg_pages (struct linux_binprm *bprm); +extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); +extern void ia32_load_segment_descriptors (struct task_struct *task); + +#define ia32f2ia64f(dst,src) \ + do { \ + register double f6 asm ("f6"); \ + asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ + } while(0) + +#define ia64f2ia32f(dst,src) \ + do { \ + register double f6 asm ("f6"); \ + asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ + } while(0) + +#endif /* !CONFIG_IA32_SUPPORT */ + +#endif /* _ASM_IA64_IA32_H */ diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Sat May 10 02:28:45 2003 +++ b/arch/ia64/ia32/sys_ia32.c Wed Jun 18 00:37:28 2003 @@ -53,7 +53,8 @@ #include #include #include -#include + +#include "ia32priv.h" #include #include @@ -206,9 +207,8 @@ static int -get_page_prot (unsigned long addr) +get_page_prot (struct vm_area_struct *vma, unsigned long addr) { - struct vm_area_struct *vma = find_vma(current->mm, addr); int prot = 0; if (!vma || vma->vm_start > addr) @@ -231,14 +231,26 @@ mmap_subpage (struct file *file, unsigned long start, unsigned long end, int prot, int flags, loff_t off) { - void *page = (void *) get_zeroed_page(GFP_KERNEL); + void *page = NULL; struct inode *inode; - unsigned long ret; - int old_prot = get_page_prot(start); + unsigned long ret = 0; + struct vm_area_struct *vma = find_vma(current->mm, start); + int old_prot = get_page_prot(vma, start); DBG("mmap_subpage(file=%p,start=0x%lx,end=0x%lx,prot=%x,flags=%x,off=0x%llx)\n", file, start, end, prot, flags, off); + + /* Optimize the case where the old mmap and the new mmap are both anonymous */ + if ((old_prot & PROT_WRITE) && (flags & MAP_ANONYMOUS) && !vma->vm_file) { + if (clear_user((void *) start, end - start)) { + ret = -EFAULT; + goto out; + } + goto skip_mmap; + } + + page = (void *) get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -263,6 +275,7 @@ copy_to_user((void *) end, page + PAGE_OFF(end), PAGE_SIZE - PAGE_OFF(end)); } + if (!(flags & MAP_ANONYMOUS)) { /* read the file contents */ inode = file->f_dentry->d_inode; @@ -273,10 +286,13 @@ goto out; } } + + skip_mmap: if (!(prot & PROT_WRITE)) ret = sys_mprotect(PAGE_START(start), PAGE_SIZE, prot | old_prot); out: - free_page((unsigned long) page); + if (page) + free_page((unsigned long) page); return ret; } @@ -532,11 +548,12 @@ mprotect_subpage (unsigned long address, int new_prot) { int old_prot; + struct vm_area_struct *vma; if (new_prot == PROT_NONE) return 0; /* optimize case where nothing changes... */ - - old_prot = get_page_prot(address); + vma = find_vma(current->mm, address); + old_prot = get_page_prot(vma, address); return sys_mprotect(address, PAGE_SIZE, new_prot | old_prot); } @@ -642,7 +659,6 @@ sorts of things, like timeval and itimerval. */ extern struct timezone sys_tz; -extern int do_sys_settimeofday (struct timeval *tv, struct timezone *tz); asmlinkage long sys32_gettimeofday (struct compat_timeval *tv, struct timezone *tz) @@ -664,18 +680,21 @@ sys32_settimeofday (struct compat_timeval *tv, struct timezone *tz) { struct timeval ktv; + struct timespec kts; struct timezone ktz; if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; + kts.tv_sec = ktv.tv_sec; + kts.tv_nsec = ktv.tv_usec * 1000; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } - return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); + return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); } struct getdents32_callback { @@ -836,9 +855,8 @@ } } - size = FDS_BYTES(n); ret = -EINVAL; - if (n < 0 || size < n) + if (n < 0) goto out_nofds; if (n > current->files->max_fdset) @@ -850,6 +868,7 @@ * long-words. */ ret = -ENOMEM; + size = FDS_BYTES(n); bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; @@ -1102,7 +1121,7 @@ }; struct shmid64_ds32 { - struct ipc64_perm shm_perm; + struct ipc64_perm32 shm_perm; compat_size_t shm_segsz; compat_time_t shm_atime; unsigned int __unused1; @@ -1320,7 +1339,6 @@ msgctl32 (int first, int second, void *uptr) { int err = -EINVAL, err2; - struct msqid_ds m; struct msqid64_ds m64; struct msqid_ds32 *up32 = (struct msqid_ds32 *)uptr; struct msqid64_ds32 *up64 = (struct msqid64_ds32 *)uptr; @@ -1336,21 +1354,21 @@ case IPC_SET: if (version == IPC_64) { - err = get_user(m.msg_perm.uid, &up64->msg_perm.uid); - err |= get_user(m.msg_perm.gid, &up64->msg_perm.gid); - err |= get_user(m.msg_perm.mode, &up64->msg_perm.mode); - err |= get_user(m.msg_qbytes, &up64->msg_qbytes); + err = get_user(m64.msg_perm.uid, &up64->msg_perm.uid); + err |= get_user(m64.msg_perm.gid, &up64->msg_perm.gid); + err |= get_user(m64.msg_perm.mode, &up64->msg_perm.mode); + err |= get_user(m64.msg_qbytes, &up64->msg_qbytes); } else { - err = get_user(m.msg_perm.uid, &up32->msg_perm.uid); - err |= get_user(m.msg_perm.gid, &up32->msg_perm.gid); - err |= get_user(m.msg_perm.mode, &up32->msg_perm.mode); - err |= get_user(m.msg_qbytes, &up32->msg_qbytes); + err = get_user(m64.msg_perm.uid, &up32->msg_perm.uid); + err |= get_user(m64.msg_perm.gid, &up32->msg_perm.gid); + err |= get_user(m64.msg_perm.mode, &up32->msg_perm.mode); + err |= get_user(m64.msg_qbytes, &up32->msg_qbytes); } if (err) break; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_msgctl(first, second, &m); + err = sys_msgctl(first, second, &m64); set_fs(old_fs); break; @@ -1430,7 +1448,7 @@ shmctl32 (int first, int second, void *uptr) { int err = -EFAULT, err2; - struct shmid_ds s; + struct shmid64_ds s64; struct shmid_ds32 *up32 = (struct shmid_ds32 *)uptr; struct shmid64_ds32 *up64 = (struct shmid64_ds32 *)uptr; @@ -1482,19 +1500,19 @@ case IPC_SET: if (version == IPC_64) { - err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); + err = get_user(s64.shm_perm.uid, &up64->shm_perm.uid); + err |= get_user(s64.shm_perm.gid, &up64->shm_perm.gid); + err |= get_user(s64.shm_perm.mode, &up64->shm_perm.mode); } else { - err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); - err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); - err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); + err = get_user(s64.shm_perm.uid, &up32->shm_perm.uid); + err |= get_user(s64.shm_perm.gid, &up32->shm_perm.gid); + err |= get_user(s64.shm_perm.mode, &up32->shm_perm.mode); } if (err) break; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_shmctl(first, second, &s); + err = sys_shmctl(first, second, &s64); set_fs(old_fs); break; @@ -1798,12 +1816,16 @@ ia64f2ia32f(f, &ptp->f9); break; case 2: + ia64f2ia32f(f, &ptp->f10); + break; case 3: + ia64f2ia32f(f, &ptp->f11); + break; case 4: case 5: case 6: case 7: - ia64f2ia32f(f, &swp->f10 + (regno - 2)); + ia64f2ia32f(f, &swp->f12 + (regno - 4)); break; } copy_to_user(reg, f, sizeof(*reg)); @@ -1824,12 +1846,16 @@ copy_from_user(&ptp->f9, reg, sizeof(*reg)); break; case 2: + copy_from_user(&ptp->f10, reg, sizeof(*reg)); + break; case 3: + copy_from_user(&ptp->f11, reg, sizeof(*reg)); + break; case 4: case 5: case 6: case 7: - copy_from_user(&swp->f10 + (regno - 2), reg, sizeof(*reg)); + copy_from_user(&swp->f12 + (regno - 4), reg, sizeof(*reg)); break; } return; @@ -1860,7 +1886,7 @@ ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + put_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0; } @@ -1893,7 +1919,7 @@ ptp = ia64_task_regs(tsk); tos = (tsk->thread.fsr >> 11) & 7; for (i = 0; i < 8; i++) - get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos); + get_fpreg(i, &save->st_space[i], ptp, swp, tos); return 0; } diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile --- a/arch/ia64/kernel/Makefile Fri Apr 11 18:05:22 2003 +++ b/arch/ia64/kernel/Makefile Tue Jun 17 23:50:16 2003 @@ -4,12 +4,11 @@ extra-y := head.o init_task.o -obj-y := acpi.o entry.o efi.o efi_stub.o gate.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o \ - ivt.o machvec.o pal.o perfmon.o process.o ptrace.o sal.o semaphore.o setup.o signal.o \ - sys_ia64.o time.o traps.o unaligned.o unwind.o +obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ + irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ + semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o obj-$(CONFIG_EFI_VARS) += efivars.o -obj-$(CONFIG_FSYS) += fsys.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o @@ -18,3 +17,30 @@ obj-$(CONFIG_IOSAPIC) += iosapic.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o + +# The gate DSO image is built using a special linker script. +targets += gate.so gate-syms.o + +AFLAGS_gate.lds.o += -P -C -U$(ARCH) +arch/ia64/kernel/gate.lds.s: %.s: %.S scripts FORCE + $(call if_changed_dep,as_s_S) + +quiet_cmd_gate = GATE $@ + cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@ + +GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 +$(obj)/gate.so: $(src)/gate.lds.s $(obj)/gate.o FORCE + $(call if_changed,gate) + +$(obj)/built-in.o: $(obj)/gate-syms.o +$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o + +GATECFLAGS_gate-syms.o = -r +$(obj)/gate-syms.o: $(src)/gate.lds.s $(obj)/gate.o FORCE + $(call if_changed,gate) + +# gate-data.o contains the gate DSO image as data in section .data.gate. +# We must build gate.so before we can assemble it. +# Note: kbuild does not track this dependency due to usage of .incbin +$(obj)/gate-data.o: $(obj)/gate.so diff -Nru a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c --- a/arch/ia64/kernel/acpi-ext.c Fri Apr 25 11:13:59 2003 +++ b/arch/ia64/kernel/acpi-ext.c Thu Jun 12 00:39:53 2003 @@ -84,7 +84,6 @@ acpi_status status; u8 *data; u32 length; - int i; status = acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length); diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c --- a/arch/ia64/kernel/acpi.c Sat May 10 02:28:45 2003 +++ b/arch/ia64/kernel/acpi.c Sat Jun 7 14:11:05 2003 @@ -96,6 +96,9 @@ if (!strcmp(hdr->oem_id, "HP")) { return "hpzx1"; } + else if (!strcmp(hdr->oem_id, "SGI")) { + return "sn2"; + } return "dig"; #else @@ -103,8 +106,6 @@ return "hpsim"; # elif defined (CONFIG_IA64_HP_ZX1) return "hpzx1"; -# elif defined (CONFIG_IA64_SGI_SN1) - return "sn1"; # elif defined (CONFIG_IA64_SGI_SN2) return "sn2"; # elif defined (CONFIG_IA64_DIG) @@ -191,21 +192,19 @@ printk(KERN_INFO "CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid); - if (lsapic->flags.enabled) { - available_cpus++; + if (!lsapic->flags.enabled) + printk(" disabled"); + else if (available_cpus >= NR_CPUS) + printk(" ignored (increase NR_CPUS)"); + else { printk(" enabled"); #ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid; + smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid; if (hard_smp_processor_id() - == (unsigned int) smp_boot_data.cpu_phys_id[total_cpus]) + == (unsigned int) smp_boot_data.cpu_phys_id[available_cpus]) printk(" (BSP)"); #endif - } - else { - printk(" disabled"); -#ifdef CONFIG_SMP - smp_boot_data.cpu_phys_id[total_cpus] = -1; -#endif + ++available_cpus; } printk("\n"); @@ -694,11 +693,11 @@ #endif #ifdef CONFIG_SMP + smp_boot_data.cpu_count = available_cpus; if (available_cpus == 0) { printk(KERN_INFO "ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } - smp_boot_data.cpu_count = total_cpus; smp_build_cpu_map(); # ifdef CONFIG_NUMA diff -Nru a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/kernel/asm-offsets.c Fri May 30 17:32:18 2003 @@ -0,0 +1,189 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + */ + +#include + +#include + +#include +#include +#include +#include + +#include "../kernel/sigframe.h" + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +void foo(void) +{ + DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct)); + DEFINE(IA64_THREAD_INFO_SIZE, sizeof (struct thread_info)); + DEFINE(IA64_PT_REGS_SIZE, sizeof (struct pt_regs)); + DEFINE(IA64_SWITCH_STACK_SIZE, sizeof (struct switch_stack)); + DEFINE(IA64_SIGINFO_SIZE, sizeof (struct siginfo)); + DEFINE(IA64_CPU_SIZE, sizeof (struct cpuinfo_ia64)); + DEFINE(SIGFRAME_SIZE, sizeof (struct sigframe)); + DEFINE(UNW_FRAME_INFO_SIZE, sizeof (struct unw_frame_info)); + + BLANK(); + + DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); + DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); + DEFINE(IA64_TASK_PID_OFFSET, offsetof (struct task_struct, pid)); + DEFINE(IA64_TASK_REAL_PARENT_OFFSET, offsetof (struct task_struct, real_parent)); + DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); + DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp)); + DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack)); + + BLANK(); + + DEFINE(IA64_PT_REGS_B6_OFFSET, offsetof (struct pt_regs, b6)); + DEFINE(IA64_PT_REGS_B7_OFFSET, offsetof (struct pt_regs, b7)); + DEFINE(IA64_PT_REGS_AR_CSD_OFFSET, offsetof (struct pt_regs, ar_csd)); + DEFINE(IA64_PT_REGS_AR_SSD_OFFSET, offsetof (struct pt_regs, ar_ssd)); + DEFINE(IA64_PT_REGS_R8_OFFSET, offsetof (struct pt_regs, r8)); + DEFINE(IA64_PT_REGS_R9_OFFSET, offsetof (struct pt_regs, r9)); + DEFINE(IA64_PT_REGS_R10_OFFSET, offsetof (struct pt_regs, r10)); + DEFINE(IA64_PT_REGS_R11_OFFSET, offsetof (struct pt_regs, r11)); + DEFINE(IA64_PT_REGS_CR_IPSR_OFFSET, offsetof (struct pt_regs, cr_ipsr)); + DEFINE(IA64_PT_REGS_CR_IIP_OFFSET, offsetof (struct pt_regs, cr_iip)); + DEFINE(IA64_PT_REGS_CR_IFS_OFFSET, offsetof (struct pt_regs, cr_ifs)); + DEFINE(IA64_PT_REGS_AR_UNAT_OFFSET, offsetof (struct pt_regs, ar_unat)); + DEFINE(IA64_PT_REGS_AR_PFS_OFFSET, offsetof (struct pt_regs, ar_pfs)); + DEFINE(IA64_PT_REGS_AR_RSC_OFFSET, offsetof (struct pt_regs, ar_rsc)); + DEFINE(IA64_PT_REGS_AR_RNAT_OFFSET, offsetof (struct pt_regs, ar_rnat)); + + DEFINE(IA64_PT_REGS_AR_BSPSTORE_OFFSET, offsetof (struct pt_regs, ar_bspstore)); + DEFINE(IA64_PT_REGS_PR_OFFSET, offsetof (struct pt_regs, pr)); + DEFINE(IA64_PT_REGS_B0_OFFSET, offsetof (struct pt_regs, b0)); + DEFINE(IA64_PT_REGS_LOADRS_OFFSET, offsetof (struct pt_regs, loadrs)); + DEFINE(IA64_PT_REGS_R1_OFFSET, offsetof (struct pt_regs, r1)); + DEFINE(IA64_PT_REGS_R12_OFFSET, offsetof (struct pt_regs, r12)); + DEFINE(IA64_PT_REGS_R13_OFFSET, offsetof (struct pt_regs, r13)); + DEFINE(IA64_PT_REGS_AR_FPSR_OFFSET, offsetof (struct pt_regs, ar_fpsr)); + DEFINE(IA64_PT_REGS_R15_OFFSET, offsetof (struct pt_regs, r15)); + DEFINE(IA64_PT_REGS_R14_OFFSET, offsetof (struct pt_regs, r14)); + DEFINE(IA64_PT_REGS_R2_OFFSET, offsetof (struct pt_regs, r2)); + DEFINE(IA64_PT_REGS_R3_OFFSET, offsetof (struct pt_regs, r3)); + DEFINE(IA64_PT_REGS_R16_OFFSET, offsetof (struct pt_regs, r16)); + DEFINE(IA64_PT_REGS_R17_OFFSET, offsetof (struct pt_regs, r17)); + DEFINE(IA64_PT_REGS_R18_OFFSET, offsetof (struct pt_regs, r18)); + DEFINE(IA64_PT_REGS_R19_OFFSET, offsetof (struct pt_regs, r19)); + DEFINE(IA64_PT_REGS_R20_OFFSET, offsetof (struct pt_regs, r20)); + DEFINE(IA64_PT_REGS_R21_OFFSET, offsetof (struct pt_regs, r21)); + DEFINE(IA64_PT_REGS_R22_OFFSET, offsetof (struct pt_regs, r22)); + DEFINE(IA64_PT_REGS_R23_OFFSET, offsetof (struct pt_regs, r23)); + DEFINE(IA64_PT_REGS_R24_OFFSET, offsetof (struct pt_regs, r24)); + DEFINE(IA64_PT_REGS_R25_OFFSET, offsetof (struct pt_regs, r25)); + DEFINE(IA64_PT_REGS_R26_OFFSET, offsetof (struct pt_regs, r26)); + DEFINE(IA64_PT_REGS_R27_OFFSET, offsetof (struct pt_regs, r27)); + DEFINE(IA64_PT_REGS_R28_OFFSET, offsetof (struct pt_regs, r28)); + DEFINE(IA64_PT_REGS_R29_OFFSET, offsetof (struct pt_regs, r29)); + DEFINE(IA64_PT_REGS_R30_OFFSET, offsetof (struct pt_regs, r30)); + DEFINE(IA64_PT_REGS_R31_OFFSET, offsetof (struct pt_regs, r31)); + DEFINE(IA64_PT_REGS_AR_CCV_OFFSET, offsetof (struct pt_regs, ar_ccv)); + DEFINE(IA64_PT_REGS_F6_OFFSET, offsetof (struct pt_regs, f6)); + DEFINE(IA64_PT_REGS_F7_OFFSET, offsetof (struct pt_regs, f7)); + DEFINE(IA64_PT_REGS_F8_OFFSET, offsetof (struct pt_regs, f8)); + DEFINE(IA64_PT_REGS_F9_OFFSET, offsetof (struct pt_regs, f9)); + DEFINE(IA64_PT_REGS_F10_OFFSET, offsetof (struct pt_regs, f10)); + DEFINE(IA64_PT_REGS_F11_OFFSET, offsetof (struct pt_regs, f11)); + + BLANK(); + + DEFINE(IA64_SWITCH_STACK_CALLER_UNAT_OFFSET, offsetof (struct switch_stack, caller_unat)); + DEFINE(IA64_SWITCH_STACK_AR_FPSR_OFFSET, offsetof (struct switch_stack, ar_fpsr)); + DEFINE(IA64_SWITCH_STACK_F2_OFFSET, offsetof (struct switch_stack, f2)); + DEFINE(IA64_SWITCH_STACK_F3_OFFSET, offsetof (struct switch_stack, f3)); + DEFINE(IA64_SWITCH_STACK_F4_OFFSET, offsetof (struct switch_stack, f4)); + DEFINE(IA64_SWITCH_STACK_F5_OFFSET, offsetof (struct switch_stack, f5)); + DEFINE(IA64_SWITCH_STACK_F12_OFFSET, offsetof (struct switch_stack, f12)); + DEFINE(IA64_SWITCH_STACK_F13_OFFSET, offsetof (struct switch_stack, f13)); + DEFINE(IA64_SWITCH_STACK_F14_OFFSET, offsetof (struct switch_stack, f14)); + DEFINE(IA64_SWITCH_STACK_F15_OFFSET, offsetof (struct switch_stack, f15)); + DEFINE(IA64_SWITCH_STACK_F16_OFFSET, offsetof (struct switch_stack, f16)); + DEFINE(IA64_SWITCH_STACK_F17_OFFSET, offsetof (struct switch_stack, f17)); + DEFINE(IA64_SWITCH_STACK_F18_OFFSET, offsetof (struct switch_stack, f18)); + DEFINE(IA64_SWITCH_STACK_F19_OFFSET, offsetof (struct switch_stack, f19)); + DEFINE(IA64_SWITCH_STACK_F20_OFFSET, offsetof (struct switch_stack, f20)); + DEFINE(IA64_SWITCH_STACK_F21_OFFSET, offsetof (struct switch_stack, f21)); + DEFINE(IA64_SWITCH_STACK_F22_OFFSET, offsetof (struct switch_stack, f22)); + DEFINE(IA64_SWITCH_STACK_F23_OFFSET, offsetof (struct switch_stack, f23)); + DEFINE(IA64_SWITCH_STACK_F24_OFFSET, offsetof (struct switch_stack, f24)); + DEFINE(IA64_SWITCH_STACK_F25_OFFSET, offsetof (struct switch_stack, f25)); + DEFINE(IA64_SWITCH_STACK_F26_OFFSET, offsetof (struct switch_stack, f26)); + DEFINE(IA64_SWITCH_STACK_F27_OFFSET, offsetof (struct switch_stack, f27)); + DEFINE(IA64_SWITCH_STACK_F28_OFFSET, offsetof (struct switch_stack, f28)); + DEFINE(IA64_SWITCH_STACK_F29_OFFSET, offsetof (struct switch_stack, f29)); + DEFINE(IA64_SWITCH_STACK_F30_OFFSET, offsetof (struct switch_stack, f30)); + DEFINE(IA64_SWITCH_STACK_F31_OFFSET, offsetof (struct switch_stack, f31)); + DEFINE(IA64_SWITCH_STACK_R4_OFFSET, offsetof (struct switch_stack, r4)); + DEFINE(IA64_SWITCH_STACK_R5_OFFSET, offsetof (struct switch_stack, r5)); + DEFINE(IA64_SWITCH_STACK_R6_OFFSET, offsetof (struct switch_stack, r6)); + DEFINE(IA64_SWITCH_STACK_R7_OFFSET, offsetof (struct switch_stack, r7)); + DEFINE(IA64_SWITCH_STACK_B0_OFFSET, offsetof (struct switch_stack, b0)); + DEFINE(IA64_SWITCH_STACK_B1_OFFSET, offsetof (struct switch_stack, b1)); + DEFINE(IA64_SWITCH_STACK_B2_OFFSET, offsetof (struct switch_stack, b2)); + DEFINE(IA64_SWITCH_STACK_B3_OFFSET, offsetof (struct switch_stack, b3)); + DEFINE(IA64_SWITCH_STACK_B4_OFFSET, offsetof (struct switch_stack, b4)); + DEFINE(IA64_SWITCH_STACK_B5_OFFSET, offsetof (struct switch_stack, b5)); + DEFINE(IA64_SWITCH_STACK_AR_PFS_OFFSET, offsetof (struct switch_stack, ar_pfs)); + DEFINE(IA64_SWITCH_STACK_AR_LC_OFFSET, offsetof (struct switch_stack, ar_lc)); + DEFINE(IA64_SWITCH_STACK_AR_UNAT_OFFSET, offsetof (struct switch_stack, ar_unat)); + DEFINE(IA64_SWITCH_STACK_AR_RNAT_OFFSET, offsetof (struct switch_stack, ar_rnat)); + DEFINE(IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET, offsetof (struct switch_stack, ar_bspstore)); + DEFINE(IA64_SWITCH_STACK_PR_OFFSET, offsetof (struct switch_stack, pr)); + + BLANK(); + + DEFINE(IA64_SIGCONTEXT_IP_OFFSET, offsetof (struct sigcontext, sc_ip)); + DEFINE(IA64_SIGCONTEXT_AR_BSP_OFFSET, offsetof (struct sigcontext, sc_ar_bsp)); + DEFINE(IA64_SIGCONTEXT_AR_FPSR_OFFSET, offsetof (struct sigcontext, sc_ar_fpsr)); + DEFINE(IA64_SIGCONTEXT_AR_RNAT_OFFSET, offsetof (struct sigcontext, sc_ar_rnat)); + DEFINE(IA64_SIGCONTEXT_AR_UNAT_OFFSET, offsetof (struct sigcontext, sc_ar_unat)); + DEFINE(IA64_SIGCONTEXT_B0_OFFSET, offsetof (struct sigcontext, sc_br[0])); + DEFINE(IA64_SIGCONTEXT_CFM_OFFSET, offsetof (struct sigcontext, sc_cfm)); + DEFINE(IA64_SIGCONTEXT_FLAGS_OFFSET, offsetof (struct sigcontext, sc_flags)); + DEFINE(IA64_SIGCONTEXT_FR6_OFFSET, offsetof (struct sigcontext, sc_fr[6])); + DEFINE(IA64_SIGCONTEXT_PR_OFFSET, offsetof (struct sigcontext, sc_pr)); + DEFINE(IA64_SIGCONTEXT_R12_OFFSET, offsetof (struct sigcontext, sc_gr[12])); + DEFINE(IA64_SIGCONTEXT_RBS_BASE_OFFSET,offsetof (struct sigcontext, sc_rbs_base)); + DEFINE(IA64_SIGCONTEXT_LOADRS_OFFSET, offsetof (struct sigcontext, sc_loadrs)); + + BLANK(); + + DEFINE(IA64_SIGFRAME_ARG0_OFFSET, offsetof (struct sigframe, arg0)); + DEFINE(IA64_SIGFRAME_ARG1_OFFSET, offsetof (struct sigframe, arg1)); + DEFINE(IA64_SIGFRAME_ARG2_OFFSET, offsetof (struct sigframe, arg2)); + DEFINE(IA64_SIGFRAME_HANDLER_OFFSET, offsetof (struct sigframe, handler)); + DEFINE(IA64_SIGFRAME_SIGCONTEXT_OFFSET, offsetof (struct sigframe, sc)); + BLANK(); + /* for assembly files which can't include sched.h: */ + DEFINE(IA64_CLONE_VFORK, CLONE_VFORK); + DEFINE(IA64_CLONE_VM, CLONE_VM); + + BLANK(); + /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ + DEFINE(IA64_CPUINFO_ITM_DELTA_OFFSET, offsetof (struct cpuinfo_ia64, itm_delta)); + DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); + DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, offsetof (struct cpuinfo_ia64, nsec_per_cyc)); + DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); + + + DEFINE(CLONE_IDLETASK_BIT, 12); +#if CLONE_IDLETASK != (1 << 12) +# error "CLONE_IDLETASK_BIT incorrect, please fix" +#endif + + DEFINE(CLONE_SETTLS_BIT, 19); +#if CLONE_SETTLS != (1<<19) +# error "CLONE_SETTLS_BIT incorrect, please fix" +#endif + +} diff -Nru a/arch/ia64/kernel/efi_stub.S b/arch/ia64/kernel/efi_stub.S --- a/arch/ia64/kernel/efi_stub.S Tue May 21 01:52:24 2002 +++ b/arch/ia64/kernel/efi_stub.S Thu May 15 04:45:02 2003 @@ -62,7 +62,7 @@ mov b6=r2 ;; andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret0: mov out4=in5 mov out0=in1 mov out1=in2 @@ -73,7 +73,7 @@ br.call.sptk.many rp=b6 // call the EFI function .ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov ar.rsc=loc4 // restore RSE configuration mov ar.pfs=loc1 mov rp=loc0 diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S Mon May 12 18:59:21 2003 +++ b/arch/ia64/kernel/entry.S Tue Jun 17 23:50:16 2003 @@ -5,10 +5,13 @@ * * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 1999, 2002-2003 + * Asit Mallick + * Don Dugger + * Suresh Siddha + * Fenghua Yu * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999 Asit Mallick - * Copyright (C) 1999 Don Dugger */ /* * ia64_switch_to now places correct virtual mapping in in TR2 for @@ -74,19 +77,18 @@ * this executes in less than 20 cycles even on Itanium, so it's not worth * optimizing for...). */ + mov ar.unat=0; mov ar.lc=0 mov r4=0; mov f2=f0; mov b1=r0 mov r5=0; mov f3=f0; mov b2=r0 mov r6=0; mov f4=f0; mov b3=r0 mov r7=0; mov f5=f0; mov b4=r0 - mov ar.unat=0; mov f10=f0; mov b5=r0 - ldf.fill f11=[sp]; ldf.fill f12=[sp]; mov f13=f0 + ldf.fill f12=[sp]; mov f13=f0; mov b5=r0 ldf.fill f14=[sp]; ldf.fill f15=[sp]; mov f16=f0 ldf.fill f17=[sp]; ldf.fill f18=[sp]; mov f19=f0 ldf.fill f20=[sp]; ldf.fill f21=[sp]; mov f22=f0 ldf.fill f23=[sp]; ldf.fill f24=[sp]; mov f25=f0 ldf.fill f26=[sp]; ldf.fill f27=[sp]; mov f28=f0 ldf.fill f29=[sp]; ldf.fill f30=[sp]; mov f31=f0 - mov ar.lc=0 br.ret.sptk.many rp END(ia64_execve) @@ -114,14 +116,8 @@ br.call.sptk.many rp=do_fork .ret1: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys_clone2) @@ -149,14 +145,8 @@ br.call.sptk.many rp=do_fork .ret2: .restore sp adds sp=IA64_SWITCH_STACK_SIZE,sp // pop the switch stack - mov r2=-1000 - adds r3=IA64_TASK_PID_OFFSET,r8 - ;; - cmp.leu p6,p0=r8,r2 mov ar.pfs=loc1 mov rp=loc0 - ;; -(p6) ld4 r8=[r3] br.ret.sptk.many rp END(sys_clone) @@ -178,15 +168,12 @@ ;; st8 [r22]=sp // save kernel stack pointer of old task shr.u r26=r20,IA64_GRANULE_SHIFT - shr.u r17=r20,KERNEL_TR_PAGE_SHIFT - ;; - cmp.ne p6,p7=KERNEL_TR_PAGE_NUM,r17 adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 ;; /* * If we've already mapped this task's page, we can skip doing it again. */ -(p6) cmp.eq p7,p6=r26,r27 + cmp.eq p7,p6=r26,r27 (p6) br.cond.dpnt .map ;; .done: @@ -224,14 +211,12 @@ END(ia64_switch_to) /* - * Note that interrupts are enabled during save_switch_stack and - * load_switch_stack. This means that we may get an interrupt with - * "sp" pointing to the new kernel stack while ar.bspstore is still - * pointing to the old kernel backing store area. Since ar.rsc, - * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, - * this is not a problem. Also, we don't need to specify unwind - * information for preserved registers that are not modified in - * save_switch_stack as the right unwind information is already + * Note that interrupts are enabled during save_switch_stack and load_switch_stack. This + * means that we may get an interrupt with "sp" pointing to the new kernel stack while + * ar.bspstore is still pointing to the old kernel backing store area. Since ar.rsc, + * ar.rnat, ar.bsp, and ar.bspstore are all preserved by interrupts, this is not a + * problem. Also, we don't need to specify unwind information for preserved registers + * that are not modified in save_switch_stack as the right unwind information is already * specified at the call-site of save_switch_stack. */ @@ -305,8 +290,6 @@ st8 [r14]=r21,SW(B1)-SW(B0) // save b0 st8 [r15]=r23,SW(B3)-SW(B2) // save b2 mov r25=b4 - stf.spill [r2]=f10,32 - stf.spill [r3]=f11,32 mov r26=b5 ;; st8 [r14]=r22,SW(B4)-SW(B1) // save b1 @@ -405,9 +388,6 @@ ldf.fill f4=[r14],32 ldf.fill f5=[r15],32 ;; - ldf.fill f10=[r14],32 - ldf.fill f11=[r15],32 - ;; ldf.fill f12=[r14],32 ldf.fill f13=[r15],32 ;; @@ -525,11 +505,11 @@ (p6) br.cond.sptk strace_error // syscall failed -> ;; // avoid RAW on r10 strace_save_retval: -.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 -.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 +.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 +.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 ia64_strace_leave_kernel: br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value -.rety: br.cond.sptk ia64_leave_kernel +.rety: br.cond.sptk ia64_leave_syscall strace_error: ld8 r3=[r2] // load pt_regs.r8 @@ -575,129 +555,288 @@ adds r2=PT(R8)+16,sp // r2 = &pt_regs.r8 adds r3=PT(R10)+16,sp // r3 = &pt_regs.r10 ;; - .mem.offset 0,0 -(p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit - .mem.offset 8,0 -(p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit +.mem.offset 0,0; (p6) st8.spill [r2]=r8 // store return value in slot for r8 and set unat bit +.mem.offset 8,0; (p6) st8.spill [r3]=r0 // clear error indication in slot for r10 and set unat bit (p7) br.cond.spnt handle_syscall_error // handle potential syscall failure END(ia64_ret_from_syscall) // fall through -GLOBAL_ENTRY(ia64_leave_kernel) +/* + * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't + * need to switch to bank 0 and doesn't restore the scratch registers. + * To avoid leaking kernel bits, the scratch registers are set to + * the following known-to-be-safe values: + * + * r1: restored (global pointer) + * r2: cleared + * r3: 1 (when returning to user-level) + * r8-r11: restored (syscall return value(s)) + * r12: restored (user-level stack pointer) + * r13: restored (user-level thread pointer) + * r14: cleared + * r15: restored (syscall #) + * r16-r19: cleared + * r20: user-level ar.fpsr + * r21: user-level b0 + * r22: user-level b6 + * r23: user-level ar.bspstore + * r24: user-level ar.rnat + * r25: user-level ar.unat + * r26: user-level ar.pfs + * r27: user-level ar.rsc + * r28: user-level ip + * r29: user-level psr + * r30: user-level cfm + * r31: user-level pr + * f6-f11: cleared + * pr: restored (user-level pr) + * b0: restored (user-level rp) + * b6: restored + * b7: cleared + * ar.unat: restored (user-level ar.unat) + * ar.pfs: restored (user-level ar.pfs) + * ar.rsc: restored (user-level ar.rsc) + * ar.rnat: restored (user-level ar.rnat) + * ar.bspstore: restored (user-level ar.bspstore) + * ar.fpsr: restored (user-level ar.fpsr) + * ar.ccv: cleared + * ar.csd: cleared + * ar.ssd: cleared + */ +GLOBAL_ENTRY(ia64_leave_syscall) PT_REGS_UNWIND_INFO(0) - // work.need_resched etc. mustn't get changed by this CPU before it returns to - // user- or fsys-mode: -(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to + * user- or fsys-mode, hence we disable interrupts early on: + */ #ifdef CONFIG_PREEMPT rsm psr.i // disable interrupts - adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 +#else +(pUStk) rsm psr.i +#endif + cmp.eq pLvSys,p0=r0,r0 // pLvSys=1: leave from syscall +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk +.work_processed_syscall: +#ifdef CONFIG_PREEMPT (pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; -(pKStk) ld4 r21=[r20] // preempt_count ->r21 + .pred.rel.mutex pUStk,pKStk +(pKStk) ld4 r21=[r20] // r21 <- preempt_count +(pUStk) mov r21=0 // r21 <- 0 + ;; +(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) +#endif /* CONFIG_PREEMPT */ + adds r16=PT(LOADRS)+16,r12 + adds r17=PT(AR_BSPSTORE)+16,r12 + adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; +(p6) ld4 r31=[r18] // load current_thread_info()->flags + ld8 r19=[r16],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" + nop.i 0 + ;; + ld8 r23=[r17],PT(R9)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) + ld8 r22=[r16],PT(R8)-PT(B6) // load b6 +(p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? ;; -(pKStk) cmp4.eq p6,p0=r21,r0 // p6 <- preempt_count == 0 + + mov.m ar.ccv=r0 // clear ar.ccv +(p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending? +(p6) br.cond.spnt .work_pending + ;; + // start restoring the state saved on the kernel stack (struct pt_regs): + ld8.fill r8=[r16],16 + ld8.fill r9=[r17],16 + mov f6=f0 // clear f6 + ;; + ld8.fill r10=[r16],16 + ld8.fill r11=[r17],16 + mov f7=f0 // clear f7 + ;; + ld8 r29=[r16],16 // load cr.ipsr + ld8 r28=[r17],16 // load cr.iip + mov f8=f0 // clear f8 ;; -#else /* CONFIG_PREEMPT */ + ld8 r30=[r16],16 // load cr.ifs + ld8 r25=[r17],16 // load ar.unat + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs + ;; + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + invala // invalidate ALAT + mov f9=f0 // clear f9 + + mov.m ar.ssd=r0 // clear ar.ssd + mov.m ar.csd=r0 // clear ar.csd + mov f10=f0 // clear f10 + ;; + ld8 r26=[r16],16 // load ar.pfs + ld8 r27=[r17],PT(PR)-PT(AR_RSC) // load ar.rsc + mov f11=f0 // clear f11 + ;; + ld8 r24=[r16],PT(B0)-PT(AR_RNAT) // load ar.rnat (may be garbage) + ld8 r31=[r17],PT(R1)-PT(PR) // load predicates +(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 + ;; + ld8 r21=[r16],PT(R12)-PT(B0) // load b0 + ld8.fill r1=[r17],16 // load r1 +(pUStk) mov r3=1 + ;; + ld8.fill r12=[r16],16 + ld8.fill r13=[r17],16 + mov r2=r0 // clear r2 + ;; + ld8 r20=[r16] // load ar.fpsr + ld8.fill r15=[r17] // load r15 + mov b7=r0 // clear b7 + ;; +(pUStk) st1 [r14]=r3 + movl r17=THIS_CPU(ia64_phys_stacked_size_p8) + ;; + mov r16=ar.bsp // get existing backing store pointer + srlz.i // ensure interruption collection is off + mov r14=r0 // clear r14 + ;; + ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 + mov b6=r22 // restore b6 + shr.u r18=r19,16 // get byte size of existing "dirty" partition +(pKStk) br.cond.dpnt.many skip_rbs_switch + br.cond.sptk.many rbs_switch +END(ia64_leave_syscall) + +GLOBAL_ENTRY(ia64_leave_kernel) + PT_REGS_UNWIND_INFO(0) + /* + * work.need_resched etc. mustn't get changed by this CPU before it returns to + * user- or fsys-mode, hence we disable interrupts early on: + */ +#ifdef CONFIG_PREEMPT + rsm psr.i // disable interrupts +#else (pUStk) rsm psr.i +#endif + cmp.eq p0,pLvSys=r0,r0 // pLvSys=0: leave from kernel +(pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk ;; -(pUStk) adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 +.work_processed_kernel: +#ifdef CONFIG_PREEMPT + adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 + ;; + .pred.rel.mutex pUStk,pKStk +(pKStk) ld4 r21=[r20] // r21 <- preempt_count +(pUStk) mov r21=0 // r21 <- 0 ;; +(p6) cmp.eq.unc p6,p0=r21,r0 // p6 <- p6 && (r21 == 0) #endif /* CONFIG_PREEMPT */ -.work_processed: -(p6) ld4 r18=[r17] // load current_thread_info()->flags - adds r2=PT(R8)+16,r12 - adds r3=PT(R9)+16,r12 + adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 ;; - // start restoring the state saved on the kernel stack (struct pt_regs): - ld8.fill r8=[r2],16 - ld8.fill r9=[r3],16 -(p6) and r19=TIF_WORK_MASK,r18 // any work other than TIF_SYSCALL_TRACE? +(p6) ld4 r31=[r17] // load current_thread_info()->flags + adds r21=PT(PR)+16,r12 + ;; + + lfetch [r21],PT(CR_IPSR)-PT(PR) + adds r2=PT(B6)+16,r12 + adds r3=PT(R16)+16,r12 ;; - ld8.fill r10=[r2],16 - ld8.fill r11=[r3],16 + lfetch [r21] + ld8 r28=[r2],8 // load b6 + adds r29=PT(R24)+16,r12 + + ld8.fill r16=[r3],PT(AR_CSD)-PT(R16) + adds r30=PT(AR_CCV)+16,r12 +(p6) and r19=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? + ;; + ld8.fill r24=[r29] + ld8 r15=[r30] // load ar.ccv (p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending? ;; - ld8.fill r16=[r2],16 - ld8.fill r17=[r3],16 + ld8 r29=[r2],16 // load b7 + ld8 r30=[r3],16 // load ar.csd (p6) br.cond.spnt .work_pending ;; + ld8 r31=[r2],16 // load ar.ssd + ld8.fill r8=[r3],16 + ;; + ld8.fill r9=[r2],16 + ld8.fill r10=[r3],PT(R17)-PT(R10) + ;; + ld8.fill r11=[r2],PT(R18)-PT(R11) + ld8.fill r17=[r3],16 + ;; ld8.fill r18=[r2],16 ld8.fill r19=[r3],16 ;; ld8.fill r20=[r2],16 ld8.fill r21=[r3],16 + mov ar.csd=r30 + mov ar.ssd=r31 ;; - ld8.fill r22=[r2],16 - ld8.fill r23=[r3],16 - ;; - ld8.fill r24=[r2],16 - ld8.fill r25=[r3],16 - ;; - ld8.fill r26=[r2],16 - ld8.fill r27=[r3],16 + rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection + invala // invalidate ALAT ;; - ld8.fill r28=[r2],16 - ld8.fill r29=[r3],16 + ld8.fill r22=[r2],24 + ld8.fill r23=[r3],24 + mov b6=r28 ;; - ld8.fill r30=[r2],16 - ld8.fill r31=[r3],16 + ld8.fill r25=[r2],16 + ld8.fill r26=[r3],16 + mov b7=r29 ;; - rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection - invala // invalidate ALAT + ld8.fill r27=[r2],16 + ld8.fill r28=[r3],16 ;; - ld8 r1=[r2],16 // ar.ccv - ld8 r13=[r3],16 // ar.fpsr + ld8.fill r29=[r2],16 + ld8.fill r30=[r3],24 ;; - ld8 r14=[r2],16 // b0 - ld8 r15=[r3],16+8 // b7 + ld8.fill r31=[r2],PT(F9)-PT(R31) + adds r3=PT(F10)-PT(F6),r3 ;; - ldf.fill f6=[r2],32 - ldf.fill f7=[r3],32 + ldf.fill f9=[r2],PT(F6)-PT(F9) + ldf.fill f10=[r3],PT(F8)-PT(F10) ;; - ldf.fill f8=[r2],32 - ldf.fill f9=[r3],32 + ldf.fill f6=[r2],PT(F7)-PT(F6) ;; - mov ar.ccv=r1 - mov ar.fpsr=r13 - mov b0=r14 + ldf.fill f7=[r2],PT(F11)-PT(F7) + ldf.fill f8=[r3],32 ;; srlz.i // ensure interruption collection is off - mov b7=r15 + mov ar.ccv=r15 + ;; bsw.0 // switch back to bank 0 (no stop bit required beforehand...) ;; + ldf.fill f11=[r2] (pUStk) mov r18=IA64_KR(CURRENT) // Itanium 2: 12 cycle read latency - adds r16=16,r12 - adds r17=24,r12 + adds r16=PT(CR_IPSR)+16,r12 + adds r17=PT(CR_IIP)+16,r12 ;; - ld8 rCRIPSR=[r16],16 // load cr.ipsr - ld8 rCRIIP=[r17],16 // load cr.iip + ld8 r29=[r16],16 // load cr.ipsr + ld8 r28=[r17],16 // load cr.iip ;; - ld8 rCRIFS=[r16],16 // load cr.ifs - ld8 rARUNAT=[r17],16 // load ar.unat - cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs + ld8 r30=[r16],16 // load cr.ifs + ld8 r25=[r17],16 // load ar.unat ;; - ld8 rARPFS=[r16],16 // load ar.pfs - ld8 rARRSC=[r17],16 // load ar.rsc + ld8 r26=[r16],16 // load ar.pfs + ld8 r27=[r17],16 // load ar.rsc + cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; - ld8 rARRNAT=[r16],16 // load ar.rnat (may be garbage) - ld8 rARBSPSTORE=[r17],16 // load ar.bspstore (may be garbage) + ld8 r24=[r16],16 // load ar.rnat (may be garbage) + ld8 r23=[r17],16// load ar.bspstore (may be garbage) ;; - ld8 rARPR=[r16],16 // load predicates - ld8 rB6=[r17],16 // load b6 + ld8 r31=[r16],16 // load predicates + ld8 r21=[r17],16 // load b0 ;; ld8 r19=[r16],16 // load ar.rsc value for "loadrs" ld8.fill r1=[r17],16 // load r1 ;; - ld8.fill r2=[r16],16 - ld8.fill r3=[r17],16 - ;; ld8.fill r12=[r16],16 ld8.fill r13=[r17],16 (pUStk) adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18 ;; - ld8.fill r14=[r16] - ld8.fill r15=[r17] + ld8 r20=[r16],16 // ar.fpsr + ld8.fill r15=[r17],16 + ;; + ld8.fill r14=[r16],16 + ld8.fill r2=[r17] (pUStk) mov r17=1 ;; + ld8.fill r3=[r16] (pUStk) st1 [r18]=r17 // restore current->thread.on_ustack shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; @@ -713,6 +852,8 @@ * NOTE: alloc, loadrs, and cover can't be predicated. */ (pNonSys) br.cond.dpnt dont_preserve_current_frame + +rbs_switch: cover // add current frame into dirty partition and set cr.ifs ;; mov r19=ar.bsp // get new backing store pointer @@ -765,7 +906,7 @@ }{ .mib mov loc3=0 mov loc4=0 -(pRecurse) br.call.sptk.many b6=rse_clear_invalid +(pRecurse) br.call.sptk.many b0=rse_clear_invalid }{ .mfi // cycle 2 mov loc5=0 @@ -774,7 +915,7 @@ }{ .mib mov loc6=0 mov loc7=0 -(pReturn) br.ret.sptk.many b6 +(pReturn) br.ret.sptk.many b0 } #else /* !CONFIG_ITANIUM */ alloc loc0=ar.pfs,2,Nregs-2,2,0 @@ -789,14 +930,14 @@ mov loc5=0 mov loc6=0 mov loc7=0 -(pRecurse) br.call.sptk.many b6=rse_clear_invalid +(pRecurse) br.call.sptk.few b0=rse_clear_invalid ;; mov loc8=0 mov loc9=0 cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret mov loc10=0 mov loc11=0 -(pReturn) br.ret.sptk.many b6 +(pReturn) br.ret.sptk.many b0 #endif /* !CONFIG_ITANIUM */ # undef pRecurse # undef pReturn @@ -806,59 +947,65 @@ loadrs ;; skip_rbs_switch: - mov b6=rB6 - mov ar.pfs=rARPFS -(pUStk) mov ar.bspstore=rARBSPSTORE -(p9) mov cr.ifs=rCRIFS - mov cr.ipsr=rCRIPSR - mov cr.iip=rCRIIP - ;; -(pUStk) mov ar.rnat=rARRNAT // must happen with RSE in lazy mode - mov ar.rsc=rARRSC - mov ar.unat=rARUNAT - mov pr=rARPR,-1 +(pLvSys) mov r19=r0 // clear r19 for leave_syscall, no-op otherwise + mov b0=r21 + mov ar.pfs=r26 +(pUStk) mov ar.bspstore=r23 +(p9) mov cr.ifs=r30 +(pLvSys)mov r16=r0 // clear r16 for leave_syscall, no-op otherwise + mov cr.ipsr=r29 + mov ar.fpsr=r20 +(pLvSys)mov r17=r0 // clear r17 for leave_syscall, no-op otherwise + mov cr.iip=r28 + ;; +(pUStk) mov ar.rnat=r24 // must happen with RSE in lazy mode +(pLvSys)mov r18=r0 // clear r18 for leave_syscall, no-op otherwise + mov ar.rsc=r27 + mov ar.unat=r25 + mov pr=r31,-1 rfi + /* + * On entry: + * r20 = ¤t->thread_info->pre_count (if CONFIG_PREEMPT) + * r31 = current->thread_info->flags + * On exit: + * p6 = TRUE if work-pending-check needs to be redone + */ .work_pending: - tbit.z p6,p0=r18,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? + tbit.z p6,p0=r31,TIF_NEED_RESCHED // current_thread_info()->need_resched==0? (p6) br.cond.sptk.few .notify #ifdef CONFIG_PREEMPT -(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 +(pKStk) dep r21=-1,r0,PREEMPT_ACTIVE_BIT,1 ;; (pKStk) st4 [r20]=r21 - ssm psr.i // enable interrupts + ssm psr.i // enable interrupts #endif - -#if __GNUC__ < 3 - br.call.spnt.many rp=invoke_schedule -#else br.call.spnt.many rp=schedule -#endif .ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1 rsm psr.i // disable interrupts ;; - adds r17=TI_FLAGS+IA64_TASK_SIZE,r13 #ifdef CONFIG_PREEMPT (pKStk) adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13 ;; (pKStk) st4 [r20]=r0 // preempt_count() <- 0 #endif - br.cond.sptk.many .work_processed // re-check +(pLvSys)br.cond.sptk.many .work_processed_syscall // re-check + br.cond.sptk.many .work_processed_kernel // re-check .notify: br.call.spnt.many rp=notify_resume_user .ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0 - br.cond.sptk.many .work_processed // don't re-check +(pLvSys)br.cond.sptk.many .work_processed_syscall // don't re-check + br.cond.sptk.many .work_processed_kernel // don't re-check END(ia64_leave_kernel) ENTRY(handle_syscall_error) /* - * Some system calls (e.g., ptrace, mmap) can return arbitrary - * values which could lead us to mistake a negative return - * value as a failed syscall. Those syscall must deposit - * a non-zero value in pt_regs.r8 to indicate an error. - * If pt_regs.r8 is zero, we assume that the call completed - * successfully. + * Some system calls (e.g., ptrace, mmap) can return arbitrary values which could + * lead us to mistake a negative return value as a failed syscall. Those syscall + * must deposit a non-zero value in pt_regs.r8 to indicate an error. If + * pt_regs.r8 is zero, we assume that the call completed successfully. */ PT_REGS_UNWIND_INFO(0) ld8 r3=[r2] // load pt_regs.r8 @@ -873,7 +1020,7 @@ ;; .mem.offset 0,0; st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit .mem.offset 8,0; st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit - br.cond.sptk ia64_leave_kernel + br.cond.sptk ia64_leave_syscall END(handle_syscall_error) /* @@ -892,31 +1039,6 @@ br.ret.sptk.many rp END(ia64_invoke_schedule_tail) -#if __GNUC__ < 3 - - /* - * Invoke schedule() while preserving in0-in7, which may be needed - * in case a system call gets restarted. Note that declaring schedule() - * with asmlinkage() is NOT enough because that will only preserve as many - * registers as there are formal arguments. - * - * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage - * renders all eight input registers (in0-in7) as "untouchable". - */ -ENTRY(invoke_schedule) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,2,0,0 - mov loc0=rp - ;; - .body - br.call.sptk.many rp=schedule -.ret14: mov ar.pfs=loc1 - mov rp=loc0 - br.ret.sptk.many rp -END(invoke_schedule) - -#endif /* __GNUC__ < 3 */ - /* * Setup stack and call do_notify_resume_user(). Note that pSys and pNonSys need to * be set up by the caller. We declare 8 input registers so the system call @@ -984,6 +1106,23 @@ .body cmp.eq pNonSys,pSys=r0,r0 // sigreturn isn't a normal syscall... ;; + /* + * leave_kernel() restores f6-f11 from pt_regs, but since the streamlined + * syscall-entry path does not save them we save them here instead. Note: we + * don't need to save any other registers that are not saved by the stream-lined + * syscall path, because restore_sigcontext() restores them. + */ + adds r16=PT(F6)+32,sp + adds r17=PT(F7)+32,sp + ;; + stf.spill [r16]=f6,32 + stf.spill [r17]=f7,32 + ;; + stf.spill [r16]=f8,32 + stf.spill [r17]=f9,32 + ;; + stf.spill [r16]=f10 + stf.spill [r17]=f11 adds out0=16,sp // out0 = &sigscratch br.call.sptk.many rp=ia64_rt_sigreturn .ret19: .restore sp 0 @@ -1313,3 +1452,6 @@ data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall + data8 ia64_ni_syscall + + .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff -Nru a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h --- a/arch/ia64/kernel/entry.h Tue Jan 14 22:14:16 2003 +++ b/arch/ia64/kernel/entry.h Tue Jun 17 23:50:16 2003 @@ -4,8 +4,9 @@ * Preserved registers that are shared between code in ivt.S and entry.S. Be * careful not to step on these! */ -#define pKStk p2 /* will leave_kernel return to kernel-stacks? */ -#define pUStk p3 /* will leave_kernel return to user-stacks? */ +#define pLvSys p1 /* set 1 if leave from syscall; otherwise, set 0*/ +#define pKStk p2 /* will leave_{kernel,syscall} return to kernel-stacks? */ +#define pUStk p3 /* will leave_{kernel,syscall} return to user-stacks? */ #define pSys p4 /* are we processing a (synchronous) system call? */ #define pNonSys p5 /* complement of pSys */ @@ -13,6 +14,7 @@ #define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) #define PT_REGS_SAVES(off) \ + .unwabi 3, 'i'; \ .unwabi @svr4, 'i'; \ .fframe IA64_PT_REGS_SIZE+16+(off); \ .spillsp rp, PT(CR_IIP)+16+(off); \ diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S --- a/arch/ia64/kernel/fsys.S Fri Mar 7 04:39:25 2003 +++ b/arch/ia64/kernel/fsys.S Thu Jun 12 01:09:18 2003 @@ -14,6 +14,11 @@ #include #include #include +#include +#include +#include + +#include "entry.h" /* * See Documentation/ia64/fsys.txt for details on fsyscalls. @@ -38,6 +43,9 @@ */ ENTRY(fsys_ni_syscall) + .prologue + .altrp b6 + .body mov r8=ENOSYS mov r10=-1 MCKINLEY_E9_WORKAROUND @@ -45,6 +53,9 @@ END(fsys_ni_syscall) ENTRY(fsys_getpid) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 ;; ld4 r9=[r9] @@ -60,6 +71,9 @@ END(fsys_getpid) ENTRY(fsys_getppid) + .prologue + .altrp b6 + .body add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16 ;; ld8 r17=[r17] // r17 = current->group_leader @@ -105,6 +119,9 @@ END(fsys_getppid) ENTRY(fsys_set_tid_address) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 ;; ld4 r9=[r9] @@ -142,23 +159,33 @@ * we ought to either skip the ITC-based interpolation or run an ntp-like * daemon to keep the ITCs from drifting too far apart. */ + ENTRY(fsys_gettimeofday) + .prologue + .altrp b6 + .body add r9=TI_FLAGS+IA64_TASK_SIZE,r16 movl r3=THIS_CPU(cpu_info) mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc) - movl r19=xtime // xtime is a timespec struct - ;; - #ifdef CONFIG_SMP movl r10=__per_cpu_offset + movl r2=sal_platform_features ;; + + ld8 r2=[r2] + movl r19=xtime // xtime is a timespec struct + ld8 r10=[r10] // r10 <- __per_cpu_offset[0] - movl r21=cpu_info__per_cpu + movl r21=THIS_CPU(cpu_info) ;; add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id) + tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT +(p8) br.spnt.many fsys_fallback_syscall #else + ;; mov r10=r3 + movl r19=xtime // xtime is a timespec struct #endif ld4 r9=[r9] movl r17=xtime_lock @@ -305,262 +332,374 @@ br.ret.spnt.many b6 // return with r8 set to EINVAL END(fsys_gettimeofday) +ENTRY(fsys_fallback_syscall) + .prologue + .altrp b6 + .body + /* + * We only get here from light-weight syscall handlers. Thus, we already + * know that r15 contains a valid syscall number. No need to re-check. + */ + adds r17=-1024,r15 + movl r14=sys_call_table + ;; + shladd r18=r17,3,r14 + ;; + ld8 r18=[r18] // load normal (heavy-weight) syscall entry-point + mov r29=psr // read psr (12 cyc load latency) + mov r27=ar.rsc + mov r21=ar.fpsr + mov r26=ar.pfs +END(fsys_fallback_syscall) + /* FALL THROUGH */ +GLOBAL_ENTRY(fsys_bubble_down) + .prologue + .altrp b6 + .body + /* + * We get here for syscalls that don't have a lightweight handler. For those, we + * need to bubble down into the kernel and that requires setting up a minimal + * pt_regs structure, and initializing the CPU state more or less as if an + * interruption had occurred. To make syscall-restarts work, we setup pt_regs + * such that cr_iip points to the second instruction in syscall_via_break. + * Decrementing the IP hence will restart the syscall via break and not + * decrementing IP will return us to the caller, as usual. Note that we preserve + * the value of psr.pp rather than initializing it from dcr.pp. This makes it + * possible to distinguish fsyscall execution from other privileged execution. + * + * On entry: + * - normal fsyscall handler register usage, except that we also have: + * - r18: address of syscall entry point + * - r21: ar.fpsr + * - r26: ar.pfs + * - r27: ar.rsc + * - r29: psr + */ +# define PSR_PRESERVED_BITS (IA64_PSR_UP | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_PK \ + | IA64_PSR_DT | IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_RT \ + | IA64_PSR_IC) + /* + * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. The rest we have + * to synthesize. + */ +# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \ + | IA64_PSR_BN) + + invala + movl r8=PSR_ONE_BITS + + mov r25=ar.unat // save ar.unat (5 cyc) + movl r9=PSR_PRESERVED_BITS + + mov ar.rsc=0 // set enforced lazy mode, pl 0, little-endian, loadrs=0 + movl r28=__kernel_syscall_via_break + ;; + mov r23=ar.bspstore // save ar.bspstore (12 cyc) + mov r31=pr // save pr (2 cyc) + mov r20=r1 // save caller's gp in r20 + ;; + mov r2=r16 // copy current task addr to addl-addressable register + and r9=r9,r29 + mov r19=b6 // save b6 (2 cyc) + ;; + mov psr.l=r9 // slam the door (17 cyc to srlz.i) + or r29=r8,r29 // construct cr.ipsr value to save + addl r22=IA64_RBS_OFFSET,r2 // compute base of RBS + ;; + mov.m r24=ar.rnat // read ar.rnat (5 cyc lat) + lfetch.fault.excl.nt1 [r22] + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r2 + + // ensure previous insn group is issued before we stall for srlz.i: + ;; + srlz.i // ensure new psr.l has been established + ///////////////////////////////////////////////////////////////////////////// + ////////// from this point on, execution is not interruptible anymore + ///////////////////////////////////////////////////////////////////////////// + addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // compute base of memory stack + cmp.ne pKStk,pUStk=r0,r0 // set pKStk <- 0, pUStk <- 1 + ;; + st1 [r16]=r0 // clear current->thread.on_ustack flag + mov ar.bspstore=r22 // switch to kernel RBS + mov b6=r18 // copy syscall entry-point to b6 (7 cyc) + add r3=TI_FLAGS+IA64_TASK_SIZE,r2 + ;; + ld4 r3=[r3] // r2 = current_thread_info()->flags + mov r18=ar.bsp // save (kernel) ar.bsp (12 cyc) + mov ar.rsc=0x3 // set eager mode, pl 0, little-endian, loadrs=0 + br.call.sptk.many b7=ia64_syscall_setup + ;; + ssm psr.i + movl r2=ia64_ret_from_syscall + ;; + mov rp=r2 // set the real return addr + tbit.z p8,p0=r3,TIF_SYSCALL_TRACE + +(p8) br.call.sptk.many b6=b6 // ignore this return addr + br.cond.sptk ia64_trace_syscall +END(fsys_bubble_down) + .rodata .align 8 .globl fsyscall_table + + data8 fsys_bubble_down fsyscall_table: data8 fsys_ni_syscall - data8 fsys_fallback_syscall // exit // 1025 - data8 fsys_fallback_syscall // read - data8 fsys_fallback_syscall // write - data8 fsys_fallback_syscall // open - data8 fsys_fallback_syscall // close - data8 fsys_fallback_syscall // creat // 1030 - data8 fsys_fallback_syscall // link - data8 fsys_fallback_syscall // unlink - data8 fsys_fallback_syscall // execve - data8 fsys_fallback_syscall // chdir - data8 fsys_fallback_syscall // fchdir // 1035 - data8 fsys_fallback_syscall // utimes - data8 fsys_fallback_syscall // mknod - data8 fsys_fallback_syscall // chmod - data8 fsys_fallback_syscall // chown - data8 fsys_fallback_syscall // lseek // 1040 - data8 fsys_getpid + data8 0 // exit // 1025 + data8 0 // read + data8 0 // write + data8 0 // open + data8 0 // close + data8 0 // creat // 1030 + data8 0 // link + data8 0 // unlink + data8 0 // execve + data8 0 // chdir + data8 0 // fchdir // 1035 + data8 0 // utimes + data8 0 // mknod + data8 0 // chmod + data8 0 // chown + data8 0 // lseek // 1040 + data8 fsys_getpid // getpid data8 fsys_getppid // getppid - data8 fsys_fallback_syscall // mount - data8 fsys_fallback_syscall // umount - data8 fsys_fallback_syscall // setuid // 1045 - data8 fsys_fallback_syscall // getuid - data8 fsys_fallback_syscall // geteuid - data8 fsys_fallback_syscall // ptrace - data8 fsys_fallback_syscall // access - data8 fsys_fallback_syscall // sync // 1050 - data8 fsys_fallback_syscall // fsync - data8 fsys_fallback_syscall // fdatasync - data8 fsys_fallback_syscall // kill - data8 fsys_fallback_syscall // rename - data8 fsys_fallback_syscall // mkdir // 1055 - data8 fsys_fallback_syscall // rmdir - data8 fsys_fallback_syscall // dup - data8 fsys_fallback_syscall // pipe - data8 fsys_fallback_syscall // times - data8 fsys_fallback_syscall // brk // 1060 - data8 fsys_fallback_syscall // setgid - data8 fsys_fallback_syscall // getgid - data8 fsys_fallback_syscall // getegid - data8 fsys_fallback_syscall // acct - data8 fsys_fallback_syscall // ioctl // 1065 - data8 fsys_fallback_syscall // fcntl - data8 fsys_fallback_syscall // umask - data8 fsys_fallback_syscall // chroot - data8 fsys_fallback_syscall // ustat - data8 fsys_fallback_syscall // dup2 // 1070 - data8 fsys_fallback_syscall // setreuid - data8 fsys_fallback_syscall // setregid - data8 fsys_fallback_syscall // getresuid - data8 fsys_fallback_syscall // setresuid - data8 fsys_fallback_syscall // getresgid // 1075 - data8 fsys_fallback_syscall // setresgid - data8 fsys_fallback_syscall // getgroups - data8 fsys_fallback_syscall // setgroups - data8 fsys_fallback_syscall // getpgid - data8 fsys_fallback_syscall // setpgid // 1080 - data8 fsys_fallback_syscall // setsid - data8 fsys_fallback_syscall // getsid - data8 fsys_fallback_syscall // sethostname - data8 fsys_fallback_syscall // setrlimit - data8 fsys_fallback_syscall // getrlimit // 1085 - data8 fsys_fallback_syscall // getrusage + data8 0 // mount + data8 0 // umount + data8 0 // setuid // 1045 + data8 0 // getuid + data8 0 // geteuid + data8 0 // ptrace + data8 0 // access + data8 0 // sync // 1050 + data8 0 // fsync + data8 0 // fdatasync + data8 0 // kill + data8 0 // rename + data8 0 // mkdir // 1055 + data8 0 // rmdir + data8 0 // dup + data8 0 // pipe + data8 0 // times + data8 0 // brk // 1060 + data8 0 // setgid + data8 0 // getgid + data8 0 // getegid + data8 0 // acct + data8 0 // ioctl // 1065 + data8 0 // fcntl + data8 0 // umask + data8 0 // chroot + data8 0 // ustat + data8 0 // dup2 // 1070 + data8 0 // setreuid + data8 0 // setregid + data8 0 // getresuid + data8 0 // setresuid + data8 0 // getresgid // 1075 + data8 0 // setresgid + data8 0 // getgroups + data8 0 // setgroups + data8 0 // getpgid + data8 0 // setpgid // 1080 + data8 0 // setsid + data8 0 // getsid + data8 0 // sethostname + data8 0 // setrlimit + data8 0 // getrlimit // 1085 + data8 0 // getrusage data8 fsys_gettimeofday // gettimeofday - data8 fsys_fallback_syscall // settimeofday - data8 fsys_fallback_syscall // select - data8 fsys_fallback_syscall // poll // 1090 - data8 fsys_fallback_syscall // symlink - data8 fsys_fallback_syscall // readlink - data8 fsys_fallback_syscall // uselib - data8 fsys_fallback_syscall // swapon - data8 fsys_fallback_syscall // swapoff // 1095 - data8 fsys_fallback_syscall // reboot - data8 fsys_fallback_syscall // truncate - data8 fsys_fallback_syscall // ftruncate - data8 fsys_fallback_syscall // fchmod - data8 fsys_fallback_syscall // fchown // 1100 - data8 fsys_fallback_syscall // getpriority - data8 fsys_fallback_syscall // setpriority - data8 fsys_fallback_syscall // statfs - data8 fsys_fallback_syscall // fstatfs - data8 fsys_fallback_syscall // gettid // 1105 - data8 fsys_fallback_syscall // semget - data8 fsys_fallback_syscall // semop - data8 fsys_fallback_syscall // semctl - data8 fsys_fallback_syscall // msgget - data8 fsys_fallback_syscall // msgsnd // 1110 - data8 fsys_fallback_syscall // msgrcv - data8 fsys_fallback_syscall // msgctl - data8 fsys_fallback_syscall // shmget - data8 fsys_fallback_syscall // shmat - data8 fsys_fallback_syscall // shmdt // 1115 - data8 fsys_fallback_syscall // shmctl - data8 fsys_fallback_syscall // syslog - data8 fsys_fallback_syscall // setitimer - data8 fsys_fallback_syscall // getitimer - data8 fsys_fallback_syscall // 1120 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // vhangup - data8 fsys_fallback_syscall // lchown - data8 fsys_fallback_syscall // remap_file_pages // 1125 - data8 fsys_fallback_syscall // wait4 - data8 fsys_fallback_syscall // sysinfo - data8 fsys_fallback_syscall // clone - data8 fsys_fallback_syscall // setdomainname - data8 fsys_fallback_syscall // newuname // 1130 - data8 fsys_fallback_syscall // adjtimex - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // init_module - data8 fsys_fallback_syscall // delete_module - data8 fsys_fallback_syscall // 1135 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // quotactl - data8 fsys_fallback_syscall // bdflush - data8 fsys_fallback_syscall // sysfs - data8 fsys_fallback_syscall // personality // 1140 - data8 fsys_fallback_syscall // afs_syscall - data8 fsys_fallback_syscall // setfsuid - data8 fsys_fallback_syscall // setfsgid - data8 fsys_fallback_syscall // getdents - data8 fsys_fallback_syscall // flock // 1145 - data8 fsys_fallback_syscall // readv - data8 fsys_fallback_syscall // writev - data8 fsys_fallback_syscall // pread64 - data8 fsys_fallback_syscall // pwrite64 - data8 fsys_fallback_syscall // sysctl // 1150 - data8 fsys_fallback_syscall // mmap - data8 fsys_fallback_syscall // munmap - data8 fsys_fallback_syscall // mlock - data8 fsys_fallback_syscall // mlockall - data8 fsys_fallback_syscall // mprotect // 1155 - data8 fsys_fallback_syscall // mremap - data8 fsys_fallback_syscall // msync - data8 fsys_fallback_syscall // munlock - data8 fsys_fallback_syscall // munlockall - data8 fsys_fallback_syscall // sched_getparam // 1160 - data8 fsys_fallback_syscall // sched_setparam - data8 fsys_fallback_syscall // sched_getscheduler - data8 fsys_fallback_syscall // sched_setscheduler - data8 fsys_fallback_syscall // sched_yield - data8 fsys_fallback_syscall // sched_get_priority_max // 1165 - data8 fsys_fallback_syscall // sched_get_priority_min - data8 fsys_fallback_syscall // sched_rr_get_interval - data8 fsys_fallback_syscall // nanosleep - data8 fsys_fallback_syscall // nfsservctl - data8 fsys_fallback_syscall // prctl // 1170 - data8 fsys_fallback_syscall // getpagesize - data8 fsys_fallback_syscall // mmap2 - data8 fsys_fallback_syscall // pciconfig_read - data8 fsys_fallback_syscall // pciconfig_write - data8 fsys_fallback_syscall // perfmonctl // 1175 - data8 fsys_fallback_syscall // sigaltstack - data8 fsys_fallback_syscall // rt_sigaction - data8 fsys_fallback_syscall // rt_sigpending - data8 fsys_fallback_syscall // rt_sigprocmask - data8 fsys_fallback_syscall // rt_sigqueueinfo // 1180 - data8 fsys_fallback_syscall // rt_sigreturn - data8 fsys_fallback_syscall // rt_sigsuspend - data8 fsys_fallback_syscall // rt_sigtimedwait - data8 fsys_fallback_syscall // getcwd - data8 fsys_fallback_syscall // capget // 1185 - data8 fsys_fallback_syscall // capset - data8 fsys_fallback_syscall // sendfile - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // socket // 1190 - data8 fsys_fallback_syscall // bind - data8 fsys_fallback_syscall // connect - data8 fsys_fallback_syscall // listen - data8 fsys_fallback_syscall // accept - data8 fsys_fallback_syscall // getsockname // 1195 - data8 fsys_fallback_syscall // getpeername - data8 fsys_fallback_syscall // socketpair - data8 fsys_fallback_syscall // send - data8 fsys_fallback_syscall // sendto - data8 fsys_fallback_syscall // recv // 1200 - data8 fsys_fallback_syscall // recvfrom - data8 fsys_fallback_syscall // shutdown - data8 fsys_fallback_syscall // setsockopt - data8 fsys_fallback_syscall // getsockopt - data8 fsys_fallback_syscall // sendmsg // 1205 - data8 fsys_fallback_syscall // recvmsg - data8 fsys_fallback_syscall // pivot_root - data8 fsys_fallback_syscall // mincore - data8 fsys_fallback_syscall // madvise - data8 fsys_fallback_syscall // newstat // 1210 - data8 fsys_fallback_syscall // newlstat - data8 fsys_fallback_syscall // newfstat - data8 fsys_fallback_syscall // clone2 - data8 fsys_fallback_syscall // getdents64 - data8 fsys_fallback_syscall // getunwind // 1215 - data8 fsys_fallback_syscall // readahead - data8 fsys_fallback_syscall // setxattr - data8 fsys_fallback_syscall // lsetxattr - data8 fsys_fallback_syscall // fsetxattr - data8 fsys_fallback_syscall // getxattr // 1220 - data8 fsys_fallback_syscall // lgetxattr - data8 fsys_fallback_syscall // fgetxattr - data8 fsys_fallback_syscall // listxattr - data8 fsys_fallback_syscall // llistxattr - data8 fsys_fallback_syscall // flistxattr // 1225 - data8 fsys_fallback_syscall // removexattr - data8 fsys_fallback_syscall // lremovexattr - data8 fsys_fallback_syscall // fremovexattr - data8 fsys_fallback_syscall // tkill - data8 fsys_fallback_syscall // futex // 1230 - data8 fsys_fallback_syscall // sched_setaffinity - data8 fsys_fallback_syscall // sched_getaffinity + data8 0 // settimeofday + data8 0 // select + data8 0 // poll // 1090 + data8 0 // symlink + data8 0 // readlink + data8 0 // uselib + data8 0 // swapon + data8 0 // swapoff // 1095 + data8 0 // reboot + data8 0 // truncate + data8 0 // ftruncate + data8 0 // fchmod + data8 0 // fchown // 1100 + data8 0 // getpriority + data8 0 // setpriority + data8 0 // statfs + data8 0 // fstatfs + data8 0 // gettid // 1105 + data8 0 // semget + data8 0 // semop + data8 0 // semctl + data8 0 // msgget + data8 0 // msgsnd // 1110 + data8 0 // msgrcv + data8 0 // msgctl + data8 0 // shmget + data8 0 // shmat + data8 0 // shmdt // 1115 + data8 0 // shmctl + data8 0 // syslog + data8 0 // setitimer + data8 0 // getitimer + data8 0 // 1120 + data8 0 + data8 0 + data8 0 // vhangup + data8 0 // lchown + data8 0 // remap_file_pages // 1125 + data8 0 // wait4 + data8 0 // sysinfo + data8 0 // clone + data8 0 // setdomainname + data8 0 // newuname // 1130 + data8 0 // adjtimex + data8 0 + data8 0 // init_module + data8 0 // delete_module + data8 0 // 1135 + data8 0 + data8 0 // quotactl + data8 0 // bdflush + data8 0 // sysfs + data8 0 // personality // 1140 + data8 0 // afs_syscall + data8 0 // setfsuid + data8 0 // setfsgid + data8 0 // getdents + data8 0 // flock // 1145 + data8 0 // readv + data8 0 // writev + data8 0 // pread64 + data8 0 // pwrite64 + data8 0 // sysctl // 1150 + data8 0 // mmap + data8 0 // munmap + data8 0 // mlock + data8 0 // mlockall + data8 0 // mprotect // 1155 + data8 0 // mremap + data8 0 // msync + data8 0 // munlock + data8 0 // munlockall + data8 0 // sched_getparam // 1160 + data8 0 // sched_setparam + data8 0 // sched_getscheduler + data8 0 // sched_setscheduler + data8 0 // sched_yield + data8 0 // sched_get_priority_max // 1165 + data8 0 // sched_get_priority_min + data8 0 // sched_rr_get_interval + data8 0 // nanosleep + data8 0 // nfsservctl + data8 0 // prctl // 1170 + data8 0 // getpagesize + data8 0 // mmap2 + data8 0 // pciconfig_read + data8 0 // pciconfig_write + data8 0 // perfmonctl // 1175 + data8 0 // sigaltstack + data8 0 // rt_sigaction + data8 0 // rt_sigpending + data8 0 // rt_sigprocmask + data8 0 // rt_sigqueueinfo // 1180 + data8 0 // rt_sigreturn + data8 0 // rt_sigsuspend + data8 0 // rt_sigtimedwait + data8 0 // getcwd + data8 0 // capget // 1185 + data8 0 // capset + data8 0 // sendfile + data8 0 + data8 0 + data8 0 // socket // 1190 + data8 0 // bind + data8 0 // connect + data8 0 // listen + data8 0 // accept + data8 0 // getsockname // 1195 + data8 0 // getpeername + data8 0 // socketpair + data8 0 // send + data8 0 // sendto + data8 0 // recv // 1200 + data8 0 // recvfrom + data8 0 // shutdown + data8 0 // setsockopt + data8 0 // getsockopt + data8 0 // sendmsg // 1205 + data8 0 // recvmsg + data8 0 // pivot_root + data8 0 // mincore + data8 0 // madvise + data8 0 // newstat // 1210 + data8 0 // newlstat + data8 0 // newfstat + data8 0 // clone2 + data8 0 // getdents64 + data8 0 // getunwind // 1215 + data8 0 // readahead + data8 0 // setxattr + data8 0 // lsetxattr + data8 0 // fsetxattr + data8 0 // getxattr // 1220 + data8 0 // lgetxattr + data8 0 // fgetxattr + data8 0 // listxattr + data8 0 // llistxattr + data8 0 // flistxattr // 1225 + data8 0 // removexattr + data8 0 // lremovexattr + data8 0 // fremovexattr + data8 0 // tkill + data8 0 // futex // 1230 + data8 0 // sched_setaffinity + data8 0 // sched_getaffinity data8 fsys_set_tid_address // set_tid_address - data8 fsys_fallback_syscall // unused - data8 fsys_fallback_syscall // unused // 1235 - data8 fsys_fallback_syscall // exit_group - data8 fsys_fallback_syscall // lookup_dcookie - data8 fsys_fallback_syscall // io_setup - data8 fsys_fallback_syscall // io_destroy - data8 fsys_fallback_syscall // io_getevents // 1240 - data8 fsys_fallback_syscall // io_submit - data8 fsys_fallback_syscall // io_cancel - data8 fsys_fallback_syscall // epoll_create - data8 fsys_fallback_syscall // epoll_ctl - data8 fsys_fallback_syscall // epoll_wait // 1245 - data8 fsys_fallback_syscall // restart_syscall - data8 fsys_fallback_syscall // semtimedop - data8 fsys_fallback_syscall // timer_create - data8 fsys_fallback_syscall // timer_settime - data8 fsys_fallback_syscall // timer_gettime // 1250 - data8 fsys_fallback_syscall // timer_getoverrun - data8 fsys_fallback_syscall // timer_delete - data8 fsys_fallback_syscall // clock_settime - data8 fsys_fallback_syscall // clock_gettime - data8 fsys_fallback_syscall // clock_getres // 1255 - data8 fsys_fallback_syscall // clock_nanosleep - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1260 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1265 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1270 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall // 1275 - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall - data8 fsys_fallback_syscall + data8 0 // unused + data8 0 // unused // 1235 + data8 0 // exit_group + data8 0 // lookup_dcookie + data8 0 // io_setup + data8 0 // io_destroy + data8 0 // io_getevents // 1240 + data8 0 // io_submit + data8 0 // io_cancel + data8 0 // epoll_create + data8 0 // epoll_ctl + data8 0 // epoll_wait // 1245 + data8 0 // restart_syscall + data8 0 // semtimedop + data8 0 // timer_create + data8 0 // timer_settime + data8 0 // timer_gettime // 1250 + data8 0 // timer_getoverrun + data8 0 // timer_delete + data8 0 // clock_settime + data8 0 // clock_gettime + data8 0 // clock_getres // 1255 + data8 0 // clock_nanosleep + data8 0 + data8 0 + data8 0 + data8 0 // 1260 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1265 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1270 + data8 0 + data8 0 + data8 0 + data8 0 + data8 0 // 1275 + data8 0 + data8 0 + data8 0 + data8 0 + + .org fsyscall_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff -Nru a/arch/ia64/kernel/gate-data.S b/arch/ia64/kernel/gate-data.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/kernel/gate-data.S Thu Jun 12 01:09:19 2003 @@ -0,0 +1,3 @@ + .section .data.gate, "ax" + + .incbin "arch/ia64/kernel/gate.so" diff -Nru a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S --- a/arch/ia64/kernel/gate.S Mon May 12 18:59:21 2003 +++ b/arch/ia64/kernel/gate.S Tue Jun 17 23:50:16 2003 @@ -6,20 +6,47 @@ * David Mosberger-Tang */ +#include + #include +#include #include #include #include #include -#include - - .section .text.gate, "ax" -.start_gate: +/* + * We can't easily refer to symbols inside the kernel. To avoid full runtime relocation, + * complications with the linker (which likes to create PLT stubs for branches + * to targets outside the shared object) and to avoid multi-phase kernel builds, we + * simply create minimalistic "patch lists" in special ELF sections. + */ + .section ".data.patch.fsyscall_table", "a" + .previous +#define LOAD_FSYSCALL_TABLE(reg) \ +[1:] movl reg=0; \ + .xdata4 ".data.patch.fsyscall_table", 1b-. + + .section ".data.patch.brl_fsys_bubble_down", "a" + .previous +#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \ +[1:](pr)brl.cond.sptk 0; \ + .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-. -#ifdef CONFIG_FSYS - -#include +GLOBAL_ENTRY(__kernel_syscall_via_break) + .prologue + .altrp b6 + .body + /* + * Note: for (fast) syscall restart to work, the break instruction must be + * the first one in the bundle addressed by syscall_via_break. + */ +{ .mib + break 0x100000 + nop.i 0 + br.ret.sptk.many b6 +} +END(__kernel_syscall_via_break) /* * On entry: @@ -34,7 +61,8 @@ * all other "scratch" registers: undefined * all "preserved" registers: same as on entry */ -GLOBAL_ENTRY(syscall_via_epc) + +GLOBAL_ENTRY(__kernel_syscall_via_epc) .prologue .altrp b6 .body @@ -49,52 +77,50 @@ epc } ;; - rsm psr.be - movl r18=fsyscall_table + rsm psr.be // note: on McKinley "rsm psr.be/srlz.d" is slightly faster than "rum psr.be" + LOAD_FSYSCALL_TABLE(r14) - mov r16=IA64_KR(CURRENT) - mov r19=255 + mov r16=IA64_KR(CURRENT) // 12 cycle read latency + mov r19=NR_syscalls-1 ;; - shladd r18=r17,3,r18 - cmp.geu p6,p0=r19,r17 // (syscall > 0 && syscall <= 1024+255)? + shladd r18=r17,3,r14 + + srlz.d + cmp.ne p8,p0=r0,r0 // p8 <- FALSE + /* Note: if r17 is a NaT, p6 will be set to zero. */ + cmp.geu p6,p7=r19,r17 // (syscall > 0 && syscall < 1024+NR_syscalls)? ;; - srlz.d // ensure little-endian byteorder is in effect (p6) ld8 r18=[r18] + mov r29=psr // read psr (12 cyc load latency) + add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry ;; (p6) mov b7=r18 +(p6) tbit.z p8,p0=r18,0 +(p8) br.dptk.many b7 + + mov r27=ar.rsc + mov r21=ar.fpsr + mov r26=ar.pfs +/* + * brl.cond doesn't work as intended because the linker would convert this branch + * into a branch to a PLT. Perhaps there will be a way to avoid this with some + * future version of the linker. In the meantime, we just use an indirect branch + * instead. + */ +#ifdef CONFIG_ITANIUM +(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down + ;; +(p6) mov b7=r14 (p6) br.sptk.many b7 +#else + BRL_COND_FSYS_BUBBLE_DOWN(p6) +#endif mov r10=-1 mov r8=ENOSYS MCKINLEY_E9_WORKAROUND br.ret.sptk.many b6 -END(syscall_via_epc) - -GLOBAL_ENTRY(syscall_via_break) - .prologue - .altrp b6 - .body - break 0x100000 - br.ret.sptk.many b6 -END(syscall_via_break) - -GLOBAL_ENTRY(fsys_fallback_syscall) - /* - * It would be better/fsyser to do the SAVE_MIN magic directly here, but for now - * we simply fall back on doing a system-call via break. Good enough - * to get started. (Note: we have to do this through the gate page again, since - * the br.ret will switch us back to user-level privilege.) - * - * XXX Move this back to fsys.S after changing it over to avoid break 0x100000. - */ - movl r2=(syscall_via_break - .start_gate) + GATE_ADDR - ;; - MCKINLEY_E9_WORKAROUND - mov b7=r2 - br.ret.sptk.many b7 -END(fsys_fallback_syscall) - -#endif /* CONFIG_FSYS */ +END(__kernel_syscall_via_epc) # define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) # define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) @@ -145,7 +171,8 @@ */ #define SIGTRAMP_SAVES \ - .unwabi @svr4, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ + .unwabi 3, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \ + .unwabi @svr4, 's'; /* backwards compatibility with old unwinders (remove in v2.7) */ \ .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \ .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \ .savesp pr, PR_OFF+SIGCONTEXT_OFF; \ @@ -153,7 +180,7 @@ .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \ .vframesp SP_OFF+SIGCONTEXT_OFF -GLOBAL_ENTRY(ia64_sigtramp) +GLOBAL_ENTRY(__kernel_sigtramp) // describe the state that is active when we get here: .prologue SIGTRAMP_SAVES @@ -335,4 +362,4 @@ mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode br.cond.sptk back_from_restore_rbs -END(ia64_sigtramp) +END(__kernel_sigtramp) diff -Nru a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/kernel/gate.lds.S Sat Jun 14 00:38:59 2003 @@ -0,0 +1,95 @@ +/* + * Linker script for gate DSO. The gate pages are an ELF shared object prelinked to its + * virtual address, with only one read-only segment and one execute-only segment (both fit + * in one page). This script controls its layout. + */ + +#include + +#include + +SECTIONS +{ + . = GATE_ADDR + SIZEOF_HEADERS; + + .hash : { *(.hash) } :readable + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .dynamic : { *(.dynamic) } :readable :dynamic + + /* + * This linker script is used both with -r and with -shared. For the layouts to match, + * we need to skip more than enough space for the dynamic symbol table et al. If this + * amount is insufficient, ld -shared will barf. Just increase it here. + */ + . = GATE_ADDR + 0x500; + + .data.patch : { + __start_gate_mckinley_e9_patchlist = .; + *(.data.patch.mckinley_e9) + __end_gate_mckinley_e9_patchlist = .; + + __start_gate_vtop_patchlist = .; + *(.data.patch.vtop) + __end_gate_vtop_patchlist = .; + + __start_gate_fsyscall_patchlist = .; + *(.data.patch.fsyscall_table) + __end_gate_fsyscall_patchlist = .; + + __start_gate_brl_fsys_bubble_down_patchlist = .; + *(.data.patch.brl_fsys_bubble_down) + __end_gate_brl_fsys_bubble_down_patchlist = .; + } :readable + .IA_64.unwind_info : { *(.IA_64.unwind_info*) } + .IA_64.unwind : { *(.IA_64.unwind*) } :readable :unwind +#ifdef HAVE_BUGGY_SEGREL + .text (GATE_ADDR + PAGE_SIZE) : { *(.text) *(.text.*) } :readable +#else + . = ALIGN (PERCPU_PAGE_SIZE) + (. & (PERCPU_PAGE_SIZE - 1)); + .text : { *(.text) *(.text.*) } :epc +#endif + + /DISCARD/ : { + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(__ex_table) + } +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + readable PT_LOAD FILEHDR PHDRS FLAGS(4); /* PF_R */ +#ifndef HAVE_BUGGY_SEGREL + epc PT_LOAD FILEHDR PHDRS FLAGS(1); /* PF_X */ +#endif + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + unwind 0x70000001; /* PT_IA_64_UNWIND, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.5 { + global: + __kernel_syscall_via_break; + __kernel_syscall_via_epc; + __kernel_sigtramp; + + local: *; + }; +} + +/* The ELF entry point can be used to set the AT_SYSINFO value. */ +ENTRY(__kernel_syscall_via_epc) diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S Tue May 6 10:56:54 2003 +++ b/arch/ia64/kernel/head.S Thu May 15 04:45:02 2003 @@ -60,22 +60,42 @@ mov r4=r0 .body - /* - * Initialize the region register for region 7 and install a translation register - * that maps the kernel's text and data: - */ rsm psr.i | psr.ic - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (IA64_GRANULE_SHIFT << 2)) ;; srlz.i + ;; + /* + * Initialize kernel region registers: + * rr[5]: VHPT enabled, page size = PAGE_SHIFT + * rr[6]: VHPT disabled, page size = IA64_GRANULE_SHIFT + * rr[5]: VHPT disabled, page size = IA64_GRANULE_SHIFT + */ + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1) + movl r17=(5<<61) + mov r18=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) + movl r19=(6<<61) + mov r20=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2)) + movl r21=(7<<61) + ;; + mov rr[r17]=r16 + mov rr[r19]=r18 + mov rr[r21]=r20 + ;; + /* + * Now pin mappings into the TLB for kernel text and data + */ mov r18=KERNEL_TR_PAGE_SHIFT<<2 movl r17=KERNEL_START ;; - mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL) + mov r3=ip + movl r18=PAGE_KERNEL + ;; + dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT + ;; + or r18=r2,r18 ;; srlz.i ;; @@ -113,16 +133,6 @@ mov ar.fpsr=r2 ;; -#ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (IA64_GRANULE_SHIFT<<2) - movl r2=6<<61 - ;; - mov rr[r2]=r3 - ;; - srlz.i - ;; -#endif - #define isAP p2 // are we an Application Processor? #define isBP p3 // are we the Bootstrap Processor? @@ -143,12 +153,36 @@ movl r2=init_thread_union cmp.eq isBP,isAP=r0,r0 #endif - mov r16=KERNEL_TR_PAGE_NUM ;; + tpa r3=r2 // r3 == phys addr of task struct + // load mapping for stack (virtaddr in r2, physaddr in r3) + rsm psr.ic + movl r17=PAGE_KERNEL + ;; + srlz.d + dep r18=0,r3,0,12 + ;; + or r18=r17,r18 + dep r2=-1,r3,61,3 // IMVA of task + ;; + mov r17=rr[r2] + shr.u r16=r3,IA64_GRANULE_SHIFT + ;; + dep r17=0,r17,8,24 + ;; + mov cr.itir=r17 + mov cr.ifa=r2 + + mov r19=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r19]=r18 + ;; + ssm psr.ic + srlz.d + ;; // load the "current" pointer (r13) and ar.k6 with the current task mov IA64_KR(CURRENT)=r2 // virtual address - // initialize k4 to a safe value (64-128MB is mapped by TR_KERNEL) mov IA64_KR(CURRENT_STACK)=r16 mov r13=r2 /* @@ -665,14 +699,14 @@ END(__ia64_init_fpu) /* - * Switch execution mode from virtual to physical or vice versa. + * Switch execution mode from virtual to physical * * Inputs: * r16 = new psr to establish * * Note: RSE must already be in enforced lazy mode */ -GLOBAL_ENTRY(ia64_switch_mode) +GLOBAL_ENTRY(ia64_switch_mode_phys) { alloc r2=ar.pfs,0,0,0,0 rsm psr.i | psr.ic // disable interrupts and interrupt collection @@ -682,35 +716,86 @@ { flushrs // must be first insn in group srlz.i - shr.u r19=r15,61 // r19 <- top 3 bits of current IP } ;; mov cr.ipsr=r16 // set new PSR - add r3=1f-ia64_switch_mode,r15 - xor r15=0x7,r19 // flip the region bits + add r3=1f-ia64_switch_mode_phys,r15 mov r17=ar.bsp mov r14=rp // get return address into a general register + ;; - // switch RSE backing store: + // going to physical mode, use tpa to translate virt->phys + tpa r17=r17 + tpa r3=r3 + tpa sp=sp + tpa r14=r14 ;; - dep r17=r15,r17,61,3 // make ar.bsp physical or virtual + mov r18=ar.rnat // save ar.rnat - ;; mov ar.bspstore=r17 // this steps on ar.rnat - dep r3=r15,r3,61,3 // make rfi return address physical or virtual + mov cr.iip=r3 + mov cr.ifs=r0 ;; + mov ar.rnat=r18 // restore ar.rnat + rfi // must be last insn in group + ;; +1: mov rp=r14 + br.ret.sptk.many rp +END(ia64_switch_mode_phys) + +/* + * Switch execution mode from physical to virtual + * + * Inputs: + * r16 = new psr to establish + * + * Note: RSE must already be in enforced lazy mode + */ +GLOBAL_ENTRY(ia64_switch_mode_virt) + { + alloc r2=ar.pfs,0,0,0,0 + rsm psr.i | psr.ic // disable interrupts and interrupt collection + mov r15=ip + } + ;; + { + flushrs // must be first insn in group + srlz.i + } + ;; + mov cr.ipsr=r16 // set new PSR + add r3=1f-ia64_switch_mode_virt,r15 + + mov r17=ar.bsp + mov r14=rp // get return address into a general register + ;; + + // going to virtual + // - for code addresses, set upper bits of addr to KERNEL_START + // - for stack addresses, set upper 3 bits to 0xe.... Dont change any of the + // lower bits since we want it to stay identity mapped + movl r18=KERNEL_START + dep r3=0,r3,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r14=0,r14,KERNEL_TR_PAGE_SHIFT,64-KERNEL_TR_PAGE_SHIFT + dep r17=-1,r17,61,3 + dep sp=-1,sp,61,3 + ;; + or r3=r3,r18 + or r14=r14,r18 + ;; + + mov r18=ar.rnat // save ar.rnat + mov ar.bspstore=r17 // this steps on ar.rnat mov cr.iip=r3 mov cr.ifs=r0 - dep sp=r15,sp,61,3 // make stack pointer physical or virtual ;; mov ar.rnat=r18 // restore ar.rnat - dep r14=r15,r14,61,3 // make function return address physical or virtual rfi // must be last insn in group ;; 1: mov rp=r14 br.ret.sptk.many rp -END(ia64_switch_mode) +END(ia64_switch_mode_virt) #ifdef CONFIG_IA64_BRL_EMU @@ -753,7 +838,7 @@ * r29 - available for use. * r30 - available for use. * r31 - address of lock, available for use. - * b7 - return address + * b6 - return address * p14 - available for use. * * If you patch this code to use more registers, do not forget to update diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c --- a/arch/ia64/kernel/ia64_ksyms.c Sat May 10 03:13:39 2003 +++ b/arch/ia64/kernel/ia64_ksyms.c Mon Jun 16 14:26:17 2003 @@ -65,6 +65,9 @@ #include EXPORT_SYMBOL(cpu_info__per_cpu); +#ifdef CONFIG_SMP +EXPORT_SYMBOL(__per_cpu_offset); +#endif EXPORT_SYMBOL(kernel_thread); #include @@ -88,6 +91,7 @@ EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_single); EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(phys_cpu_present_map); EXPORT_SYMBOL(ia64_cpu_to_sapicid); #else /* !CONFIG_SMP */ @@ -124,6 +128,18 @@ EXPORT_SYMBOL_NOVERS(__moddi3); EXPORT_SYMBOL_NOVERS(__umoddi3); +#if defined(CONFIG_MD_RAID5) || defined(CONFIG_MD_RAID5_MODULE) +extern void xor_ia64_2(void); +extern void xor_ia64_3(void); +extern void xor_ia64_4(void); +extern void xor_ia64_5(void); + +EXPORT_SYMBOL_NOVERS(xor_ia64_2); +EXPORT_SYMBOL_NOVERS(xor_ia64_3); +EXPORT_SYMBOL_NOVERS(xor_ia64_4); +EXPORT_SYMBOL_NOVERS(xor_ia64_5); +#endif + extern unsigned long ia64_iobase; EXPORT_SYMBOL(ia64_iobase); @@ -147,10 +163,15 @@ EXPORT_SYMBOL(ia64_mv); #endif EXPORT_SYMBOL(machvec_noop); +EXPORT_SYMBOL(machvec_memory_fence); +EXPORT_SYMBOL(zero_page_memmap_ptr); #ifdef CONFIG_PERFMON #include -EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem); -EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem); +EXPORT_SYMBOL(pfm_register_buffer_fmt); +EXPORT_SYMBOL(pfm_unregister_buffer_fmt); +EXPORT_SYMBOL(pfm_mod_fast_read_pmds); +EXPORT_SYMBOL(pfm_mod_read_pmds); +EXPORT_SYMBOL(pfm_mod_write_pmcs); #endif #ifdef CONFIG_NUMA @@ -169,10 +190,25 @@ EXPORT_SYMBOL(unw_access_ar); EXPORT_SYMBOL(unw_access_pr); -#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) -extern void ia64_spinlock_contention_pre3_4 (void); +#ifdef CONFIG_SMP +# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +/* + * This is not a normal routine and we don't want a function descriptor for it, so we use + * a fake declaration here. + */ +extern char ia64_spinlock_contention_pre3_4; EXPORT_SYMBOL(ia64_spinlock_contention_pre3_4); -#else -extern void ia64_spinlock_contention (void); +# else +/* + * This is not a normal routine and we don't want a function descriptor for it, so we use + * a fake declaration here. + */ +extern char ia64_spinlock_contention; EXPORT_SYMBOL(ia64_spinlock_contention); +# endif #endif + +EXPORT_SYMBOL(ia64_max_iommu_merge_mask); + +#include +EXPORT_SYMBOL(pm_idle); diff -Nru a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c --- a/arch/ia64/kernel/init_task.c Wed Feb 12 00:11:32 2003 +++ b/arch/ia64/kernel/init_task.c Wed Jun 4 19:22:35 2003 @@ -36,7 +36,7 @@ unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)]; } init_thread_union __attribute__((section(".data.init_task"))) = {{ .task = INIT_TASK(init_thread_union.s.task), - .thread_info = INIT_THREAD_INFO(init_thread_union.s.thread_info) + .thread_info = INIT_THREAD_INFO(init_thread_union.s.task) }}; asm (".global init_task; init_task = init_thread_union"); diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Thu Jun 5 23:36:37 2003 +++ b/arch/ia64/kernel/irq.c Tue Jun 17 23:50:17 2003 @@ -65,7 +65,7 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { +irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = { .status = IRQ_DISABLED, .handler = &no_irq_type, @@ -235,7 +235,6 @@ { int status = 1; /* Force the "do bottom halves" bit */ int retval = 0; - struct irqaction *first_action = action; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -248,30 +247,88 @@ if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); - if (retval != 1) { - static int count = 100; - if (count) { - count--; - if (retval) { - printk("irq event %d: bogus retval mask %x\n", - irq, retval); - } else { - printk("irq %d: nobody cared!\n", irq); - } - dump_stack(); - printk("handlers:\n"); - action = first_action; - do { - printk("[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; - } while (action); - } + return retval; +} + +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; + + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); } - return status; + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; } /* @@ -380,21 +437,24 @@ * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int cpu; irq_desc_t *desc = irq_desc(irq); struct irqaction * action; + irqreturn_t action_ret; unsigned int status; + int cpu; irq_enter(); - cpu = smp_processor_id(); + cpu = smp_processor_id(); /* for CONFIG_PREEMPT, this must come after irq_enter()! */ kstat_cpu(cpu).irqs[irq]++; if (desc->status & IRQ_PER_CPU) { /* no locking required for CPU-local interrupts: */ desc->handler->ack(irq); - handle_IRQ_event(irq, regs, desc->action); + action_ret = handle_IRQ_event(irq, regs, desc->action); desc->handler->end(irq); + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); } else { spin_lock(&desc->lock); desc->handler->ack(irq); @@ -438,9 +498,10 @@ */ for (;;) { spin_unlock(&desc->lock); - handle_IRQ_event(irq, regs, action); + action_ret = handle_IRQ_event(irq, regs, action); spin_lock(&desc->lock); - + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; diff -Nru a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S --- a/arch/ia64/kernel/ivt.S Sat Feb 15 04:39:48 2003 +++ b/arch/ia64/kernel/ivt.S Thu Jun 12 01:09:18 2003 @@ -1,9 +1,14 @@ /* * arch/ia64/kernel/ivt.S * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * Stephane Eranian * David Mosberger + * Copyright (C) 2000, 2002-2003 Intel Co + * Asit Mallick + * Suresh Siddha + * Kenneth Chen + * Fenghua Yu * * 00/08/23 Asit Mallick TLB handling for SMP * 00/12/20 David Mosberger-Tang DTLB/ITLB handler now uses virtual PT. @@ -122,8 +127,11 @@ 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 -(p6) movl r19=__pa(swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + srlz.d + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ;; @@ -415,8 +423,11 @@ shr.u r18=r16,PGDIR_SHIFT // get bits 33-63 of faulting address ;; (p7) dep r17=r17,r19,(PAGE_SHIFT-3),3 // put region number bits in place + srlz.d -(p6) movl r19=__pa(swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + LOAD_PHYSICAL(p6, r19, swapper_pg_dir) // region 5 is rooted at swapper_pg_dir + + .pred.rel "mutex", p6, p7 (p6) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT (p7) shr.u r21=r21,PGDIR_SHIFT+PAGE_SHIFT-3 ;; @@ -622,103 +633,95 @@ ///////////////////////////////////////////////////////////////////////////////////////// // 0x2c00 Entry 11 (size 64 bundles) Break instruction (33) ENTRY(break_fault) + /* + * The streamlined system call entry/exit paths only save/restore the initial part + * of pt_regs. This implies that the callers of system-calls must adhere to the + * normal procedure calling conventions. + * + * Registers to be saved & restored: + * CR registers: cr.ipsr, cr.iip, cr.ifs + * AR registers: ar.unat, ar.pfs, ar.rsc, ar.rnat, ar.bspstore, ar.fpsr + * others: pr, b0, b6, loadrs, r1, r11, r12, r13, r15 + * Registers to be restored only: + * r8-r11: output value from the system call. + * + * During system call exit, scratch registers (including r15) are modified/cleared + * to prevent leaking bits from kernel to user level. + */ DBG_FAULT(11) - mov r16=cr.iim - mov r17=__IA64_BREAK_SYSCALL - mov r31=pr // prepare to save predicates + mov r16=IA64_KR(CURRENT) // r16 = current task; 12 cycle read lat. + mov r17=cr.iim + mov r18=__IA64_BREAK_SYSCALL + mov r21=ar.fpsr + mov r29=cr.ipsr + mov r19=b6 + mov r25=ar.unat + mov r27=ar.rsc + mov r26=ar.pfs + mov r28=cr.iip + mov r31=pr // prepare to save predicates + mov r20=r1 ;; - cmp.eq p0,p7=r16,r17 // is this a system call? (p7 <- false, if so) + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 + cmp.eq p0,p7=r18,r17 // is this a system call? (p7 <- false, if so) (p7) br.cond.spnt non_syscall + ;; + ld1 r17=[r16] // load current->thread.on_ustack flag + st1 [r16]=r0 // clear current->thread.on_ustack flag + add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT + ;; + invala - SAVE_MIN // uses r31; defines r2: + /* adjust return address so we skip over the break instruction: */ - ssm psr.ic | PSR_DEFAULT_BITS + extr.u r8=r29,41,2 // extract ei field from cr.ipsr ;; - srlz.i // guarantee that interruption collection is on - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + cmp.eq p6,p7=2,r8 // isr.ei==2? + mov r2=r1 // setup r2 for ia64_syscall_setup ;; -(p15) ssm psr.i // restore psr.i - adds r8=(IA64_PT_REGS_R8_OFFSET-IA64_PT_REGS_R16_OFFSET),r2 +(p6) mov r8=0 // clear ei to 0 +(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped +(p7) adds r8=1,r8 // increment ei to next slot ;; - stf8 [r8]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) - adds r3=8,r2 // set up second base pointer for SAVE_REST + cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already? + dep r29=r8,r29,41,2 // insert new ei into cr.ipsr ;; - SAVE_REST - br.call.sptk.many rp=demine_args // clear NaT bits in (potential) syscall args - mov r3=255 - adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + // switch from user to kernel RBS: + MINSTATE_START_SAVE_MIN_VIRT + br.call.sptk.many b7=ia64_syscall_setup ;; - cmp.geu p6,p7=r3,r15 // (syscall > 0 && syscall <= 1024+255) ? - movl r16=sys_call_table + MINSTATE_END_SAVE_MIN_VIRT // switch to bank 1 + ssm psr.ic | PSR_DEFAULT_BITS ;; -(p6) shladd r16=r15,3,r16 - movl r15=ia64_ret_from_syscall -(p7) adds r16=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall + srlz.i // guarantee that interruption collection is on ;; - ld8 r16=[r16] // load address of syscall entry point - mov rp=r15 // set the real return addr +(p15) ssm psr.i // restore psr.i ;; - mov b6=r16 - - // arrange things so we skip over break instruction when returning: + mov r3=NR_syscalls - 1 + movl r16=sys_call_table - adds r16=16,sp // get pointer to cr_ipsr - adds r17=24,sp // get pointer to cr_iip - add r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld8 r18=[r16] // fetch cr_ipsr - ld4 r2=[r2] // r2 = current_thread_info()->flags + adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 + movl r2=ia64_ret_from_syscall ;; - ld8 r19=[r17] // fetch cr_iip - extr.u r20=r18,41,2 // extract ei field + shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024) + cmp.geu p0,p7=r3,r15 // (syscall > 0 && syscall < 1024 + NR_syscalls) ? + mov rp=r2 // set the real return addr ;; - cmp.eq p6,p7=2,r20 // isr.ei==2? - adds r19=16,r19 // compute address of next bundle +(p7) add r20=(__NR_ni_syscall-1024)*8,r16 // force __NR_ni_syscall + add r2=TI_FLAGS+IA64_TASK_SIZE,r13 ;; -(p6) mov r20=0 // clear ei to 0 -(p7) adds r20=1,r20 // increment ei to next slot + ld8 r20=[r20] // load address of syscall entry point + ld4 r2=[r2] // r2 = current_thread_info()->flags ;; -(p6) st8 [r17]=r19 // store new cr.iip if cr.isr.ei wrapped around - dep r18=r20,r18,41,2 // insert new ei into cr.isr tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + mov b6=r20 ;; - st8 [r16]=r18 // store new value for cr.isr - (p8) br.call.sptk.many b6=b6 // ignore this return addr br.cond.sptk ia64_trace_syscall // NOT REACHED END(break_fault) -ENTRY_MIN_ALIGN(demine_args) - alloc r2=ar.pfs,8,0,0,0 - tnat.nz p8,p0=in0 - tnat.nz p9,p0=in1 - ;; -(p8) mov in0=-1 - tnat.nz p10,p0=in2 - tnat.nz p11,p0=in3 - -(p9) mov in1=-1 - tnat.nz p12,p0=in4 - tnat.nz p13,p0=in5 - ;; -(p10) mov in2=-1 - tnat.nz p14,p0=in6 - tnat.nz p15,p0=in7 - -(p11) mov in3=-1 - tnat.nz p8,p0=r15 // demining r15 is not a must, but it is safer - -(p12) mov in4=-1 -(p13) mov in5=-1 - ;; -(p14) mov in6=-1 -(p15) mov in7=-1 -(p8) mov r15=-1 - br.ret.sptk.many rp -END(demine_args) - .org ia64_ivt+0x3000 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) @@ -726,7 +729,6 @@ DBG_FAULT(12) mov r31=pr // prepare to save predicates ;; - SAVE_MIN_WITH_COVER // uses r31; defines r2 and r3 ssm psr.ic | PSR_DEFAULT_BITS ;; @@ -739,7 +741,7 @@ mov out0=cr.ivr // pass cr.ivr as first arg add out1=16,sp // pass pointer to pt_regs as second arg ;; - srlz.d // make sure we see the effect of cr.ivr + srlz.d // make sure we see the effect of cr.ivr movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -758,6 +760,131 @@ DBG_FAULT(14) FAULT(14) + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + * + * ia64_syscall_setup() is a separate subroutine so that it can + * allocate stacked registers so it can safely demine any + * potential NaT values from the input registers. + * + * On entry: + * - executing on bank 0 or bank 1 register set (doesn't matter) + * - r1: stack pointer + * - r2: current task pointer + * - r3: preserved + * - r11: original contents (saved ar.pfs to be saved) + * - r12: original contents (sp to be saved) + * - r13: original contents (tp to be saved) + * - r15: original contents (syscall # to be saved) + * - r18: saved bsp (after switching to kernel stack) + * - r19: saved b6 + * - r20: saved r1 (gp) + * - r21: saved ar.fpsr + * - r22: kernel's register backing store base (krbs_base) + * - r23: saved ar.bspstore + * - r24: saved ar.rnat + * - r25: saved ar.unat + * - r26: saved ar.pfs + * - r27: saved ar.rsc + * - r28: saved cr.iip + * - r29: saved cr.ipsr + * - r31: saved pr + * - b0: original contents (to be saved) + * On exit: + * - executing on bank 1 registers + * - psr.ic enabled, interrupts restored + * - r1: kernel's gp + * - r3: preserved (same as on entry) + * - r12: points to kernel stack + * - r13: points to current task + * - p15: TRUE if interrupts need to be re-enabled + * - ar.fpsr: set to kernel settings + */ +GLOBAL_ENTRY(ia64_syscall_setup) +#if PT(B6) != 0 +# error This code assumes that b6 is the first field in pt_regs. +#endif + st8 [r1]=r19 // save b6 + add r16=PT(CR_IPSR),r1 // initialize first base pointer + add r17=PT(R11),r1 // initialize second base pointer + ;; + alloc r19=ar.pfs,8,0,0,0 // ensure in0-in7 are writable + st8 [r16]=r29,PT(CR_IFS)-PT(CR_IPSR) // save cr.ipsr + tnat.nz p8,p0=in0 + + st8.spill [r17]=r11,PT(CR_IIP)-PT(R11) // save r11 + tnat.nz p9,p0=in1 +(pKStk) mov r18=r0 // make sure r18 isn't NaT + ;; + + st8 [r17]=r28,PT(AR_UNAT)-PT(CR_IIP) // save cr.iip + mov r28=b0 // save b0 (2 cyc) +(p8) mov in0=-1 + ;; + + st8 [r16]=r0,PT(AR_PFS)-PT(CR_IFS) // clear cr.ifs + st8 [r17]=r25,PT(AR_RSC)-PT(AR_UNAT) // save ar.unat +(p9) mov in1=-1 + ;; + + st8 [r16]=r26,PT(AR_RNAT)-PT(AR_PFS) // save ar.pfs + st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc + tnat.nz p10,p0=in2 + +(pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 + tbit.nz p15,p0=r29,IA64_PSR_I_BIT + tnat.nz p11,p0=in3 + ;; +(pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field +(pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field +(p10) mov in2=-1 + +(p11) mov in3=-1 + tnat.nz p12,p0=in4 + tnat.nz p13,p0=in5 + ;; +(pUStk) st8 [r16]=r24,PT(PR)-PT(AR_RNAT) // save ar.rnat +(pUStk) st8 [r17]=r23,PT(B0)-PT(AR_BSPSTORE) // save ar.bspstore + shl r18=r18,16 // compute ar.rsc to be used for "loadrs" + ;; + st8 [r16]=r31,PT(LOADRS)-PT(PR) // save predicates + st8 [r17]=r28,PT(R1)-PT(B0) // save b0 +(p12) mov in4=-1 + ;; + st8 [r16]=r18,PT(R12)-PT(LOADRS) // save ar.rsc value for "loadrs" + st8.spill [r17]=r20,PT(R13)-PT(R1) // save original r1 +(p13) mov in5=-1 + ;; + +.mem.offset 0,0; st8.spill [r16]=r12,PT(AR_FPSR)-PT(R12) // save r12 +.mem.offset 8,0; st8.spill [r17]=r13,PT(R15)-PT(R13) // save r13 + tnat.nz p14,p0=in6 + ;; + st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr + st8.spill [r17]=r15 // save r15 + tnat.nz p8,p0=in7 + ;; + stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) + adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) +(p14) mov in6=-1 + + mov r13=r2 // establish `current' + movl r1=__gp // establish kernel global pointer + ;; +(p8) mov in7=-1 + tnat.nz p9,p0=r15 + + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + movl r17=FPSR_DEFAULT + ;; + mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value +(p9) mov r15=-1 + br.ret.sptk.many b7 +END(ia64_syscall_setup) + .org ia64_ivt+0x3c00 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3c00 Entry 15 (size 64 bundles) Reserved @@ -809,90 +936,6 @@ DBG_FAULT(16) FAULT(16) -#ifdef CONFIG_IA32_SUPPORT - - /* - * There is no particular reason for this code to be here, other than that - * there happens to be space here that would go unused otherwise. If this - * fault ever gets "unreserved", simply moved the following code to a more - * suitable spot... - */ - - // IA32 interrupt entry point - -ENTRY(dispatch_to_ia32_handler) - SAVE_MIN - ;; - mov r14=cr.isr - ssm psr.ic | PSR_DEFAULT_BITS - ;; - srlz.i // guarantee that interruption collection is on - ;; -(p15) ssm psr.i - adds r3=8,r2 // Base pointer for SAVE_REST - ;; - SAVE_REST - ;; - mov r15=0x80 - shr r14=r14,16 // Get interrupt number - ;; - cmp.ne p6,p0=r14,r15 -(p6) br.call.dpnt.many b6=non_ia32_syscall - - adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions - adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp - ;; - cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 - st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) - ;; - alloc r15=ar.pfs,0,0,6,0 // must first in an insn group - ;; - ld4 r8=[r14],8 // r8 == eax (syscall number) - mov r15=250 // number of entries in ia32 system call table - ;; - cmp.ltu.unc p6,p7=r8,r15 - ld4 out1=[r14],8 // r9 == ecx - ;; - ld4 out2=[r14],8 // r10 == edx - ;; - ld4 out0=[r14] // r11 == ebx - adds r14=(IA64_PT_REGS_R8_OFFSET-(8*3)) + 16,sp - ;; - ld4 out5=[r14],8 // r13 == ebp - ;; - ld4 out3=[r14],8 // r14 == esi - adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 - ;; - ld4 out4=[r14] // r15 == edi - movl r16=ia32_syscall_table - ;; -(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number - ld4 r2=[r2] // r2 = current_thread_info()->flags - ;; - ld8 r16=[r16] - tbit.z p8,p0=r2,TIF_SYSCALL_TRACE - ;; - mov b6=r16 - movl r15=ia32_ret_from_syscall - ;; - mov rp=r15 -(p8) br.call.sptk.many b6=b6 - br.cond.sptk ia32_trace_syscall - -non_ia32_syscall: - alloc r15=ar.pfs,0,0,2,0 - mov out0=r14 // interrupt # - add out1=16,sp // pointer to pt_regs - ;; // avoid WAW on CFM - br.call.sptk.many rp=ia32_bad_interrupt -.ret1: movl r15=ia64_leave_kernel - ;; - mov rp=r15 - br.ret.sptk.many rp -END(dispatch_to_ia32_handler) - -#endif /* CONFIG_IA32_SUPPORT */ - .org ia64_ivt+0x4400 ///////////////////////////////////////////////////////////////////////////////////////// // 0x4400 Entry 17 (size 64 bundles) Reserved @@ -1428,3 +1471,89 @@ // 0x7f00 Entry 67 (size 16 bundles) Reserved DBG_FAULT(67) FAULT(67) + +#ifdef CONFIG_IA32_SUPPORT + + /* + * There is no particular reason for this code to be here, other than that + * there happens to be space here that would go unused otherwise. If this + * fault ever gets "unreserved", simply moved the following code to a more + * suitable spot... + */ + + // IA32 interrupt entry point + +ENTRY(dispatch_to_ia32_handler) + SAVE_MIN + ;; + mov r14=cr.isr + ssm psr.ic | PSR_DEFAULT_BITS + ;; + srlz.i // guarantee that interruption collection is on + ;; +(p15) ssm psr.i + adds r3=8,r2 // Base pointer for SAVE_REST + ;; + SAVE_REST + ;; + mov r15=0x80 + shr r14=r14,16 // Get interrupt number + ;; + cmp.ne p6,p0=r14,r15 +(p6) br.call.dpnt.many b6=non_ia32_syscall + + adds r14=IA64_PT_REGS_R8_OFFSET + 16,sp // 16 byte hole per SW conventions + adds r15=IA64_PT_REGS_R1_OFFSET + 16,sp + ;; + cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 + ld8 r8=[r14] // get r8 + ;; + st8 [r15]=r8 // save original EAX in r1 (IA32 procs don't use the GP) + ;; + alloc r15=ar.pfs,0,0,6,0 // must first in an insn group + ;; + ld4 r8=[r14],8 // r8 == eax (syscall number) + mov r15=250 // number of entries in ia32 system call table + ;; + cmp.ltu.unc p6,p7=r8,r15 + ld4 out1=[r14],8 // r9 == ecx + ;; + ld4 out2=[r14],8 // r10 == edx + ;; + ld4 out0=[r14] // r11 == ebx + adds r14=(IA64_PT_REGS_R13_OFFSET) + 16,sp + ;; + ld4 out5=[r14],PT(R14)-PT(R13) // r13 == ebp + ;; + ld4 out3=[r14],PT(R15)-PT(R14) // r14 == esi + adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 out4=[r14] // r15 == edi + movl r16=ia32_syscall_table + ;; +(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number + ld4 r2=[r2] // r2 = current_thread_info()->flags + ;; + ld8 r16=[r16] + tbit.z p8,p0=r2,TIF_SYSCALL_TRACE + ;; + mov b6=r16 + movl r15=ia32_ret_from_syscall + ;; + mov rp=r15 +(p8) br.call.sptk.many b6=b6 + br.cond.sptk ia32_trace_syscall + +non_ia32_syscall: + alloc r15=ar.pfs,0,0,2,0 + mov out0=r14 // interrupt # + add out1=16,sp // pointer to pt_regs + ;; // avoid WAW on CFM + br.call.sptk.many rp=ia32_bad_interrupt +.ret1: movl r15=ia64_leave_kernel + ;; + mov rp=r15 + br.ret.sptk.many rp +END(dispatch_to_ia32_handler) + +#endif /* CONFIG_IA32_SUPPORT */ diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/mca.c Mon Jun 9 07:16:09 2003 @@ -322,7 +322,7 @@ } void -init_handler_platform (sal_log_processor_info_t *proc_ptr, +init_handler_platform (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw) { struct unw_frame_info info; @@ -337,15 +337,18 @@ */ printk("Delaying for 5 seconds...\n"); udelay(5*1000000); - show_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area); + show_min_state(ms); printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm); - fetch_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area, pt, sw); + fetch_min_state(ms, pt, sw); unw_init_from_interruption(&info, current, pt, sw); ia64_do_show_stack(&info, NULL); +#ifdef CONFIG_SMP + /* read_trylock() would be handy... */ if (!tasklist_lock.write_lock) read_lock(&tasklist_lock); +#endif { struct task_struct *g, *t; do_each_thread (g, t) { @@ -353,11 +356,13 @@ continue; printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm); - show_stack(t); + show_stack(t, NULL); } while_each_thread (g, t); } +#ifdef CONFIG_SMP if (!tasklist_lock.write_lock) read_unlock(&tasklist_lock); +#endif printk("\nINIT dump complete. Please reboot now.\n"); while (1); /* hang city if no debugger */ @@ -657,17 +662,17 @@ IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); - ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); + ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be - * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); + * ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, - mca_hldlr_ptr->gp, + ia64_tpa(mca_hldlr_ptr->gp), ia64_mc_info.imi_mca_handler_size, 0, 0, 0))) { @@ -677,15 +682,15 @@ } IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", - ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); + ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp)); /* * XXX - disable SAL checksum by setting size to 0, should be * IA64_INIT_HANDLER_SIZE */ - ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); + ia64_mc_info.imi_monarch_init_handler = ia64_tpa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; - ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); + ia64_mc_info.imi_slave_init_handler = ia64_tpa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", @@ -694,10 +699,10 @@ /* Register the os init handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT, ia64_mc_info.imi_monarch_init_handler, - __pa(ia64_get_gp()), + ia64_tpa(ia64_get_gp()), ia64_mc_info.imi_monarch_init_handler_size, ia64_mc_info.imi_slave_init_handler, - __pa(ia64_get_gp()), + ia64_tpa(ia64_get_gp()), ia64_mc_info.imi_slave_init_handler_size))) { printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. " @@ -1235,32 +1240,19 @@ void ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) { - sal_log_processor_info_t *proc_ptr; - ia64_err_rec_t *plog_ptr; + pal_min_state_area_t *ms; - printk(KERN_INFO "Entered OS INIT handler\n"); - - /* Get the INIT processor log */ - if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) - return; // no record retrieved - -#ifdef IA64_DUMP_ALL_PROC_INFO - ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk); -#endif + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n", + ia64_sal_to_os_handoff_state.proc_state_param); /* - * get pointer to min state save area - * + * Address of minstate area provided by PAL is physical, + * uncacheable (bit 63 set). Convert to Linux virtual + * address in region 6. */ - plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT); - proc_ptr = &plog_ptr->proc_err; - - ia64_process_min_state_save(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area); - - /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ - ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); + ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61)); - init_handler_platform(proc_ptr, pt, sw); /* call platform specific routines */ + init_handler_platform(ms, pt, sw); /* call platform specific routines */ } /* diff -Nru a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S --- a/arch/ia64/kernel/mca_asm.S Tue Apr 15 13:16:39 2003 +++ b/arch/ia64/kernel/mca_asm.S Thu Jun 12 01:09:18 2003 @@ -50,14 +50,15 @@ * 6. GR12 = Return address to location within SAL_CHECK */ #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=ia64_sal_to_os_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ + LOAD_PHYSICAL(p0, _tmp, ia64_sal_to_os_handoff_state);; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ st8 [_tmp]=r9,0x08;; \ st8 [_tmp]=r10,0x08;; \ st8 [_tmp]=r11,0x08;; \ - st8 [_tmp]=r12,0x08 + st8 [_tmp]=r12,0x08;; \ + st8 [_tmp]=r17,0x08;; \ + st8 [_tmp]=r18,0x08 /* * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) @@ -70,9 +71,8 @@ * returns ptr to SAL rtn save loc in _tmp */ #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \ -(p6) movl _tmp=ia64_sal_to_os_handoff_state;; \ -(p7) movl _tmp=ia64_os_to_sal_handoff_state;; \ - DATA_VA_TO_PA(_tmp);; \ + LOAD_PHYSICAL(p6, _tmp, ia64_sal_to_os_handoff_state);; \ + LOAD_PHYSICAL(p7, _tmp, ia64_os_to_sal_handoff_state);; \ (p6) movl r8=IA64_MCA_COLD_BOOT; \ (p6) movl r10=IA64_MCA_SAME_CONTEXT; \ (p6) add _tmp=0x18,_tmp;; \ diff -Nru a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h --- a/arch/ia64/kernel/minstate.h Tue Feb 25 02:41:31 2003 +++ b/arch/ia64/kernel/minstate.h Mon Jun 2 09:49:08 2003 @@ -5,42 +5,24 @@ #include "entry.h" /* - * A couple of convenience macros that make writing and reading - * SAVE_MIN and SAVE_REST easier. - */ -#define rARPR r31 -#define rCRIFS r30 -#define rCRIPSR r29 -#define rCRIIP r28 -#define rARRSC r27 -#define rARPFS r26 -#define rARUNAT r25 -#define rARRNAT r24 -#define rARBSPSTORE r23 -#define rKRBS r22 -#define rB6 r21 -#define rR1 r20 - -/* - * Here start the source dependent macros. - */ - -/* * For ivt.s we want to access the stack virtually so we don't have to disable translation * on interrupts. + * + * On entry: + * r1: pointer to current task (ar.k6) */ #define MINSTATE_START_SAVE_MIN_VIRT \ (pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ ;; \ -(pUStk) mov.m rARRNAT=ar.rnat; \ -(pUStk) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ +(pUStk) mov.m r24=ar.rnat; \ +(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of RBS */ \ (pKStk) mov r1=sp; /* get sp */ \ ;; \ -(pUStk) lfetch.fault.excl.nt1 [rKRBS]; \ +(pUStk) lfetch.fault.excl.nt1 [r22]; \ (pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ +(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ ;; \ -(pUStk) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ (pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ ;; \ (pUStk) mov r18=ar.bsp; \ @@ -57,16 +39,16 @@ #define MINSTATE_START_SAVE_MIN_PHYS \ (pKStk) movl sp=ia64_init_stack+IA64_STK_OFFSET-IA64_PT_REGS_SIZE; \ (pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ -(pUStk) addl rKRBS=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ +(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ -(pUStk) mov rARRNAT=ar.rnat; \ -(pKStk) dep r1=0,sp,61,3; /* compute physical addr of sp */ \ +(pUStk) mov r24=ar.rnat; \ +(pKStk) tpa r1=sp; /* compute physical addr of sp */ \ (pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1; /* compute base of memory stack */ \ -(pUStk) mov rARBSPSTORE=ar.bspstore; /* save ar.bspstore */ \ -(pUStk) dep rKRBS=-1,rKRBS,61,3; /* compute kernel virtual addr of RBS */\ +(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ +(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ ;; \ (pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ -(pUStk) mov ar.bspstore=rKRBS; /* switch to kernel RBS */ \ +(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ ;; \ (pUStk) mov r18=ar.bsp; \ (pUStk) mov ar.rsc=0x3; /* set eager mode, pl 0, little-endian, loadrs=0 */ \ @@ -99,153 +81,170 @@ * * Upon exit, the state is as follows: * psr.ic: off - * r2 = points to &pt_regs.r16 + * r2 = points to &pt_regs.r16 + * r8 = contents of ar.ccv + * r9 = contents of ar.csd + * r10 = contents of ar.ssd + * r11 = FPSR_DEFAULT * r12 = kernel sp (kernel virtual address) * r13 = points to current task_struct (kernel virtual address) * p15 = TRUE if psr.i is set in cr.ipsr - * predicate registers (other than p2, p3, and p15), b6, r3, r8, r9, r10, r11, r14, r15: + * predicate registers (other than p2, p3, and p15), b6, r3, r14, r15: * preserved * * Note that psr.ic is NOT turned on by this macro. This is so that * we can pass interruption state as arguments to a handler. */ -#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ - mov rARRSC=ar.rsc; /* M */ \ - mov rARUNAT=ar.unat; /* M */ \ - mov rR1=r1; /* A */ \ - MINSTATE_GET_CURRENT(r1); /* M (or M;;I) */ \ - mov rCRIPSR=cr.ipsr; /* M */ \ - mov rARPFS=ar.pfs; /* I */ \ - mov rCRIIP=cr.iip; /* M */ \ - mov rB6=b6; /* I */ /* rB6 = branch reg 6 */ \ - COVER; /* B;; (or nothing) */ \ - ;; \ - adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r1; \ - ;; \ - ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ - st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ - /* switch from user to kernel RBS: */ \ - ;; \ - invala; /* M */ \ - SAVE_IFS; \ - cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? (psr.cpl==0) */ \ - ;; \ - MINSTATE_START_SAVE_MIN \ - add r17=L1_CACHE_BYTES,r1 /* really: biggest cache-line size */ \ - ;; \ - st8 [r1]=rCRIPSR; /* save cr.ipsr */ \ - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ - add r16=16,r1; /* initialize first base pointer */ \ - ;; \ - lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ - ;; \ - lfetch.fault.excl.nt1 [r17]; \ - adds r17=8,r1; /* initialize second base pointer */ \ -(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ - ;; \ - st8 [r17]=rCRIIP,16; /* save cr.iip */ \ - st8 [r16]=rCRIFS,16; /* save cr.ifs */ \ -(pUStk) sub r18=r18,rKRBS; /* r18=RSE.ndirty*8 */ \ - ;; \ - st8 [r17]=rARUNAT,16; /* save ar.unat */ \ - st8 [r16]=rARPFS,16; /* save ar.pfs */ \ - shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ - ;; \ - st8 [r17]=rARRSC,16; /* save ar.rsc */ \ -(pUStk) st8 [r16]=rARRNAT,16; /* save ar.rnat */ \ -(pKStk) adds r16=16,r16; /* skip over ar_rnat field */ \ - ;; /* avoid RAW on r16 & r17 */ \ -(pUStk) st8 [r17]=rARBSPSTORE,16; /* save ar.bspstore */ \ - st8 [r16]=rARPR,16; /* save predicates */ \ -(pKStk) adds r17=16,r17; /* skip over ar_bspstore field */ \ - ;; \ - st8 [r17]=rB6,16; /* save b6 */ \ - st8 [r16]=r18,16; /* save ar.rsc value for "loadrs" */ \ - tbit.nz p15,p0=rCRIPSR,IA64_PSR_I_BIT \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=rR1,16; /* save original r1 */ \ -.mem.offset 0,0; st8.spill [r16]=r2,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r3,16; \ -.mem.offset 0,0; st8.spill [r16]=r12,16; \ - adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r13,16; \ -.mem.offset 0,0; st8.spill [r16]=r14,16; \ - cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r15,16; \ -.mem.offset 0,0; st8.spill [r16]=r8,16; \ - dep r14=-1,r0,61,3; \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r9,16; \ -.mem.offset 0,0; st8.spill [r16]=r10,16; \ - adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ - ;; \ -.mem.offset 8,0; st8.spill [r17]=r11,16; \ - mov r13=IA64_KR(CURRENT); /* establish `current' */ \ - ;; \ - EXTRA; \ - movl r1=__gp; /* establish kernel global pointer */ \ - ;; \ +#define DO_SAVE_MIN(COVER,SAVE_IFS,EXTRA) \ + MINSTATE_GET_CURRENT(r16); /* M (or M;;I) */ \ + mov r27=ar.rsc; /* M */ \ + mov r20=r1; /* A */ \ + mov r25=ar.unat; /* M */ \ + mov r29=cr.ipsr; /* M */ \ + mov r26=ar.pfs; /* I */ \ + mov r28=cr.iip; /* M */ \ + mov r21=ar.fpsr; /* M */ \ + COVER; /* B;; (or nothing) */ \ + ;; \ + adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16; \ + ;; \ + ld1 r17=[r16]; /* load current->thread.on_ustack flag */ \ + st1 [r16]=r0; /* clear current->thread.on_ustack flag */ \ + adds r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 \ + /* switch from user to kernel RBS: */ \ + ;; \ + invala; /* M */ \ + SAVE_IFS; \ + cmp.eq pKStk,pUStk=r0,r17; /* are we in kernel mode already? */ \ + ;; \ + MINSTATE_START_SAVE_MIN \ + adds r17=2*L1_CACHE_BYTES,r1; /* really: biggest cache-line size */ \ + adds r16=PT(CR_IPSR),r1; \ + ;; \ + lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES; \ + st8 [r16]=r29; /* save cr.ipsr */ \ + ;; \ + lfetch.fault.excl.nt1 [r17]; \ + tbit.nz p15,p0=r29,IA64_PSR_I_BIT; \ + mov r29=b0 \ + ;; \ + adds r16=PT(R8),r1; /* initialize first base pointer */ \ + adds r17=PT(R9),r1; /* initialize second base pointer */ \ +(pKStk) mov r18=r0; /* make sure r18 isn't NaT */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r8,16; \ +.mem.offset 8,0; st8.spill [r17]=r9,16; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r10,24; \ +.mem.offset 8,0; st8.spill [r17]=r11,24; \ + ;; \ + st8 [r16]=r28,16; /* save cr.iip */ \ + st8 [r17]=r30,16; /* save cr.ifs */ \ +(pUStk) sub r18=r18,r22; /* r18=RSE.ndirty*8 */ \ + mov r8=ar.ccv; \ + mov r9=ar.csd; \ + mov r10=ar.ssd; \ + movl r11=FPSR_DEFAULT; /* L-unit */ \ + ;; \ + st8 [r16]=r25,16; /* save ar.unat */ \ + st8 [r17]=r26,16; /* save ar.pfs */ \ + shl r18=r18,16; /* compute ar.rsc to be used for "loadrs" */ \ + ;; \ + st8 [r16]=r27,16; /* save ar.rsc */ \ +(pUStk) st8 [r17]=r24,16; /* save ar.rnat */ \ +(pKStk) adds r17=16,r17; /* skip over ar_rnat field */ \ + ;; /* avoid RAW on r16 & r17 */ \ +(pUStk) st8 [r16]=r23,16; /* save ar.bspstore */ \ + st8 [r17]=r31,16; /* save predicates */ \ +(pKStk) adds r16=16,r16; /* skip over ar_bspstore field */ \ + ;; \ + st8 [r16]=r29,16; /* save b0 */ \ + st8 [r17]=r18,16; /* save ar.rsc value for "loadrs" */ \ + cmp.eq pNonSys,pSys=r0,r0 /* initialize pSys=0, pNonSys=1 */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r20,16; /* save original r1 */ \ +.mem.offset 8,0; st8.spill [r17]=r12,16; \ + adds r12=-16,r1; /* switch to kernel memory stack (with 16 bytes of scratch) */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r13,16; \ +.mem.offset 8,0; st8.spill [r17]=r21,16; /* save ar.fpsr */ \ + mov r13=IA64_KR(CURRENT); /* establish `current' */ \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r15,16; \ +.mem.offset 8,0; st8.spill [r17]=r14,16; \ + dep r14=-1,r0,61,3; \ + ;; \ +.mem.offset 0,0; st8.spill [r16]=r2,16; \ +.mem.offset 8,0; st8.spill [r17]=r3,16; \ + adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ + ;; \ + EXTRA; \ + movl r1=__gp; /* establish kernel global pointer */ \ + ;; \ MINSTATE_END_SAVE_MIN /* - * SAVE_REST saves the remainder of pt_regs (with psr.ic on). This - * macro guarantees to preserve all predicate registers, r8, r9, r10, - * r11, r14, and r15. + * SAVE_REST saves the remainder of pt_regs (with psr.ic on). * * Assumed state upon entry: * psr.ic: on * r2: points to &pt_regs.r16 * r3: points to &pt_regs.r17 + * r8: contents of ar.ccv + * r9: contents of ar.csd + * r10: contents of ar.ssd + * r11: FPSR_DEFAULT + * + * Registers r14 and r15 are guaranteed not to be touched by SAVE_REST. */ #define SAVE_REST \ -.mem.offset 0,0; st8.spill [r2]=r16,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r17,16; \ -.mem.offset 0,0; st8.spill [r2]=r18,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r19,16; \ -.mem.offset 0,0; st8.spill [r2]=r20,16; \ +.mem.offset 0,0; st8.spill [r2]=r16,16; \ +.mem.offset 8,0; st8.spill [r3]=r17,16; \ ;; \ - mov r16=ar.ccv; /* M-unit */ \ - movl r18=FPSR_DEFAULT /* L-unit */ \ +.mem.offset 0,0; st8.spill [r2]=r18,16; \ +.mem.offset 8,0; st8.spill [r3]=r19,16; \ ;; \ - mov r17=ar.fpsr; /* M-unit */ \ - mov ar.fpsr=r18; /* M-unit */ \ +.mem.offset 0,0; st8.spill [r2]=r20,16; \ +.mem.offset 8,0; st8.spill [r3]=r21,16; \ + mov r18=b6; \ ;; \ -.mem.offset 8,0; st8.spill [r3]=r21,16; \ -.mem.offset 0,0; st8.spill [r2]=r22,16; \ - mov r18=b0; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r23,16; \ -.mem.offset 0,0; st8.spill [r2]=r24,16; \ +.mem.offset 0,0; st8.spill [r2]=r22,16; \ +.mem.offset 8,0; st8.spill [r3]=r23,16; \ mov r19=b7; \ ;; \ -.mem.offset 8,0; st8.spill [r3]=r25,16; \ -.mem.offset 0,0; st8.spill [r2]=r26,16; \ - ;; \ -.mem.offset 8,0; st8.spill [r3]=r27,16; \ -.mem.offset 0,0; st8.spill [r2]=r28,16; \ +.mem.offset 0,0; st8.spill [r2]=r24,16; \ +.mem.offset 8,0; st8.spill [r3]=r25,16; \ ;; \ -.mem.offset 8,0; st8.spill [r3]=r29,16; \ -.mem.offset 0,0; st8.spill [r2]=r30,16; \ +.mem.offset 0,0; st8.spill [r2]=r26,16; \ +.mem.offset 8,0; st8.spill [r3]=r27,16; \ ;; \ -.mem.offset 8,0; st8.spill [r3]=r31,16; \ - st8 [r2]=r16,16; /* ar.ccv */ \ +.mem.offset 0,0; st8.spill [r2]=r28,16; \ +.mem.offset 8,0; st8.spill [r3]=r29,16; \ ;; \ - st8 [r3]=r17,16; /* ar.fpsr */ \ - st8 [r2]=r18,16; /* b0 */ \ +.mem.offset 0,0; st8.spill [r2]=r30,16; \ +.mem.offset 8,0; st8.spill [r3]=r31,32; \ ;; \ - st8 [r3]=r19,16+8; /* b7 */ \ + mov ar.fpsr=r11; /* M-unit */ \ + st8 [r2]=r8,8; /* ar.ccv */ \ + adds r24=PT(B6)-PT(F7),r3; \ ;; \ stf.spill [r2]=f6,32; \ stf.spill [r3]=f7,32; \ ;; \ stf.spill [r2]=f8,32; \ - stf.spill [r3]=f9,32 + stf.spill [r3]=f9,32; \ + ;; \ + stf.spill [r2]=f10; \ + stf.spill [r3]=f11; \ + adds r25=PT(B7)-PT(F11),r3; \ + ;; \ + st8 [r24]=r18,16; /* b6 */ \ + st8 [r25]=r19,16; /* b7 */ \ + ;; \ + st8 [r24]=r9; /* ar.csd */ \ + st8 [r25]=r10; /* ar.ssd */ \ + ;; -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) -#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov r30=cr.ifs,) +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov r30=cr.ifs, mov r15=r19) +#define SAVE_MIN DO_SAVE_MIN( , mov r30=r0, ) diff -Nru a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c --- a/arch/ia64/kernel/module.c Thu Jun 5 23:36:29 2003 +++ b/arch/ia64/kernel/module.c Tue Jun 17 23:50:17 2003 @@ -18,7 +18,8 @@ LTOFF22X LTOFF22X LTOFF_FPTR22 - PCREL21B + PCREL21B (for br.call only; br.cond is not supported out of modules!) + PCREL60B (for brl.cond only; brl.call is not supported for modules!) PCREL64LSB SECREL32LSB SEGREL64LSB @@ -33,6 +34,7 @@ #include #include +#include #include #define ARCH_MODULE_DEBUG 0 @@ -158,27 +160,6 @@ return (uint64_t) insn & 0x3; } -/* Patch instruction with "val" where "mask" has 1 bits. */ -static void -apply (struct insn *insn, uint64_t mask, uint64_t val) -{ - uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) bundle(insn); -# define insn_mask ((1UL << 41) - 1) - unsigned long shift; - - b0 = b[0]; b1 = b[1]; - shift = 5 + 41 * slot(insn); /* 5 bits of template, then 3 x 41-bit instructions */ - if (shift >= 64) { - m1 = mask << (shift - 64); - v1 = val << (shift - 64); - } else { - m0 = mask << shift; m1 = mask >> (64 - shift); - v0 = val << shift; v1 = val >> (64 - shift); - b[0] = (b0 & ~m0) | (v0 & m0); - } - b[1] = (b1 & ~m1) | (v1 & m1); -} - static int apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) { @@ -187,12 +168,7 @@ mod->name, slot(insn)); return 0; } - apply(insn, 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ - | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ - | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); - apply((void *) insn - 1, 0x1ffffffffff, val >> 22); + ia64_patch_imm64((u64) insn, val); return 1; } @@ -208,9 +184,7 @@ printk(KERN_ERR "%s: value %ld out of IMM60 range\n", mod->name, (int64_t) val); return 0; } - apply(insn, 0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */ - | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); - apply((void *) insn - 1, 0x1fffffffffc, val >> 18); + ia64_patch_imm60((u64) insn, val); return 1; } @@ -221,10 +195,10 @@ printk(KERN_ERR "%s: value %li out of IMM22 range\n", mod->name, (int64_t)val); return 0; } - apply(insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ - | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ - | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ - | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x01fffcfe000, ( ((val & 0x200000) << 15) /* bit 21 -> 36 */ + | ((val & 0x1f0000) << 6) /* bit 16 -> 22 */ + | ((val & 0x00ff80) << 20) /* bit 7 -> 27 */ + | ((val & 0x00007f) << 13) /* bit 0 -> 13 */)); return 1; } @@ -235,8 +209,8 @@ printk(KERN_ERR "%s: value %li out of IMM21b range\n", mod->name, (int64_t)val); return 0; } - apply(insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ - | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch((u64) insn, 0x11ffffe000, ( ((val & 0x100000) << 16) /* bit 20 -> 36 */ + | ((val & 0x0fffff) << 13) /* bit 0 -> 13 */)); return 1; } @@ -281,7 +255,7 @@ b0 = b[0]; b1 = b[1]; off = ( ((b1 & 0x00fffff000000000) >> 36) /* imm20b -> bit 0 */ | ((b0 >> 48) << 20) | ((b1 & 0x7fffff) << 36) /* imm39 -> bit 20 */ - | ((b1 & 0x0800000000000000) << 1)); /* i -> bit 60 */ + | ((b1 & 0x0800000000000000) << 0)); /* i -> bit 59 */ return (long) plt->bundle[1] + 16*off; } @@ -751,7 +725,7 @@ if (gp_addressable(mod, val)) { /* turn "ld8" into "mov": */ DEBUGP("%s: patching ld8 at %p to mov\n", __FUNCTION__, location); - apply(location, 0x1fff80fe000, 0x10000000000); + ia64_patch((u64) location, 0x1fff80fe000, 0x10000000000); } return 0; @@ -889,7 +863,8 @@ } #ifdef CONFIG_SMP -void percpu_modcopy(void *pcpudst, const void *src, unsigned long size) +void +percpu_modcopy (void *pcpudst, const void *src, unsigned long size) { unsigned int i; for (i = 0; i < NR_CPUS; i++) diff -Nru a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S --- a/arch/ia64/kernel/pal.S Tue Jan 14 21:57:29 2003 +++ b/arch/ia64/kernel/pal.S Thu May 15 04:45:02 2003 @@ -164,7 +164,7 @@ ;; mov loc4=ar.rsc // save RSE configuration dep.z loc2=loc2,0,61 // convert pal entry point to physical - dep.z r8=r8,0,61 // convert rp to physical + tpa r8=r8 // convert rp to physical ;; mov b7 = loc2 // install target to branch reg mov ar.rsc=0 // put RSE in enforced lazy, LE mode @@ -174,13 +174,13 @@ or loc3=loc3,r17 // add in psr the bits to set ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret1: mov rp = r8 // install return address (physical) br.cond.sptk.many b7 1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret2: mov psr.l = loc3 // restore init PSR @@ -228,13 +228,13 @@ mov b7 = loc2 // install target to branch reg ;; andcm r16=loc3,r16 // removes bits to clear from psr - br.call.sptk.many rp=ia64_switch_mode + br.call.sptk.many rp=ia64_switch_mode_phys .ret6: br.call.sptk.many rp=b7 // now make the call .ret7: mov ar.rsc=0 // put RSE in enforced lazy, LE mode mov r16=loc3 // r16= original psr - br.call.sptk.many rp=ia64_switch_mode // return to virtual mode + br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode .ret8: mov psr.l = loc3 // restore init PSR mov ar.pfs = loc1 diff -Nru a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/kernel/patch.c Sat Jun 14 00:38:59 2003 @@ -0,0 +1,194 @@ +/* + * Instruction-patching support. + * + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + */ +#include +#include + +#include +#include +#include +#include + +/* + * This was adapted from code written by Tony Luck: + * + * The 64-bit value in a "movl reg=value" is scattered between the two words of the bundle + * like this: + * + * 6 6 5 4 3 2 1 + * 3210987654321098765432109876543210987654321098765432109876543210 + * ABBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCDEEEEEFFFFFFFFFGGGGGGG + * + * CCCCCCCCCCCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + * xxxxAFFFFFFFFFEEEEEDxGGGGGGGxxxxxxxxxxxxxBBBBBBBBBBBBBBBBBBBBBBB + */ +static u64 +get_imm64 (u64 insn_addr) +{ + u64 *p = (u64 *) (insn_addr & -16); /* mask out slot number */ + + return ( (p[1] & 0x0800000000000000UL) << 4) | /*A*/ + ((p[1] & 0x00000000007fffffUL) << 40) | /*B*/ + ((p[0] & 0xffffc00000000000UL) >> 24) | /*C*/ + ((p[1] & 0x0000100000000000UL) >> 23) | /*D*/ + ((p[1] & 0x0003e00000000000UL) >> 29) | /*E*/ + ((p[1] & 0x07fc000000000000UL) >> 43) | /*F*/ + ((p[1] & 0x000007f000000000UL) >> 36); /*G*/ +} + +/* Patch instruction with "val" where "mask" has 1 bits. */ +void +ia64_patch (u64 insn_addr, u64 mask, u64 val) +{ + u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16); +# define insn_mask ((1UL << 41) - 1) + unsigned long shift; + + b0 = b[0]; b1 = b[1]; + shift = 5 + 41 * (insn_addr % 16); /* 5 bits of template, then 3 x 41-bit instructions */ + if (shift >= 64) { + m1 = mask << (shift - 64); + v1 = val << (shift - 64); + } else { + m0 = mask << shift; m1 = mask >> (64 - shift); + v0 = val << shift; v1 = val >> (64 - shift); + b[0] = (b0 & ~m0) | (v0 & m0); + } + b[1] = (b1 & ~m1) | (v1 & m1); +} + +void +ia64_patch_imm64 (u64 insn_addr, u64 val) +{ + ia64_patch(insn_addr, + 0x01fffefe000, ( ((val & 0x8000000000000000) >> 27) /* bit 63 -> 36 */ + | ((val & 0x0000000000200000) << 0) /* bit 21 -> 21 */ + | ((val & 0x00000000001f0000) << 6) /* bit 16 -> 22 */ + | ((val & 0x000000000000ff80) << 20) /* bit 7 -> 27 */ + | ((val & 0x000000000000007f) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1ffffffffff, val >> 22); +} + +void +ia64_patch_imm60 (u64 insn_addr, u64 val) +{ + ia64_patch(insn_addr, + 0x011ffffe000, ( ((val & 0x1000000000000000) >> 24) /* bit 60 -> 36 */ + | ((val & 0x00000000000fffff) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr - 1, 0x1fffffffffc, val >> 18); +} + +/* + * We need sometimes to load the physical address of a kernel + * object. Often we can convert the virtual address to physical + * at execution time, but sometimes (either for performance reasons + * or during error recovery) we cannot to this. Patch the marked + * bundles to load the physical address. + */ +void __init +ia64_patch_vtop (unsigned long start, unsigned long end) +{ + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) offp + *offp; + + /* replace virtual address with corresponding physical address: */ + ia64_patch_imm64(ip, ia64_tpa(get_imm64(ip))); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +void +ia64_patch_mckinley_e9 (unsigned long start, unsigned long end) +{ + static int first_time = 1; + int need_workaround; + s32 *offp = (s32 *) start; + u64 *wp; + + need_workaround = (local_cpu_data->family == 0x1f && local_cpu_data->model == 0); + + if (first_time) { + first_time = 0; + if (need_workaround) + printk(KERN_INFO "Leaving McKinley Errata 9 workaround enabled\n"); + else + printk(KERN_INFO "McKinley Errata 9 workaround not needed; " + "disabling it\n"); + } + if (need_workaround) + return; + + while (offp < (s32 *) end) { + wp = (u64 *) ia64_imva((char *) offp + *offp); + wp[0] = 0x0000000100000000; + wp[1] = 0x0004000000000200; + ia64_fc(wp); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +static void +patch_fsyscall_table (unsigned long start, unsigned long end) +{ + extern unsigned long fsyscall_table[NR_syscalls]; + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) ia64_imva((char *) offp + *offp); + ia64_patch_imm64(ip, (u64) fsyscall_table); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +static void +patch_brl_fsys_bubble_down (unsigned long start, unsigned long end) +{ + extern char fsys_bubble_down[]; + s32 *offp = (s32 *) start; + u64 ip; + + while (offp < (s32 *) end) { + ip = (u64) offp + *offp; + ia64_patch_imm60((u64) ia64_imva((void *) ip), + (u64) (fsys_bubble_down - (ip & -16)) / 16); + ia64_fc((void *) ip); + ++offp; + } + ia64_sync_i(); + ia64_srlz_i(); +} + +void +ia64_patch_gate (void) +{ + extern char __start_gate_mckinley_e9_patchlist; + extern char __end_gate_mckinley_e9_patchlist; + extern char __start_gate_vtop_patchlist; + extern char __end_gate_vtop_patchlist; + extern char __start_gate_fsyscall_patchlist; + extern char __end_gate_fsyscall_patchlist; + extern char __start_gate_brl_fsys_bubble_down_patchlist; + extern char __end_gate_brl_fsys_bubble_down_patchlist; +# define START(name) ((unsigned long) &__start_gate_##name##_patchlist) +# define END(name) ((unsigned long)&__end_gate_##name##_patchlist) + + patch_fsyscall_table(START(fsyscall), END(fsyscall)); + patch_brl_fsys_bubble_down(START(brl_fsys_bubble_down), END(brl_fsys_bubble_down)); + ia64_patch_vtop(START(vtop), END(vtop)); + ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9)); +} diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c --- a/arch/ia64/kernel/perfmon.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/perfmon.c Fri Jun 13 08:41:32 2003 @@ -1,16 +1,22 @@ /* - * This file implements the perfmon subsystem which is used + * This file implements the perfmon-2 subsystem which is used * to program the IA-64 Performance Monitoring Unit (PMU). * - * Originally Written by Ganesh Venkitachalam, IBM Corp. - * Copyright (C) 1999 Ganesh Venkitachalam + * The initial version of perfmon.c was written by + * Ganesh Venkitachalam, IBM Corp. * - * Modifications by Stephane Eranian, Hewlett-Packard Co. - * Modifications by David Mosberger-Tang, Hewlett-Packard Co. + * Then it was modified for perfmon-1.x by Stephane Eranian and + * David Mosberger, Hewlett Packard Co. + * + * Version Perfmon-2.x is a rewrite of perfmon-1.x + * by Stephane Eranian, Hewlett Packard Co. * * Copyright (C) 1999-2003 Hewlett Packard Co * Stephane Eranian * David Mosberger-Tang + * + * More information about perfmon available at: + * http://www.hpl.hp.com/research/linux/perfmon */ #include @@ -23,7 +29,13 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -33,123 +45,206 @@ #include #include #include -#include /* for ia64_get_itc() */ +#include #ifdef CONFIG_PERFMON - /* - * For PMUs which rely on the debug registers for some features, you must - * you must enable the following flag to activate the support for - * accessing the registers via the perfmonctl() interface. + * perfmon context state */ -#if defined(CONFIG_ITANIUM) || defined(CONFIG_MCKINLEY) -#define PFM_PMU_USES_DBR 1 -#endif +#define PFM_CTX_UNLOADED 1 /* context is not loaded onto any task */ +#define PFM_CTX_LOADED 2 /* context is loaded onto a task */ +#define PFM_CTX_MASKED 3 /* context is loaded but monitoring is masked due to overflow */ +#define PFM_CTX_ZOMBIE 4 /* owner of the context is closing it */ +#define PFM_CTX_TERMINATED 5 /* the task the context was loaded onto is gone */ -/* - * perfmon context states - */ -#define PFM_CTX_DISABLED 0 -#define PFM_CTX_ENABLED 1 +#define CTX_LOADED(c) (c)->ctx_state = PFM_CTX_LOADED +#define CTX_UNLOADED(c) (c)->ctx_state = PFM_CTX_UNLOADED +#define CTX_ZOMBIE(c) (c)->ctx_state = PFM_CTX_ZOMBIE +#define CTX_DESTROYED(c) (c)->ctx_state = PFM_CTX_DESTROYED +#define CTX_MASKED(c) (c)->ctx_state = PFM_CTX_MASKED +#define CTX_TERMINATED(c) (c)->ctx_state = PFM_CTX_TERMINATED + +#define CTX_IS_UNLOADED(c) ((c)->ctx_state == PFM_CTX_UNLOADED) +#define CTX_IS_LOADED(c) ((c)->ctx_state == PFM_CTX_LOADED) +#define CTX_IS_ZOMBIE(c) ((c)->ctx_state == PFM_CTX_ZOMBIE) +#define CTX_IS_MASKED(c) ((c)->ctx_state == PFM_CTX_MASKED) +#define CTX_IS_TERMINATED(c) ((c)->ctx_state == PFM_CTX_TERMINATED) +#define CTX_IS_DEAD(c) ((c)->ctx_state == PFM_CTX_TERMINATED || (c)->ctx_state == PFM_CTX_ZOMBIE) + +#define PFM_INVALID_ACTIVATION (~0UL) -/* - * Reset register flags - */ -#define PFM_PMD_LONG_RESET 1 -#define PFM_PMD_SHORT_RESET 2 /* - * Misc macros and definitions + * depth of message queue */ -#define PMU_FIRST_COUNTER 4 -#define PMU_MAX_PMCS 256 -#define PMU_MAX_PMDS 256 +#define PFM_MAX_MSGS 32 +#define PFM_CTXQ_EMPTY(g) ((g)->ctx_msgq_head == (g)->ctx_msgq_tail) /* * type of a PMU register (bitmask). * bitmask structure: * bit0 : register implemented - * bit1 : end marker + * bit1 : end marker * bit2-3 : reserved - * bit4-7 : register type + * bit4 : pmc has pmc.pm + * bit5 : pmc controls a counter (has pmc.oi), pmd is used as counter + * bit6-7 : register type * bit8-31: reserved */ +#define PFM_REG_NOTIMPL 0x0 /* not implemented at all */ #define PFM_REG_IMPL 0x1 /* register implemented */ #define PFM_REG_END 0x2 /* end marker */ #define PFM_REG_MONITOR (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */ -#define PFM_REG_COUNTING (0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */ -#define PFM_REG_CONTROL (0x3<<4|PFM_REG_IMPL) /* PMU control register */ -#define PFM_REG_CONFIG (0x4<<4|PFM_REG_IMPL) /* refine configuration */ -#define PFM_REG_BUFFER (0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */ +#define PFM_REG_COUNTING (0x2<<4|PFM_REG_MONITOR|PFM_REG_IMPL) /* a monitor + pmc.oi+ PMD used as a counter */ +#define PFM_REG_CONTROL (0x4<<4|PFM_REG_IMPL) /* PMU control register */ +#define PFM_REG_CONFIG (0x8<<4|PFM_REG_IMPL) /* configuration register */ +#define PFM_REG_BUFFER (0xc<<4|PFM_REG_IMPL) /* PMD used as buffer */ #define PMC_IS_LAST(i) (pmu_conf.pmc_desc[i].type & PFM_REG_END) #define PMD_IS_LAST(i) (pmu_conf.pmd_desc[i].type & PFM_REG_END) -#define PFM_IS_DISABLED() pmu_conf.disabled +#define PFM_IS_DISABLED() (pmu_conf.enabled == 0) -#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_soft_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) -#define PFM_FL_INHERIT_MASK (PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL) +#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) -/* i assume unsigned */ +/* i assumed unsigned */ #define PMC_IS_IMPL(i) (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL)) #define PMD_IS_IMPL(i) (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL)) -/* XXX: these three assume that register i is implemented */ -#define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) -#define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING) -#define PMC_IS_MONITOR(i) (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR) +/* XXX: these assume that register i is implemented */ +#define PMD_IS_COUNTING(i) ((pmu_conf.pmd_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_COUNTING(i) ((pmu_conf.pmc_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_MONITOR(i) ((pmu_conf.pmc_desc[i].type & PFM_REG_MONITOR) == PFM_REG_MONITOR) #define PMC_DFL_VAL(i) pmu_conf.pmc_desc[i].default_value #define PMC_RSVD_MASK(i) pmu_conf.pmc_desc[i].reserved_mask #define PMD_PMD_DEP(i) pmu_conf.pmd_desc[i].dep_pmd[0] #define PMC_PMD_DEP(i) pmu_conf.pmc_desc[i].dep_pmd[0] -/* k assume unsigned */ -#define IBR_IS_IMPL(k) (kctx_flags.state == PFM_CTX_ENABLED) #define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) -#define CTX_INHERIT_MODE(c) ((c)->ctx_fl_inherit) -#define CTX_HAS_SMPL(c) ((c)->ctx_psb != NULL) +#define CTX_HAS_SMPL(c) ((c)->ctx_fl_is_sampling) +#define PFM_CTX_TASK(h) (h)->ctx_task + /* XXX: does not support more than 64 PMDs */ #define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) #define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) +#define CTX_USED_MONITOR(ctx, mask) (ctx)->ctx_used_monitors[0] |= (mask) #define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) #define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) #define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) +#define PFM_CODE_RR 0 /* requesting code range restriction */ +#define PFM_DATA_RR 1 /* requestion data range restriction */ -#define LOCK_CTX(ctx) spin_lock(&(ctx)->ctx_lock) -#define UNLOCK_CTX(ctx) spin_unlock(&(ctx)->ctx_lock) +#define PFM_CPUINFO_CLEAR(v) pfm_get_cpu_var(pfm_syst_info) &= ~(v) +#define PFM_CPUINFO_SET(v) pfm_get_cpu_var(pfm_syst_info) |= (v) +#define PFM_CPUINFO_GET() pfm_get_cpu_var(pfm_syst_info) -#define SET_PMU_OWNER(t) do { pmu_owners[smp_processor_id()].owner = (t); } while(0) -#define PMU_OWNER() pmu_owners[smp_processor_id()].owner +/* + * context protection macros + * in SMP: + * - we need to protect against CPU concurrency (spin_lock) + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * in UP: + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * + * spin_lock_irqsave()/spin_lock_irqrestore(): + * in SMP: local_irq_disable + spin_lock + * in UP : local_irq_disable + * + * spin_lock()/spin_lock(): + * in UP : removed automatically + * in SMP: protect against context accesses from other CPU. interrupts + * are not masked. This is useful for the PMU interrupt handler + * because we know we will not get PMU concurrency in that code. + */ +#define PROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_save ctx %p by [%d]\n", c, current->pid)); \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + DPRINT(("spinlocked ctx %p by [%d]\n", c, current->pid)); \ + } while(0) + +#define UNPROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_restore ctx %p by [%d]\n", c, current->pid)); \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + +#define PROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + } while(0) + + +#define UNPROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + + +#define PROTECT_CTX_NOIRQ(c) \ + do { \ + spin_lock(&(c)->ctx_lock); \ + } while(0) + +#define UNPROTECT_CTX_NOIRQ(c) \ + do { \ + spin_unlock(&(c)->ctx_lock); \ + } while(0) -#define LOCK_PFS() spin_lock(&pfm_sessions.pfs_lock) -#define UNLOCK_PFS() spin_unlock(&pfm_sessions.pfs_lock) + +#ifdef CONFIG_SMP + +#define GET_ACTIVATION() pfm_get_cpu_var(pmu_activation_number) +#define INC_ACTIVATION() pfm_get_cpu_var(pmu_activation_number)++ +#define SET_ACTIVATION(c) (c)->ctx_last_activation = GET_ACTIVATION() + +#else /* !CONFIG_SMP */ +#define SET_ACTIVATION(t) do {} while(0) +#define GET_ACTIVATION(t) do {} while(0) +#define INC_ACTIVATION(t) do {} while(0) +#endif /* CONFIG_SMP */ + +#define SET_PMU_OWNER(t, c) do { pfm_get_cpu_var(pmu_owner) = (t); pfm_get_cpu_var(pmu_ctx) = (c); } while(0) +#define GET_PMU_OWNER() pfm_get_cpu_var(pmu_owner) +#define GET_PMU_CTX() pfm_get_cpu_var(pmu_ctx) + +#define LOCK_PFS() spin_lock(&pfm_sessions.pfs_lock) +#define UNLOCK_PFS() spin_unlock(&pfm_sessions.pfs_lock) #define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) -#define PFM_CPUINFO_CLEAR(v) __get_cpu_var(pfm_syst_info) &= ~(v) -#define PFM_CPUINFO_SET(v) __get_cpu_var(pfm_syst_info) |= (v) +#ifdef CONFIG_SMP +#define PFM_CPU_ONLINE_MAP cpu_online_map +#define cpu_is_online(i) (PFM_CPU_ONLINE_MAP & (1UL << i)) +#else +#define PFM_CPU_ONLINE_MAP 1UL +#define cpu_is_online(i) (i==0) +#endif + +/* + * cmp0 must be the value of pmc0 + */ +#define PMC0_HAS_OVFL(cmp0) (cmp0 & ~0x1UL) /* * debugging */ -#define DBprintk(a) \ +#define DPRINT(a) \ do { \ - if (pfm_sysctl.debug >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ } while (0) -#define DBprintk_ovfl(a) \ +#define DPRINT_ovfl(a) \ do { \ - if (pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ } while (0) - - - -/* +/* * Architected PMC structure */ typedef struct { @@ -163,123 +258,127 @@ } pfm_monitor_t; /* - * There is one such data structure per perfmon context. It is used to describe the - * sampling buffer. It is to be shared among siblings whereas the pfm_context - * is not. - * Therefore we maintain a refcnt which is incremented on fork(). - * This buffer is private to the kernel only the actual sampling buffer - * including its header are exposed to the user. This construct allows us to - * export the buffer read-write, if needed, without worrying about security - * problems. - */ -typedef struct _pfm_smpl_buffer_desc { - spinlock_t psb_lock; /* protection lock */ - unsigned long psb_refcnt; /* how many users for the buffer */ - int psb_flags; /* bitvector of flags (not yet used) */ - - void *psb_addr; /* points to location of first entry */ - unsigned long psb_entries; /* maximum number of entries */ - unsigned long psb_size; /* aligned size of buffer */ - unsigned long psb_index; /* next free entry slot XXX: must use the one in buffer */ - unsigned long psb_entry_size; /* size of each entry including entry header */ - - perfmon_smpl_hdr_t *psb_hdr; /* points to sampling buffer header */ - - struct _pfm_smpl_buffer_desc *psb_next; /* next psb, used for rvfreeing of psb_hdr */ - -} pfm_smpl_buffer_desc_t; - -/* - * psb_flags - */ -#define PSB_HAS_VMA 0x1 /* a virtual mapping for the buffer exists */ - -#define LOCK_PSB(p) spin_lock(&(p)->psb_lock) -#define UNLOCK_PSB(p) spin_unlock(&(p)->psb_lock) - -/* * 64-bit software counter structure */ typedef struct { - u64 val; /* virtual 64bit counter value */ - u64 lval; /* last value */ - u64 long_reset; /* reset value on sampling overflow */ - u64 short_reset;/* reset value on overflow */ - u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */ - u64 seed; /* seed for random-number generator */ - u64 mask; /* mask for random-number generator */ - unsigned int flags; /* notify/do not notify */ + unsigned long val; /* virtual 64bit counter value */ + unsigned long lval; /* last reset value */ + unsigned long long_reset; /* reset value on sampling overflow */ + unsigned long short_reset; /* reset value on overflow */ + unsigned long reset_pmds[4]; /* which other pmds to reset when this counter overflows */ + unsigned long smpl_pmds[4]; /* which pmds are accessed when counter overflow */ + unsigned long seed; /* seed for random-number generator */ + unsigned long mask; /* mask for random-number generator */ + unsigned int flags; /* notify/do not notify */ + unsigned int reserved; /* for future use */ + unsigned long eventid; /* overflow event identifier */ } pfm_counter_t; /* - * perfmon context. One per process, is cloned on fork() depending on - * inheritance flags + * context flags */ typedef struct { - unsigned int state:1; /* 0=disabled, 1=enabled */ - unsigned int inherit:2; /* inherit mode */ unsigned int block:1; /* when 1, task will blocked on user notifications */ unsigned int system:1; /* do system wide monitoring */ - unsigned int frozen:1; /* pmu must be kept frozen on ctxsw in */ - unsigned int protected:1; /* allow access to creator of context only */ unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ + unsigned int is_sampling:1; /* true if using a custom format */ unsigned int excl_idle:1; /* exclude idle task in system wide session */ - unsigned int unsecure:1; /* sp = 0 for non self-monitored task */ - unsigned int trap_reason:2; /* reason for going into pfm_block_ovfl_reset() */ - unsigned int reserved:20; + unsigned int unsecure:1; /* exclude idle task in system wide session */ + unsigned int going_zombie:1; /* context is zombie (MASKED+blocking) */ + unsigned int trap_reason:2; /* reason for going into pfm_handle_work() */ + unsigned int no_msg:1; /* no message sent on overflow */ + unsigned int reserved:22; } pfm_context_flags_t; #define PFM_TRAP_REASON_NONE 0x0 /* default value */ -#define PFM_TRAP_REASON_BLOCKSIG 0x1 /* we need to block on overflow and signal user */ -#define PFM_TRAP_REASON_SIG 0x2 /* we simply need to signal user */ -#define PFM_TRAP_REASON_RESET 0x3 /* we need to reset PMDs */ +#define PFM_TRAP_REASON_BLOCK 0x1 /* we need to block on overflow */ +#define PFM_TRAP_REASON_RESET 0x2 /* we need to reset PMDs */ + /* * perfmon context: encapsulates all the state of a monitoring session - * XXX: probably need to change layout */ + typedef struct pfm_context { - pfm_smpl_buffer_desc_t *ctx_psb; /* sampling buffer, if any */ - unsigned long ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ + spinlock_t ctx_lock; /* context protection */ - spinlock_t ctx_lock; - pfm_context_flags_t ctx_flags; /* block/noblock */ + pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ + unsigned int ctx_state; /* state: active/inactive (no bitfield) */ - struct task_struct *ctx_notify_task; /* who to notify on overflow */ - struct task_struct *ctx_owner; /* pid of creator (debug) */ + struct task_struct *ctx_task; /* task to which context is attached */ unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ - unsigned long ctx_smpl_regs[4]; /* which registers to record on overflow */ struct semaphore ctx_restart_sem; /* use for blocking notification mode */ - unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ - unsigned long ctx_reload_pmds[4]; /* bitmask of PMD to reload on ctxsw */ + unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ + unsigned long ctx_all_pmds[4]; /* bitmask of all accessible PMDs */ + unsigned long ctx_reload_pmds[4]; /* bitmask of force reload PMD on ctxsw in */ + + unsigned long ctx_all_pmcs[4]; /* bitmask of all accessible PMCs */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */ + unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */ - unsigned long ctx_used_pmcs[4]; /* bitmask PMC used by context */ - unsigned long ctx_reload_pmcs[4]; /* bitmask of PMC to reload on ctxsw */ + unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */ - unsigned long ctx_used_ibrs[4]; /* bitmask of used IBR (speedup ctxsw) */ - unsigned long ctx_used_dbrs[4]; /* bitmask of used DBR (speedup ctxsw) */ + unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */ + unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */ + unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */ + unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */ - pfm_counter_t ctx_soft_pmds[IA64_NUM_PMD_REGS]; /* XXX: size should be dynamic */ + pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */ - u64 ctx_saved_psr; /* copy of psr used for lazy ctxsw */ - unsigned long ctx_saved_cpus_allowed; /* copy of the task cpus_allowed (system wide) */ - unsigned int ctx_cpu; /* CPU used by system wide session */ + u64 ctx_saved_psr; /* copy of psr used for ctxsw */ - atomic_t ctx_last_cpu; /* CPU id of current or last CPU used */ + unsigned long ctx_last_activation; /* context last activation number for last_cpu */ + unsigned int ctx_last_cpu; /* CPU id of current or last CPU used (SMP only) */ + unsigned int ctx_cpu; /* cpu to which perfmon is applied (system wide) */ + + int ctx_fd; /* file descriptor used my this context */ + + pfm_buffer_fmt_t *ctx_buf_fmt; /* buffer format callbacks */ + void *ctx_smpl_hdr; /* points to sampling buffer header kernel vaddr */ + unsigned long ctx_smpl_size; /* size of sampling buffer */ + void *ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ + + wait_queue_head_t ctx_msgq_wait; + pfm_msg_t ctx_msgq[PFM_MAX_MSGS]; + int ctx_msgq_head; + int ctx_msgq_tail; + struct fasync_struct *ctx_async_queue; + + wait_queue_head_t ctx_zombieq; /* termination cleanup wait queue */ } pfm_context_t; -#define ctx_fl_inherit ctx_flags.inherit +/* + * magic number used to verify that structure is really + * a perfmon context + */ +#define PFM_IS_FILE(f) ((f)->f_op == &pfm_file_ops) + +#define PFM_GET_CTX(t) ((pfm_context_t *)(t)->thread.pfm_context) + +#ifdef CONFIG_SMP +#define SET_LAST_CPU(ctx, v) (ctx)->ctx_last_cpu = (v) +#define GET_LAST_CPU(ctx) (ctx)->ctx_last_cpu +#else +#define SET_LAST_CPU(ctx, v) do {} while(0) +#define GET_LAST_CPU(ctx) do {} while(0) +#endif + + #define ctx_fl_block ctx_flags.block #define ctx_fl_system ctx_flags.system -#define ctx_fl_frozen ctx_flags.frozen -#define ctx_fl_protected ctx_flags.protected #define ctx_fl_using_dbreg ctx_flags.using_dbreg +#define ctx_fl_is_sampling ctx_flags.is_sampling #define ctx_fl_excl_idle ctx_flags.excl_idle -#define ctx_fl_trap_reason ctx_flags.trap_reason #define ctx_fl_unsecure ctx_flags.unsecure +#define ctx_fl_going_zombie ctx_flags.going_zombie +#define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_no_msg ctx_flags.no_msg + +#define PFM_SET_WORK_PENDING(t, v) do { (t)->thread.pfm_needs_checking = v; } while(0); +#define PFM_GET_WORK_PENDING(t) (t)->thread.pfm_needs_checking /* * global information about all sessions @@ -288,7 +387,7 @@ typedef struct { spinlock_t pfs_lock; /* lock the structure */ - unsigned int pfs_task_sessions; /* number of per task sessions */ + unsigned int pfs_task_sessions; /* number of per task sessions */ unsigned int pfs_sys_sessions; /* number of per system wide sessions */ unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ @@ -297,7 +396,7 @@ /* * information about a PMC or PMD. - * dep_pmd[]: a bitmask of dependent PMD registers + * dep_pmd[]: a bitmask of dependent PMD registers * dep_pmc[]: a bitmask of dependent PMC registers */ typedef struct { @@ -305,8 +404,8 @@ int pm_pos; unsigned long default_value; /* power-on default value */ unsigned long reserved_mask; /* bitmask of reserved bits */ - int (*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); - int (*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + int (*read_check)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + int (*write_check)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); unsigned long dep_pmd[4]; unsigned long dep_pmc[4]; } pfm_reg_desc_t; @@ -322,88 +421,122 @@ * a description of the PMU main characteristics. */ typedef struct { - unsigned int disabled; /* indicates if perfmon is working properly */ - unsigned long ovfl_val; /* overflow value for generic counters */ - unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ - unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ - unsigned int num_pmcs; /* number of implemented PMCS */ - unsigned int num_pmds; /* number of implemented PMDS */ - unsigned int num_ibrs; /* number of implemented IBRS */ - unsigned int num_dbrs; /* number of implemented DBRS */ - unsigned int num_counters; /* number of PMD/PMC counters */ + unsigned long ovfl_val; /* overflow value for counters */ + pfm_reg_desc_t *pmc_desc; /* detailed PMC register dependencies descriptions */ pfm_reg_desc_t *pmd_desc; /* detailed PMD register dependencies descriptions */ + + unsigned int num_pmcs; /* number of PMCS: computed at init time */ + unsigned int num_pmds; /* number of PMDS: computed at init time */ + unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ + unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ + + char *pmu_name; /* PMU family name */ + unsigned int enabled; /* indicates if perfmon initialized properly */ + unsigned int pmu_family; /* cpuid family pattern used to identify pmu */ + + unsigned int num_ibrs; /* number of IBRS: computed at init time */ + unsigned int num_dbrs; /* number of DBRS: computed at init time */ + unsigned int num_counters; /* PMC/PMD counting pairs : computed at init time */ + + unsigned int use_rr_dbregs:1; /* set if debug registers used for range restriction */ } pmu_config_t; /* - * structure used to pass argument to/from remote CPU - * using IPI to check and possibly save the PMU context on SMP systems. - * - * not used in UP kernels + * debug register related type definitions */ typedef struct { - struct task_struct *task; /* which task we are interested in */ - int retval; /* return value of the call: 0=you can proceed, 1=need to wait for completion */ -} pfm_smp_ipi_arg_t; + unsigned long ibr_mask:56; + unsigned long ibr_plm:4; + unsigned long ibr_ig:3; + unsigned long ibr_x:1; +} ibr_mask_reg_t; + +typedef struct { + unsigned long dbr_mask:56; + unsigned long dbr_plm:4; + unsigned long dbr_ig:2; + unsigned long dbr_w:1; + unsigned long dbr_r:1; +} dbr_mask_reg_t; + +typedef union { + unsigned long val; + ibr_mask_reg_t ibr; + dbr_mask_reg_t dbr; +} dbreg_t; + /* * perfmon command descriptions */ typedef struct { - int (*cmd_func)(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + int (*cmd_func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + char *cmd_name; int cmd_flags; unsigned int cmd_narg; size_t cmd_argsize; + int (*cmd_getsize)(void *arg, size_t *sz); } pfm_cmd_desc_t; -#define PFM_CMD_PID 0x1 /* command requires pid argument */ -#define PFM_CMD_ARG_READ 0x2 /* command must read argument(s) */ -#define PFM_CMD_ARG_RW 0x4 /* command must read/write argument(s) */ -#define PFM_CMD_CTX 0x8 /* command needs a perfmon context */ -#define PFM_CMD_NOCHK 0x10 /* command does not need to check task's state */ +#define PFM_CMD_FD 0x01 /* command requires a file descriptor */ +#define PFM_CMD_ARG_READ 0x02 /* command must read argument(s) */ +#define PFM_CMD_ARG_RW 0x04 /* command must read/write argument(s) */ +#define PFM_CMD_STOP 0x08 /* command does not work on zombie context */ + #define PFM_CMD_IDX(cmd) (cmd) +#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \ + && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) -#define PFM_CMD_IS_VALID(cmd) ((PFM_CMD_IDX(cmd) >= 0) \ - && (PFM_CMD_IDX(cmd) < (int) PFM_CMD_COUNT) \ - && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL) - -#define PFM_CMD_USE_PID(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0) -#define PFM_CMD_READ_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0) -#define PFM_CMD_RW_ARG(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0) -#define PFM_CMD_USE_CTX(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0) -#define PFM_CMD_CHK(cmd) ((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0) +#define PFM_CMD_NAME(cmd) pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_name +#define PFM_CMD_READ_ARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) +#define PFM_CMD_RW_ARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) +#define PFM_CMD_USE_FD(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_FD) +#define PFM_CMD_STOPPED(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_STOP) #define PFM_CMD_ARG_MANY -1 /* cannot be zero */ #define PFM_CMD_NARG(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_narg) #define PFM_CMD_ARG_SIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_argsize) +#define PFM_CMD_GETSIZE(cmd) (pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_getsize) typedef struct { int debug; /* turn on/off debugging via syslog */ int debug_ovfl; /* turn on/off debug printk in overflow handler */ int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ + int debug_pfm_read; } pfm_sysctl_t; typedef struct { - unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ - unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ - unsigned long pfm_recorded_samples_count; - unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */ + unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ + unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles; /* cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_min; /* min cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_max; /* max cycles spent processing ovfl interrupts */ + unsigned long pfm_sysupdt_count; + unsigned long pfm_sysupdt_cycles; + unsigned long pfm_smpl_handler_calls; + unsigned long pfm_smpl_handler_cycles; char pad[SMP_CACHE_BYTES] ____cacheline_aligned; } pfm_stats_t; /* * perfmon internal variables */ -static pfm_session_t pfm_sessions; /* global sessions information */ -static struct proc_dir_entry *perfmon_dir; /* for debug only */ -static pfm_stats_t pfm_stats[NR_CPUS]; -static pfm_intr_handler_desc_t *pfm_alternate_intr_handler; +static pfm_stats_t pfm_stats[NR_CPUS]; +static pfm_session_t pfm_sessions; /* global sessions information */ -DEFINE_PER_CPU(unsigned long, pfm_syst_info); +static struct proc_dir_entry *perfmon_dir; +static pfm_uuid_t pfm_null_uuid = {0,}; + +static spinlock_t pfm_smpl_fmt_lock; +static pfm_buffer_fmt_t *pfm_buffer_fmt_list; +#define LOCK_BUF_FMT_LIST() spin_lock(&pfm_smpl_fmt_lock) +#define UNLOCK_BUF_FMT_LIST() spin_unlock(&pfm_smpl_fmt_lock) /* sysctl() controls */ static pfm_sysctl_t pfm_sysctl; +int pfm_debug_var; static ctl_table pfm_ctl_table[]={ {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, @@ -424,24 +557,181 @@ static void pfm_vm_close(struct vm_area_struct * area); static struct vm_operations_struct pfm_vm_ops={ - .close = pfm_vm_close + close: pfm_vm_close }; /* - * keep track of task owning the PMU per CPU. + * Linux 2.5 vs. 2.4 helper macros and definitions + * + * if not at least 2.5.69, then assume 2.4.x. */ -static struct { - struct task_struct *owner; - char pad[SMP_CACHE_BYTES] ____cacheline_aligned; -} pmu_owners[NR_CPUS]; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) + +#define PFM_COMPILED_FOR_2_4 1 + +#include + +#define pfm_get_cpu_var(v) local_cpu_data->v +#define pfm_get_cpu_data(a,b) cpu_data((b))->a +typedef void pfm_irq_handler_t; +#define PFM_IRQ_HANDLER_RET(v) + +#define DEFINE_PER_CPU(a,b) + +static inline int +pfm_wait_task_inactive(struct task_struct *task) +{ +#ifdef CONFIG_SMP + /* Make sure the child gets off its CPU.. */ + for (;;) { + task_lock(task); + if (!task_has_cpu(task)) break; + task_unlock(task); + do { + if (task->state != TASK_STOPPED) + return -ESRCH; + barrier(); + cpu_relax(); + } while (task_has_cpu(task)); + } + task_unlock(task); +#endif + return 0; +} + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) free_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ +} + +static inline void +pfm_clear_task_notify(void) +{ +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + unsigned long page; + + page = ia64_tpa(a); + mem_map_reserve(virt_to_page(__va(page))); +} + +static inline void +pfm_unreserve_page(unsigned long a) +{ + unsigned long page; + + page = ia64_tpa(a); + mem_map_unreserve(virt_to_page(__va(page))); +} + +static inline int +pfm_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) +{ + return remap_page_range(from, phys_addr, size, prot); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + unsigned long f; + spin_lock(&(x)->ctx_lock); + return f; +} + +static inline unsigned long +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} + +#else /* 2.5.69 or higher */ + +#define pfm_wait_task_inactive(t) wait_task_inactive(t) +#define pfm_get_cpu_var(v) __get_cpu_var(v) +#define pfm_get_cpu_data(a,b) per_cpu(a, b) +typedef irqreturn_t pfm_irq_handler_t; +#define PFM_IRQ_HANDLER_RET(v) do { \ + put_cpu_no_resched(); \ + return IRQ_HANDLED; \ + } while(0); + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) put_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ + struct thread_info *info; + + info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); + set_bit(TIF_NOTIFY_RESUME, &info->flags); +} + +static inline void +pfm_clear_task_notify(void) +{ + clear_thread_flag(TIF_NOTIFY_RESUME); +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + SetPageReserved(vmalloc_to_page((void *)a)); +} +static inline void +pfm_unreserve_page(unsigned long a) +{ + ClearPageReserved(vmalloc_to_page((void*)a)); +} + +static inline int +pfm_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) +{ + return remap_page_range(vma, from, phys_addr, size, prot); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + spin_lock_irq(&(x)->ctx_lock); + return 0UL; +} + +static inline unsigned long +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} +#endif /* 2.5 vs. 2.4 */ +DEFINE_PER_CPU(unsigned long, pfm_syst_info); +DEFINE_PER_CPU(struct task_struct *, pmu_owner); +DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); +DEFINE_PER_CPU(unsigned long, pmu_activation_number); + + +/* forward declaration */ +static struct file_operations pfm_file_ops; /* * forward declarations */ -static void pfm_reset_pmu(struct task_struct *); +#ifndef CONFIG_SMP static void pfm_lazy_save_regs (struct task_struct *ta); +#endif #if defined(CONFIG_ITANIUM) #include "perfmon_itanium.h" @@ -451,6 +741,8 @@ #include "perfmon_generic.h" #endif +static int pfm_end_notify_user(pfm_context_t *ctx); + static inline void pfm_clear_psr_pp(void) { @@ -503,16 +795,22 @@ ia64_srlz_d(); } +/* + * PMD[i] must be a counter. no check is made + */ static inline unsigned long pfm_read_soft_counter(pfm_context_t *ctx, int i) { - return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val); + return ctx->ctx_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val); } +/* + * PMD[i] must be a counter. no check is made + */ static inline void pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) { - ctx->ctx_soft_pmds[i].val = val & ~pmu_conf.ovfl_val; + ctx->ctx_pmds[i].val = val & ~pmu_conf.ovfl_val; /* * writing to unimplemented part is ignore, so we do not need to * mask off top part @@ -520,18 +818,56 @@ ia64_set_pmd(i, val & pmu_conf.ovfl_val); } -/* - * Generates a unique (per CPU) timestamp - */ -static inline unsigned long -pfm_get_stamp(void) +static pfm_msg_t * +pfm_get_new_msg(pfm_context_t *ctx) { + int idx, next; + + next = (ctx->ctx_msgq_tail+1) % PFM_MAX_MSGS; + + DPRINT(("ctx_fd=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + if (next == ctx->ctx_msgq_head) return NULL; + + idx = ctx->ctx_msgq_tail; + ctx->ctx_msgq_tail = next; + + DPRINT(("ctx=%p head=%d tail=%d msg=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, idx)); + + return ctx->ctx_msgq+idx; +} + +static pfm_msg_t * +pfm_get_next_msg(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + DPRINT(("ctx=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + if (PFM_CTXQ_EMPTY(ctx)) return NULL; + /* - * XXX: must find something more efficient + * get oldest message */ - return ia64_get_itc(); + msg = ctx->ctx_msgq+ctx->ctx_msgq_head; + + /* + * and move forward + */ + ctx->ctx_msgq_head = (ctx->ctx_msgq_head+1) % PFM_MAX_MSGS; + + DPRINT(("ctx=%p head=%d tail=%d type=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, msg->pfm_gen_msg.msg_type)); + + return msg; } +static void +pfm_reset_msgq(pfm_context_t *ctx) +{ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + DPRINT(("ctx=%p msgq reset\n", ctx)); +} + + /* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. @@ -540,7 +876,6 @@ pfm_kvirt_to_pa(unsigned long adr) { __u64 pa = ia64_tpa(adr); - //DBprintk(("kv2pa(%lx-->%lx)\n", adr, pa)); return pa; } @@ -548,17 +883,17 @@ pfm_rvmalloc(unsigned long size) { void *mem; - unsigned long adr; + unsigned long addr; - size=PAGE_ALIGN(size); - mem=vmalloc(size); + size = PAGE_ALIGN(size); + mem = vmalloc(size); if (mem) { //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; + memset(mem, 0, size); + addr = (unsigned long)mem; while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; + pfm_reserve_page(addr); + addr+=PAGE_SIZE; size-=PAGE_SIZE; } } @@ -568,13 +903,14 @@ static void pfm_rvfree(void *mem, unsigned long size) { - unsigned long adr; + unsigned long addr; if (mem) { - adr=(unsigned long) mem; + DPRINT(("freeing physical buffer @%p size=%lu\n", mem, size)); + addr = (unsigned long) mem; while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void*)adr)); - adr+=PAGE_SIZE; + pfm_unreserve_page(addr); + addr+=PAGE_SIZE; size-=PAGE_SIZE; } vfree(mem); @@ -582,201 +918,1489 @@ return; } +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *ctx; + + /* allocate context descriptor */ + ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); + if (ctx) { + memset(ctx, 0, sizeof(pfm_context_t)); + DPRINT(("alloc ctx @%p\n", ctx)); + } + return ctx; +} + +static void +pfm_context_free(pfm_context_t *ctx) +{ + if (ctx) { + DPRINT(("free ctx @%p\n", ctx)); + kfree(ctx); + } +} + +static void +pfm_mask_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, val; + int i; + + DPRINT(("[%d] masking monitoring for [%d]\n", current->pid, task->pid)); + + /* + * monitoring can only be masked as a result of a valid + * counter overflow. In UP, it means that the PMU still + * has an owner. Note that the owner can be different + * from the current task. However the PMU state belongs + * to the owner. + * In SMP, a valid overflow only happens when task is + * current. Therefore if we come here, we know that + * the PMU state belongs to the current task, therefore + * we can access the live registers. + * + * So in both cases, the live register contains the owner's + * state. We can ONLY touch the PMU registers and NOT the PSR. + * + * As a consequence to this call, the thread->pmds[] array + * contains stale information which must be ignored + * when context is reloaded AND monitoring is active (see + * pfm_restart). + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + val = ia64_get_pmd(i); + + if (PMD_IS_COUNTING(i)) { + /* + * we rebuild the full 64 bit value of the counter + */ + ctx->ctx_pmds[i].val += (val & pmu_conf.ovfl_val); + } else { + ctx->ctx_pmds[i].val = val; + } + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val & pmu_conf.ovfl_val)); + } + /* + * mask monitoring by setting the privilege level to 0 + * we cannot use psr.pp/psr.up for this, it is controlled by + * the user + * + * if task is current, modify actual registers, otherwise modify + * thread save state, i.e., what will be restored in pfm_load_regs() + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + ia64_set_pmc(i, th->pmcs[i] & ~0xfUL); + th->pmcs[i] &= ~0xfUL; + } + /* + * make all of this visible + */ + ia64_srlz_d(); +} + /* - * This function gets called from mm/mmap.c:exit_mmap() only when there is a sampling buffer - * attached to the context AND the current task has a mapping for it, i.e., it is the original - * creator of the context. - * - * This function is used to remember the fact that the vma describing the sampling buffer - * has now been removed. It can only be called when no other tasks share the same mm context. + * must always be done with task == current * + * context must be in MASKED state when calling */ -static void -pfm_vm_close(struct vm_area_struct *vma) +static void +pfm_restore_monitoring(struct task_struct *task) { - pfm_smpl_buffer_desc_t *psb = (pfm_smpl_buffer_desc_t *)vma->vm_private_data; + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask; + unsigned long psr, val; + int i; - if (psb == NULL) { - printk(KERN_DEBUG "perfmon: psb is null in [%d]\n", current->pid); + if (task != current) { + printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task->pid, current->pid); return; } + if (CTX_IS_MASKED(ctx) == 0) { + printk(KERN_ERR "perfmon.%d: task[%d] current[%d] invalid state=%d\n", __LINE__, + task->pid, current->pid, ctx->ctx_state); + return; + } + psr = pfm_get_psr(); /* - * Add PSB to list of buffers to free on release_thread() when no more users + * monitoring is masked via the PMC. + * As we restore their value, we do not want each counter to + * restart right away. We stop monitoring using the PSR, + * restore the PMC (and PMD) and then re-establish the psr + * as it was. Note that there can be no pending overflow at + * this point, because monitoring was MASKED. * - * This call is safe because, once the count is zero is cannot be modified anymore. - * This is not because there is no more user of the mm context, that the sampling - * buffer is not being used anymore outside of this task. In fact, it can still - * be accessed from within the kernel by another task (such as the monitored task). - * - * Therefore, we only move the psb into the list of buffers to free when we know - * nobody else is using it. - * The linked list if independent of the perfmon context, because in the case of - * multi-threaded processes, the last thread may not have been involved with - * monitoring however it will be the one removing the vma and it should therefore - * also remove the sampling buffer. This buffer cannot be removed until the vma - * is removed. - * - * This function cannot remove the buffer from here, because exit_mmap() must first - * complete. Given that there is no other vma related callback in the generic code, - * we have created our own with the linked list of sampling buffers to free. The list - * is part of the thread structure. In release_thread() we check if the list is - * empty. If not we call into perfmon to free the buffer and psb. That is the only - * way to ensure a safe deallocation of the sampling buffer which works when - * the buffer is shared between distinct processes or with multi-threaded programs. - * - * We need to lock the psb because the refcnt test and flag manipulation must - * looked like an atomic operation vis a vis pfm_context_exit() + * system-wide session are pinned and self-monitoring + */ + if (ctx->ctx_fl_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* disable dcr pp */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + } else { + pfm_clear_psr_up(); + } + /* + * first, we restore the PMD + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + + if (PMD_IS_COUNTING(i)) { + /* + * we split the 64bit value according to + * counter width + */ + val = ctx->ctx_pmds[i].val & pmu_conf.ovfl_val; + ctx->ctx_pmds[i].val &= ~pmu_conf.ovfl_val; + } else { + val = ctx->ctx_pmds[i].val; + } + ia64_set_pmd(i, val); + + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val)); + } + /* + * restore the PMCs + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + th->pmcs[i] = ctx->ctx_pmcs[i]; + ia64_set_pmc(i, th->pmcs[i]); + DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i])); + } + ia64_srlz_d(); + + /* + * now restore PSR */ - LOCK_PSB(psb); + if (ctx->ctx_fl_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr() | IA64_DCR_PP); + ia64_srlz_i(); + } + pfm_set_psr_l(psr); +} + +static inline void +pfm_save_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; - if (psb->psb_refcnt == 0) { + ia64_srlz_d(); + + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) pmds[i] = ia64_get_pmd(i); + } +} + +/* + * reload from thread state (used for ctxw only) + */ +static inline void +pfm_restore_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + unsigned long val, ovfl_val = pmu_conf.ovfl_val; + + DPRINT(("mask=0x%lx\n", mask)); + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i]; + ia64_set_pmd(i, val); + DPRINT(("pmd[%d]=0x%lx\n", i, val)); + } + ia64_srlz_d(); +} + +/* + * propagate PMD from context to thread-state + */ +static inline void +pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long ovfl_val = pmu_conf.ovfl_val; + unsigned long mask = ctx->ctx_all_pmds[0]; + unsigned long val; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { - psb->psb_next = current->thread.pfm_smpl_buf_list; - current->thread.pfm_smpl_buf_list = psb; + val = ctx->ctx_pmds[i].val; + + /* + * We break up the 64 bit value into 2 pieces + * the lower bits go to the machine state in the + * thread (will be reloaded on ctxsw in). + * The upper part stays in the soft-counter. + */ + if (PMD_IS_COUNTING(i)) { + ctx->ctx_pmds[i].val = val & ~ovfl_val; + val &= ovfl_val; + } + thread->pmds[i] = val; - DBprintk(("[%d] add smpl @%p size %lu to smpl_buf_list psb_flags=0x%x\n", - current->pid, psb->psb_hdr, psb->psb_size, psb->psb_flags)); + DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n", + i, + thread->pmds[i], + ctx->ctx_pmds[i].val)); } - DBprintk(("[%d] clearing psb_flags=0x%x smpl @%p size %lu\n", - current->pid, psb->psb_flags, psb->psb_hdr, psb->psb_size)); +} + +/* + * propagate PMC from context to thread-state + */ +static inline void +pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long mask = ctx->ctx_all_pmcs[0]; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + /* masking 0 with ovfl_val yields 0 */ + thread->pmcs[i] = ctx->ctx_pmcs[i]; + DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i])); + } +} + + + +static inline void +pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask) +{ + int i; + + DPRINT(("mask=0x%lx\n", mask)); + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + ia64_set_pmc(i, pmcs[i]); + DPRINT(("pmc[%d]=0x%lx\n", i, pmcs[i])); + } + ia64_srlz_d(); +} + +static inline void +pfm_restore_ibrs(unsigned long *ibrs, unsigned int nibrs) +{ + int i; + + for (i=0; i < nibrs; i++) { + ia64_set_ibr(i, ibrs[i]); + } + ia64_srlz_i(); +} + +static inline void +pfm_restore_dbrs(unsigned long *dbrs, unsigned int ndbrs) +{ + int i; + + for (i=0; i < ndbrs; i++) { + ia64_set_dbr(i, dbrs[i]); + } + ia64_srlz_d(); +} + +static inline int +pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b) +{ + return memcmp(a, b, sizeof(pfm_uuid_t)); +} + +static inline int +pfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size) +{ + int ret = 0; + if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size); + return ret; +} + + +static inline int +pfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs); + return ret; +} + + + +int +pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt) +{ + pfm_buffer_fmt_t *p; + int ret = 0; + + /* some sanity checks */ + if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL; + + /* we need at least a handler */ + if (fmt->fmt_handler == NULL) return -EINVAL; + /* - * decrement the number vma for the buffer + * XXX: need check validity of fmt_arg_size */ - psb->psb_flags &= ~PSB_HAS_VMA; - UNLOCK_PSB(psb); + LOCK_BUF_FMT_LIST(); + p = pfm_buffer_fmt_list; + + + while (p) { + if (pfm_uuid_cmp(fmt->fmt_uuid, p->fmt_uuid) == 0) break; + p = p->fmt_next; + } + + if (p) { + printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name); + ret = -EBUSY; + } else { + fmt->fmt_prev = NULL; + fmt->fmt_next = pfm_buffer_fmt_list; + pfm_buffer_fmt_list = fmt; + printk(KERN_ERR "perfmon: added sampling format %s\n", fmt->fmt_name); + } + UNLOCK_BUF_FMT_LIST(); + + return ret; +} + +int +pfm_unregister_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t *p; + int ret = 0; + + LOCK_BUF_FMT_LIST(); + p = pfm_buffer_fmt_list; + while (p) { + if (memcmp(uuid, p->fmt_uuid, sizeof(pfm_uuid_t)) == 0) break; + p = p->fmt_next; + } + if (p) { + if (p->fmt_prev) + p->fmt_prev->fmt_next = p->fmt_next; + else + pfm_buffer_fmt_list = p->fmt_next; + + if (p->fmt_next) + p->fmt_next->fmt_prev = p->fmt_prev; + + printk(KERN_ERR "perfmon: removed sampling format: %s\n", p->fmt_name); + p->fmt_next = p->fmt_prev = NULL; + } else { + printk(KERN_ERR "perfmon: cannot unregister format, not found\n"); + ret = -EINVAL; + } + UNLOCK_BUF_FMT_LIST(); + + return ret; + } /* - * This function is called from pfm_destroy_context() and also from pfm_inherit() - * to explicitly remove the sampling buffer mapping from the user level address space. + * find a buffer format based on its uuid */ +static pfm_buffer_fmt_t * +pfm_find_buffer_fmt(pfm_uuid_t uuid, int nolock) +{ + pfm_buffer_fmt_t *p; + + LOCK_BUF_FMT_LIST(); + for (p = pfm_buffer_fmt_list; p ; p = p->fmt_next) { + if (pfm_uuid_cmp(uuid, p->fmt_uuid) == 0) break; + } + + UNLOCK_BUF_FMT_LIST(); + + return p; +} + static int -pfm_remove_smpl_mapping(struct task_struct *task) +pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) +{ + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + if (is_syswide) { + /* + * cannot mix system wide and per-task sessions + */ + if (pfm_sessions.pfs_task_sessions > 0UL) { + DPRINT(("system wide not possible, %u conflicting task_sessions\n", + pfm_sessions.pfs_task_sessions)); + goto abort; + } + + if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict; + + DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); + + pfm_sessions.pfs_sys_session[cpu] = task; + + pfm_sessions.pfs_sys_sessions++ ; + + } else { + if (pfm_sessions.pfs_sys_sessions) goto abort; + pfm_sessions.pfs_task_sessions++; + } + + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + UNLOCK_PFS(); + + return 0; + +error_conflict: + DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", + pfm_sessions.pfs_sys_session[cpu]->pid, + smp_processor_id())); +abort: + UNLOCK_PFS(); + + return -EBUSY; + +} + +static int +pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu) { - pfm_context_t *ctx = task->thread.pfm_context; - pfm_smpl_buffer_desc_t *psb; - int r; /* - * some sanity checks first + * validy checks on cpu_mask have been done upstream */ - if (ctx == NULL || task->mm == NULL || ctx->ctx_smpl_vaddr == 0 || ctx->ctx_psb == NULL) { - printk(KERN_DEBUG "perfmon: invalid context mm=%p\n", task->mm); - return -1; + LOCK_PFS(); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + + if (is_syswide) { + pfm_sessions.pfs_sys_session[cpu] = NULL; + /* + * would not work with perfmon+more than one bit in cpu_mask + */ + if (ctx && ctx->ctx_fl_using_dbreg) { + if (pfm_sessions.pfs_sys_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx); + } else { + pfm_sessions.pfs_sys_use_dbregs--; + } + } + pfm_sessions.pfs_sys_sessions--; + } else { + pfm_sessions.pfs_task_sessions--; } - psb = ctx->ctx_psb; + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + UNLOCK_PFS(); + + return 0; +} + +/* + * removes virtual mapping of the sampling buffer. + * IMPORTANT: cannot be called with interrupts disable, e.g. inside + * a PROTECT_CTX() section. + */ +static int +pfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long size) +{ + int r; + + /* sanity checks */ + if (task->mm == NULL || size == 0UL || vaddr == NULL) { + printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task->pid, task->mm); + return -EINVAL; + } + + DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size)); + /* + * does the actual unmapping + */ down_write(&task->mm->mmap_sem); - r = do_munmap(task->mm, ctx->ctx_smpl_vaddr, psb->psb_size); + DPRINT(("down_write done smpl_vaddr=%p size=%lu\n", vaddr, size)); + + r = do_munmap(task->mm, (unsigned long)vaddr, size); up_write(&task->mm->mmap_sem); if (r !=0) { - printk(KERN_DEBUG "perfmon: pid %d unable to unmap sampling buffer " - "@0x%lx size=%ld\n", task->pid, ctx->ctx_smpl_vaddr, psb->psb_size); + printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task->pid, vaddr, size); } - DBprintk(("[%d] do_unmap(0x%lx, %ld)=%d refcnt=%lu psb_flags=0x%x\n", - task->pid, ctx->ctx_smpl_vaddr, psb->psb_size, r, psb->psb_refcnt, psb->psb_flags)); + DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r)); return 0; } -static pfm_context_t * -pfm_context_alloc(void) +/* + * free actual physical storage used by sampling buffer + */ +#if 0 +static int +pfm_free_smpl_buffer(pfm_context_t *ctx) +{ + pfm_buffer_fmt_t *fmt; + + if (ctx->ctx_smpl_hdr == NULL) goto invalid_free; + + /* + * we won't use the buffer format anymore + */ + fmt = ctx->ctx_buf_fmt; + + DPRINT(("sampling buffer @%p size %lu vaddr=%p\n", + ctx->ctx_smpl_hdr, + ctx->ctx_smpl_size, + ctx->ctx_smpl_vaddr)); + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + + /* + * free the buffer + */ + pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size); + + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_smpl_size = 0UL; + + return 0; + +invalid_free: + printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", current->pid); + return -EINVAL; +} +#endif + +static inline void +pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt) +{ + if (fmt == NULL) return; + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + +} + +/* + * pfmfs should _never_ be mounted by userland - too much of security hassle, + * no real gain from having the whole whorehouse mounted. So we don't need + * any operations on the root directory. However, we need a non-trivial + * d_name - pfm: will go nicely and kill the special-casing in procfs. + */ +static struct vfsmount *pfmfs_mnt; +#define PFMFS_MAGIC 0xa0b4d889 + +#ifdef PFM_COMPILED_FOR_2_4 + +static int +pfmfs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = PFMFS_MAGIC; + buf->f_bsize = 1024; + buf->f_namelen = 255; + return 0; +} + +static struct super_operations pfmfs_ops = { + statfs: pfmfs_statfs, +}; + +static struct super_block * +pfmfs_read_super(struct super_block *sb, void *data, int silent) +{ + struct inode *root = new_inode(sb); + if (!root) + return NULL; + root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; + root->i_uid = root->i_gid = 0; + root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; + sb->s_blocksize = 1024; + sb->s_blocksize_bits = 10; + sb->s_magic = PFMFS_MAGIC; + sb->s_op = &pfmfs_ops; + sb->s_root = d_alloc(NULL, &(const struct qstr) { "pfm:", 4, 0 }); + if (!sb->s_root) { + iput(root); + return NULL; + } + sb->s_root->d_sb = sb; + sb->s_root->d_parent = sb->s_root; + d_instantiate(sb->s_root, root); + return sb; +} + +//static DECLARE_FSTYPE(pfm_fs_type, "pfmfs", pfmfs_read_super, FS_NOMOUNT); +static struct file_system_type pfm_fs_type = { + name: "pfmfs", + read_super: pfmfs_read_super, + fs_flags: FS_NOMOUNT, +}; + +#else /* ! COMPILED_FOR_2_4 */ + +static struct super_block * +pfmfs_get_sb(struct file_system_type *fs_type, int flags, char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); +} + +static struct file_system_type pfm_fs_type = { + .name = "pfmfs", + .get_sb = pfmfs_get_sb, + .kill_sb = kill_anon_super, +}; +#endif /* COMPILED_FOR_2_4 */ + +static int __init +init_pfm_fs(void) +{ + int err = register_filesystem(&pfm_fs_type); + if (!err) { + pfmfs_mnt = kern_mount(&pfm_fs_type); + err = PTR_ERR(pfmfs_mnt); + if (IS_ERR(pfmfs_mnt)) + unregister_filesystem(&pfm_fs_type); + else + err = 0; + } + return err; +} + +static void __exit +exit_pfm_fs(void) +{ + unregister_filesystem(&pfm_fs_type); + mntput(pfmfs_mnt); +} + +static loff_t +pfm_lseek(struct file *file, loff_t offset, int whence) +{ + DPRINT(("pfm_lseek called\n")); + return -ESPIPE; +} + +static ssize_t +pfm_do_read(struct file *filp, char *buf, size_t size, loff_t *ppos) { pfm_context_t *ctx; + pfm_msg_t *msg; + ssize_t ret; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return -EINVAL; + } - /* allocate context descriptor */ - ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); - if (ctx) memset(ctx, 0, sizeof(pfm_context_t)); - - return ctx; + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", current->pid); + return -EINVAL; + } + + /* + * check even when there is no message + */ + if (size < sizeof(pfm_msg_t)) { + DPRINT(("message is too small ctx=%p (>=%ld)\n", ctx, sizeof(pfm_msg_t))); + return -EINVAL; + } + /* + * seeks are not allowed on message queues + */ + if (ppos != &filp->f_pos) return -ESPIPE; + + PROTECT_CTX(ctx, flags); + + /* + * put ourselves on the wait queue + */ + add_wait_queue(&ctx->ctx_msgq_wait, &wait); + + + for(;;) { + /* + * check wait queue + */ + + set_current_state(TASK_INTERRUPTIBLE); + + DPRINT(("head=%d tail=%d\n", ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + ret = 0; + if(PFM_CTXQ_EMPTY(ctx) == 0) break; + + UNPROTECT_CTX(ctx, flags); + + /* + * check non-blocking read + */ + ret = -EAGAIN; + if(filp->f_flags & O_NONBLOCK) break; + + /* + * check pending signals + */ + if(signal_pending(current)) { + ret = -EINTR; + break; + } + /* + * no message, so wait + */ + schedule(); + + PROTECT_CTX(ctx, flags); + } + DPRINT(("[%d] back to running ret=%ld\n", current->pid, ret)); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctx->ctx_msgq_wait, &wait); + + if (ret < 0) goto abort; + + ret = -EINVAL; + msg = pfm_get_next_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_read no msg for ctx=%p [%d]\n", ctx, current->pid); + goto abort_locked; + } + + DPRINT(("[%d] fd=%d type=%d\n", current->pid, msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); + + ret = -EFAULT; + if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); + +abort_locked: + UNPROTECT_CTX(ctx, flags); +abort: + return ret; } -static void -pfm_context_free(pfm_context_t *ctx) +static ssize_t +pfm_read(struct file *filp, char *buf, size_t size, loff_t *ppos) +{ + int oldvar, ret; + + oldvar = pfm_debug_var; + pfm_debug_var = pfm_sysctl.debug_pfm_read; + ret = pfm_do_read(filp, buf, size, ppos); + pfm_debug_var = oldvar; + return ret; +} + +static ssize_t +pfm_write(struct file *file, const char *ubuf, + size_t size, loff_t *ppos) +{ + DPRINT(("pfm_write called\n")); + return -EINVAL; +} + +static unsigned int +pfm_poll(struct file *filp, poll_table * wait) { - if (ctx) kfree(ctx); + pfm_context_t *ctx; + unsigned long flags; + unsigned int mask = 0; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return 0; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", current->pid); + return 0; + } + + + DPRINT(("pfm_poll ctx_fd=%d before poll_wait\n", ctx->ctx_fd)); + + poll_wait(filp, &ctx->ctx_msgq_wait, wait); + + PROTECT_CTX(ctx, flags); + + if (PFM_CTXQ_EMPTY(ctx) == 0) + mask = POLLIN | POLLRDNORM; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("pfm_poll ctx_fd=%d mask=0x%x\n", ctx->ctx_fd, mask)); + + return mask; } static int -pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) +pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned long page; + DPRINT(("pfm_ioctl called\n")); + return -EINVAL; +} - DBprintk(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); +/* + * context is locked when coming here + */ +static inline int +pfm_do_fasync(int fd, struct file *filp, pfm_context_t *ctx, int on) +{ + int ret; - while (size > 0) { - page = pfm_kvirt_to_pa(buf); + ret = fasync_helper (fd, filp, on, &ctx->ctx_async_queue); - if (remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM; + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); - addr += PAGE_SIZE; - buf += PAGE_SIZE; - size -= PAGE_SIZE; + return ret; +} + +static int +pfm_fasync(int fd, struct file *filp, int on) +{ + pfm_context_t *ctx; + unsigned long flags; + int ret; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_fasync bad magic [%d]\n", current->pid); + return -EBADF; } - return 0; + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + + PROTECT_CTX(ctx, flags); + + ret = pfm_do_fasync(fd, filp, ctx, on); + + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); + + UNPROTECT_CTX(ctx, flags); + + return ret; } +#ifdef CONFIG_SMP /* - * counts the number of PMDS to save per entry. - * This code is generic enough to accommodate more than 64 PMDS when they become available + * this function is exclusively called from pfm_close(). + * The context is not protected at that time, nor are interrupts + * on the remote CPU. That's necessary to avoid deadlocks. */ -static unsigned long -pfm_smpl_entry_size(unsigned long *which, unsigned long size) +static void +pfm_syswide_force_stop(void *info) { - unsigned long i, res = 0; + pfm_context_t *ctx = (pfm_context_t *)info; + struct pt_regs *regs = ia64_task_regs(current); + struct task_struct *owner; - for (i=0; i < size; i++, which++) res += hweight64(*which); + if (ctx->ctx_cpu != smp_processor_id()) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop for CPU%d but on CPU%d\n", + ctx->ctx_cpu, + smp_processor_id()); + return; + } + owner = GET_PMU_OWNER(); + if (owner != ctx->ctx_task) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected owner [%d] instead of [%d]\n", + smp_processor_id(), + owner->pid, ctx->ctx_task->pid); + return; + } + if (GET_PMU_CTX() != ctx) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected ctx %p instead of %p\n", + smp_processor_id(), + GET_PMU_CTX(), ctx); + return; + } - DBprintk(("weight=%ld\n", res)); + DPRINT(("[%d] on CPU%d forcing system wide stop for [%d]\n", current->pid, smp_processor_id(), ctx->ctx_task->pid)); + /* + * Update local PMU + */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + ia64_srlz_i(); + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); + + pfm_clear_psr_pp(); + + /* + * also stop monitoring in the local interrupted task + */ + ia64_psr(regs)->pp = 0; + + SET_PMU_OWNER(NULL, NULL); +} + +static void +pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx) +{ + int ret; - return res; + DPRINT(("[%d] calling CPU%d for cleanup\n", current->pid, ctx->ctx_cpu)); + ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 0, 1); + DPRINT(("[%d] called CPU%d for cleanup ret=%d\n", current->pid, ctx->ctx_cpu, ret)); } +#endif /* CONFIG_SMP */ /* - * Allocates the sampling buffer and remaps it into caller's address space + * called either on explicit close() or from exit_files(). + * + * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero (fput()),i.e, + * last task to access the file. Nobody else can access the file at this point. + * + * When called from exit_files(), the VMA has been freed because exit_mm() + * is executed before exit_files(). + * + * When called from exit_files(), the current task is not yet ZOMBIE but we will + * flush the PMU state to the context. This means * that when we see the context + * state as TERMINATED we are guranteed to have the latest PMU state available, + * even if the task itself is in the middle of being ctxsw out. */ +static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static int -pfm_smpl_buffer_alloc(pfm_context_t *ctx, unsigned long *which_pmds, unsigned long entries, - void **user_vaddr) +pfm_close(struct inode *inode, struct file *filp) { - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = NULL; - unsigned long size, regcount; - void *smpl_buf; - pfm_smpl_buffer_desc_t *psb; + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_vaddr = NULL; + void *smpl_buf_addr = NULL; + int free_possible = 1; + { u64 psr = pfm_get_psr(); + BUG_ON((psr & IA64_PSR_I) == 0UL); + } - /* note that regcount might be 0, in this case only the header for each - * entry will be recorded. + DPRINT(("pfm_close called private=%p\n", filp->private_data)); + + if (!inode) { + printk(KERN_ERR "pfm_close: NULL inode\n"); + return 0; + } + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_close: bad magic [%d]\n", current->pid); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + PROTECT_CTX(ctx, flags); + + /* + * remove our file from the async queue, if we use it */ - regcount = pfm_smpl_entry_size(which_pmds, 1); + if (filp->f_flags & FASYNC) { + DPRINT(("[%d] before async_queue=%p\n", current->pid, ctx->ctx_async_queue)); + pfm_do_fasync (-1, filp, ctx, 0); + DPRINT(("[%d] after async_queue=%p\n", current->pid, ctx->ctx_async_queue)); + } - if ((sizeof(perfmon_smpl_hdr_t)+ entries*sizeof(perfmon_smpl_entry_t)) <= entries) { - DBprintk(("requested entries %lu is too big\n", entries)); - return -EINVAL; + task = PFM_CTX_TASK(ctx); + + DPRINT(("[%d] ctx_state=%d\n", current->pid, ctx->ctx_state)); + + if (CTX_IS_UNLOADED(ctx) || CTX_IS_TERMINATED(ctx)) { + goto doit; + } + + regs = ia64_task_regs(task); + + /* + * context still loaded/masked and self monitoring, + * we stop/unload and we destroy right here + * + * We always go here for system-wide sessions + */ + if (task == current) { +#ifdef CONFIG_SMP + /* + * the task IS the owner but it migrated to another CPU: that's bad + * but we must handle this cleanly. Unfortunately, the kernel does + * not provide a mechanism to block migration (while the context is loaded). + * + * We need to release the resource on the ORIGINAL cpu. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + + UNPROTECT_CTX(ctx, flags); + + pfm_syswide_cleanup_other_cpu(ctx); + + PROTECT_CTX(ctx, flags); + + /* + * short circuit pfm_context_unload(); + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + CTX_UNLOADED(ctx); + + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); + } else +#endif /* CONFIG_SMP */ + { + + DPRINT(("forcing unload on [%d]\n", current->pid)); + /* + * stop and unload, returning with state UNLOADED + * and session unreserved. + */ + pfm_context_unload(ctx, NULL, 0, regs); + + CTX_TERMINATED(ctx); + + DPRINT(("[%d] ctx_state=%d\n", current->pid, ctx->ctx_state)); + } + goto doit; + } + + /* + * The task is currently blocked or will block after an overflow. + * we must force it to wakeup to get out of the + * MASKED state and transition to the unloaded state by itself + */ + if (CTX_IS_MASKED(ctx) && CTX_OVFL_NOBLOCK(ctx) == 0) { + + /* + * set a "partial" zombie state to be checked + * upon return from down() in pfm_handle_work(). + * + * We cannot use the ZOMBIE state, because it is checked + * by pfm_load_regs() which is called upon wakeup from down(). + * In such cas, it would free the context and then we would + * return to pfm_handle_work() which would access the + * stale context. Instead, we set a flag invisible to pfm_load_regs() + * but visible to pfm_handle_work(). + * + * For some window of time, we have a zombie context with + * ctx_state = MASKED and not ZOMBIE + */ + ctx->ctx_fl_going_zombie = 1; + + /* + * force task to wake up from MASKED state + */ + up(&ctx->ctx_restart_sem); + + DPRINT(("waking up ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + + /* + * put ourself to sleep waiting for the other + * task to report completion + * + * the context is protected by mutex, therefore there + * is no risk of being notified of completion before + * begin actually on the waitq. + */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ctx->ctx_zombieq, &wait); + + UNPROTECT_CTX(ctx, flags); + + /* + * XXX: check for signals : + * - ok of explicit close + * - not ok when coming from exit_files() + */ + schedule(); + + DPRINT(("woken up ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + + PROTECT_CTX(ctx, flags); + + remove_wait_queue(&ctx->ctx_zombieq, &wait); + set_current_state(TASK_RUNNING); + + /* + * context is terminated at this point + */ + DPRINT(("after zombie wakeup ctx_state=%d for [%d]\n", ctx->ctx_state, current->pid)); + } + else { +#ifdef CONFIG_SMP + /* + * switch context to zombie state + */ + CTX_ZOMBIE(ctx); + + DPRINT(("zombie ctx for [%d]\n", task->pid)); + /* + * cannot free the context on the spot. deferred until + * the task notices the ZOMBIE state + */ + free_possible = 0; +#else + pfm_context_unload(ctx, NULL, 0, regs); +#endif + } + +doit: /* cannot assume task is defined from now on */ + /* + * the context is still attached to a task (possibly current) + * we cannot destroy it right now + */ + /* + * remove virtual mapping, if any. will be NULL when + * called from exit_files(). + */ + if (ctx->ctx_smpl_vaddr) { + smpl_buf_vaddr = ctx->ctx_smpl_vaddr; + smpl_buf_size = ctx->ctx_smpl_size; + ctx->ctx_smpl_vaddr = NULL; + } + + /* + * we must fre the sampling buffer right here because + * we cannot rely on it being cleaned up later by the + * monitored task. It is not possible to free vmalloc'ed + * memory in pfm_load_regs(). Instead, we remove the buffer + * now. should there be subsequent PMU overflow originally + * meant for sampling, the will be converted to spurious + * and that's fine because the monitoring tools is gone anyway. + */ + if (ctx->ctx_smpl_hdr) { + smpl_buf_addr = ctx->ctx_smpl_hdr; + smpl_buf_size = ctx->ctx_smpl_size; + /* no more sampling */ + ctx->ctx_smpl_hdr = NULL; + } + + + DPRINT(("[%d] ctx_state=%d free_possible=%d vaddr=%p addr=%p size=%lu\n", + current->pid, + ctx->ctx_state, + free_possible, + smpl_buf_vaddr, + smpl_buf_addr, + smpl_buf_size)); + + if (smpl_buf_addr) pfm_exit_smpl_buffer(ctx->ctx_buf_fmt); + + /* + * UNLOADED and TERMINATED mean that the session has already been + * unreserved. + */ + if (CTX_IS_ZOMBIE(ctx)) { + pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu); + } + + /* + * disconnect file descriptor from context must be done + * before we unlock. + */ + filp->private_data = NULL; + + /* + * if we free on the spot, the context is now completely unreacheable + * from the callers side. The monitored task side is also cut, so we + * can freely cut. + * + * If we have a deferred free, only the caller side is disconnected. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * if there was a mapping, then we systematically remove it + * at this point. Cannot be done inside critical section + * because some VM function reenables interrupts. + * + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (smpl_buf_vaddr) pfm_remove_smpl_mapping(current, smpl_buf_vaddr, smpl_buf_size); + if (smpl_buf_addr) pfm_rvfree(smpl_buf_addr, smpl_buf_size); + + /* + * return the memory used by the context + */ + if (free_possible) pfm_context_free(ctx); + + return 0; +} + +static int +pfm_no_open(struct inode *irrelevant, struct file *dontcare) +{ + DPRINT(("pfm_no_open called\n")); + return -ENXIO; +} + +static struct file_operations pfm_file_ops = { + .llseek = pfm_lseek, + .read = pfm_read, + .write = pfm_write, + .poll = pfm_poll, + .ioctl = pfm_ioctl, + .open = pfm_no_open, /* special open code to disallow open via /proc */ + .fasync = pfm_fasync, + .release = pfm_close +}; + +static int +pfmfs_delete_dentry(struct dentry *dentry) +{ + return 1; +} +static struct dentry_operations pfmfs_dentry_operations = { + d_delete: pfmfs_delete_dentry, +}; + + +static int +pfm_alloc_fd(struct file **cfile) +{ + int fd, ret = 0; + struct file *file = NULL; + struct inode * inode; + char name[32]; + struct qstr this; + + fd = get_unused_fd(); + if (fd < 0) return -ENFILE; + + ret = -ENFILE; + + file = get_empty_filp(); + if (!file) goto out; + + /* + * allocate a new inode + */ + inode = new_inode(pfmfs_mnt->mnt_sb); + if (!inode) goto out; + + DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); + + inode->i_sb = pfmfs_mnt->mnt_sb; + inode->i_mode = S_IFCHR|S_IRUGO; + inode->i_sock = 0; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; + + ret = -ENOMEM; + + /* + * allocate a new dcache entry + */ + file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); + if (!file->f_dentry) goto out; + + file->f_dentry->d_op = &pfmfs_dentry_operations; + + d_add(file->f_dentry, inode); + file->f_vfsmnt = mntget(pfmfs_mnt); + + file->f_op = &pfm_file_ops; + file->f_mode = FMODE_READ; + file->f_flags = O_RDONLY; + file->f_pos = 0; + + /* + * may have to delay until context is attached? + */ + fd_install(fd, file); + + /* + * the file structure we will use + */ + *cfile = file; + + return fd; +out: + if (file) put_filp(file); + put_unused_fd(fd); + return ret; +} + +static void +pfm_free_fd(int fd, struct file *file) +{ + if (file) put_filp(file); + put_unused_fd(fd); +} + +/* + * This function gets called from mm/mmap.c:exit_mmap() only when there is a sampling buffer + * attached to the context AND the current task has a mapping for it, i.e., it is the original + * creator of the context. + * + * This function is used to remember the fact that the vma describing the sampling buffer + * has now been removed. It can only be called when no other tasks share the same mm context. + * + */ +static void +pfm_vm_close(struct vm_area_struct *vma) +{ + pfm_context_t *ctx = (pfm_context_t *)vma->vm_private_data; + unsigned long flags; + + PROTECT_CTX(ctx, flags); + ctx->ctx_smpl_vaddr = NULL; + UNPROTECT_CTX(ctx, flags); + DPRINT(("[%d] clearing vaddr for ctx %p\n", current->pid, ctx)); +} + +static int +pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) +{ + unsigned long page; + + DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); + + while (size > 0) { + page = pfm_kvirt_to_pa(buf); + + if (pfm_remap_page_range(vma, addr, page, PAGE_SIZE, PAGE_READONLY)) return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; } + return 0; +} + +/* + * allocate a sampling buffer and remaps it into the user address space of the task + */ +static int +pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma = NULL; + unsigned long size; + void *smpl_buf; + /* - * 1 buffer hdr and for each entry a header + regcount PMDs to save + * the fixed header + requested size and align to page boundary */ - size = PAGE_ALIGN( sizeof(perfmon_smpl_hdr_t) - + entries * (sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64))); + size = PAGE_ALIGN(rsize); - DBprintk(("sampling buffer size=%lu bytes\n", size)); + DPRINT(("sampling buffer rsize=%lu size=%lu bytes\n", rsize, size)); /* * check requested size to avoid Denial-of-service attacks - * XXX: may have to refine this test + * XXX: may have to refine this test * Check against address space limit. * - * if ((mm->total_vm << PAGE_SHIFT) + len> current->rlim[RLIMIT_AS].rlim_cur) + * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) * return -ENOMEM; */ - if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; + if (size > task->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; /* * We do the easy to undo allocations first. @@ -785,69 +2409,40 @@ */ smpl_buf = pfm_rvmalloc(size); if (smpl_buf == NULL) { - DBprintk(("Can't allocate sampling buffer\n")); + DPRINT(("Can't allocate sampling buffer\n")); return -ENOMEM; } - DBprintk(("smpl_buf @%p\n", smpl_buf)); - - /* allocate sampling buffer descriptor now */ - psb = kmalloc(sizeof(*psb), GFP_KERNEL); - if (psb == NULL) { - DBprintk(("Can't allocate sampling buffer descriptor\n")); - goto error_kmalloc; - } + DPRINT(("[%d] smpl_buf @%p\n", current->pid, smpl_buf)); /* allocate vma */ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!vma) { - DBprintk(("Cannot allocate vma\n")); + DPRINT(("Cannot allocate vma\n")); goto error_kmem; } /* * partially initialize the vma for the sampling buffer * * The VM_DONTCOPY flag is very important as it ensures that the mapping - * will never be inherited for any child process (via fork()) which is always + * will never be inherited for any child process (via fork()) which is always * what we want. */ vma->vm_mm = mm; vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED|VM_DONTCOPY; vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ - vma->vm_ops = &pfm_vm_ops; /* necesarry to get the close() callback */ + vma->vm_ops = &pfm_vm_ops; vma->vm_pgoff = 0; vma->vm_file = NULL; - vma->vm_private_data = psb; /* information needed by the pfm_vm_close() function */ + vma->vm_private_data = ctx; /* information needed by the pfm_vm_close() function */ /* * Now we have everything we need and we can initialize * and connect all the data structures */ - psb->psb_hdr = smpl_buf; - psb->psb_addr = ((char *)smpl_buf)+sizeof(perfmon_smpl_hdr_t); /* first entry */ - psb->psb_size = size; /* aligned size */ - psb->psb_index = 0; - psb->psb_entries = entries; - psb->psb_refcnt = 1; - psb->psb_flags = PSB_HAS_VMA; - - spin_lock_init(&psb->psb_lock); - - /* - * XXX: will need to do cacheline alignment to avoid false sharing in SMP mode and - * multitask monitoring. - */ - psb->psb_entry_size = sizeof(perfmon_smpl_entry_t) + regcount*sizeof(u64); - - DBprintk(("psb @%p entry_size=%ld hdr=%p addr=%p refcnt=%lu psb_flags=0x%x\n", - (void *)psb,psb->psb_entry_size, (void *)psb->psb_hdr, - (void *)psb->psb_addr, psb->psb_refcnt, psb->psb_flags)); - - /* initialize some of the fields of user visible buffer header */ - psb->psb_hdr->hdr_version = PFM_SMPL_VERSION; - psb->psb_hdr->hdr_entry_size = psb->psb_entry_size; - psb->psb_hdr->hdr_pmds[0] = which_pmds[0]; + ctx->ctx_smpl_hdr = smpl_buf; + ctx->ctx_smpl_size = size; /* aligned size */ /* * Let's do the difficult operations next. @@ -855,24 +2450,23 @@ * now we atomically find some area in the address space and * remap the buffer in it. */ - down_write(¤t->mm->mmap_sem); - + down_write(&task->mm->mmap_sem); /* find some free area in address space, must have mmap sem held */ vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS); if (vma->vm_start == 0UL) { - DBprintk(("Cannot find unmapped area for size %ld\n", size)); - up_write(¤t->mm->mmap_sem); + DPRINT(("Cannot find unmapped area for size %ld\n", size)); + up_write(&task->mm->mmap_sem); goto error; } vma->vm_end = vma->vm_start + size; - DBprintk(("entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, vma->vm_start)); + DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start)); - /* can only be applied to current, need to have the mm semaphore held when called */ + /* can only be applied to current task, need to have the mm semaphore held when called */ if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { - DBprintk(("Can't remap buffer\n")); - up_write(¤t->mm->mmap_sem); + DPRINT(("Can't remap buffer\n")); + up_write(&task->mm->mmap_sem); goto error; } @@ -884,412 +2478,385 @@ mm->total_vm += size >> PAGE_SHIFT; - up_write(¤t->mm->mmap_sem); - - /* store which PMDS to record */ - ctx->ctx_smpl_regs[0] = which_pmds[0]; - - - /* link to perfmon context */ - ctx->ctx_psb = psb; + up_write(&task->mm->mmap_sem); /* - * keep track of user level virtual address + * keep track of user level virtual address */ - ctx->ctx_smpl_vaddr = *(unsigned long *)user_vaddr = vma->vm_start; + ctx->ctx_smpl_vaddr = (void *)vma->vm_start; + *(unsigned long *)user_vaddr = vma->vm_start; return 0; error: kmem_cache_free(vm_area_cachep, vma); error_kmem: - kfree(psb); -error_kmalloc: pfm_rvfree(smpl_buf, size); + return -ENOMEM; } +/* + * XXX: do something better here + */ static int -pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask) +pfm_bad_permissions(struct task_struct *task) { - unsigned long m, undo_mask; - unsigned int n, i; - - /* - * validy checks on cpu_mask have been done upstream - */ - LOCK_PFS(); - - if (is_syswide) { - /* - * cannot mix system wide and per-task sessions - */ - if (pfm_sessions.pfs_task_sessions > 0UL) { - DBprintk(("system wide not possible, %u conflicting task_sessions\n", - pfm_sessions.pfs_task_sessions)); - goto abort; - } + /* stolen from bad_signal() */ + return (current->session != task->session) + && (current->euid ^ task->suid) && (current->euid ^ task->uid) + && (current->uid ^ task->suid) && (current->uid ^ task->uid); +} - m = cpu_mask; undo_mask = 0UL; n = 0; - DBprintk(("cpu_mask=0x%lx\n", cpu_mask)); - for(i=0; m; i++, m>>=1) { +static int +pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) +{ + int ctx_flags; - if ((m & 0x1) == 0UL) continue; + /* valid signal */ - if (pfm_sessions.pfs_sys_session[i]) goto undo; + ctx_flags = pfx->ctx_flags; - DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id())); + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { - pfm_sessions.pfs_sys_session[i] = task; - undo_mask |= 1UL << i; - n++; + /* + * cannot block in this mode + */ + if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { + DPRINT(("cannot use blocking mode when in system wide monitoring\n")); + return -EINVAL; } - pfm_sessions.pfs_sys_sessions += n; } else { - if (pfm_sessions.pfs_sys_sessions) goto abort; - pfm_sessions.pfs_task_sessions++; } - DBprintk(("task_sessions=%u sys_session[%d]=%d", - pfm_sessions.pfs_task_sessions, - smp_processor_id(), pfm_sessions.pfs_sys_session[smp_processor_id()] ? 1 : 0)); - UNLOCK_PFS(); - return 0; -undo: - DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n", - pfm_sessions.pfs_sys_session[i]->pid, i)); - - for(i=0; undo_mask; i++, undo_mask >>=1) { - pfm_sessions.pfs_sys_session[i] = NULL; - } -abort: - UNLOCK_PFS(); - - return -EBUSY; + /* probably more to add here */ + return 0; } static int -pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask) +pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, + unsigned int cpu, pfarg_context_t *arg) { - pfm_context_t *ctx; - unsigned long m; - unsigned int n, i; + pfm_buffer_fmt_t *fmt = NULL; + unsigned long size = 0UL; + void *uaddr = NULL; + void *fmt_arg = NULL; + int ret = 0; +#define PFM_CTXARG_BUF_ARG(a) (pfm_buffer_fmt_t *)(a+1) - ctx = task ? task->thread.pfm_context : NULL; + /* invoke and lock buffer format, if found */ + fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id, 0); + if (fmt == NULL) { + DPRINT(("[%d] cannot find buffer format\n", task->pid)); + return -EINVAL; + } /* - * validy checks on cpu_mask have been done upstream + * buffer argument MUST be contiguous to pfarg_context_t */ - LOCK_PFS(); + if (fmt->fmt_arg_size) fmt_arg = PFM_CTXARG_BUF_ARG(arg); - DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n", - task->pid, - pfm_sessions.pfs_sys_sessions, - pfm_sessions.pfs_task_sessions, - pfm_sessions.pfs_sys_use_dbregs, - is_syswide, - cpu_mask)); + ret = pfm_buf_fmt_validate(fmt, task, ctx_flags, cpu, fmt_arg); + DPRINT(("[%d] after validate(0x%x,%d,%p)=%d\n", task->pid, ctx_flags, cpu, fmt_arg, ret)); - if (is_syswide) { - m = cpu_mask; n = 0; - for(i=0; m; i++, m>>=1) { - if ((m & 0x1) == 0UL) continue; - pfm_sessions.pfs_sys_session[i] = NULL; - n++; - } - /* - * would not work with perfmon+more than one bit in cpu_mask + if (ret) goto error; + + /* link buffer format and context */ + ctx->ctx_buf_fmt = fmt; + + /* + * check if buffer format wants to use perfmon buffer allocation/mapping service + */ + ret = pfm_buf_fmt_getsize(fmt, task, ctx_flags, cpu, fmt_arg, &size); + if (ret) goto error; + + if (size) { + /* + * buffer is always remapped into the caller's address space */ - if (ctx && ctx->ctx_fl_using_dbreg) { - if (pfm_sessions.pfs_sys_use_dbregs == 0) { - printk(KERN_DEBUG "perfmon: invalid release for [%d] " - "sys_use_dbregs=0\n", task->pid); - } else { - pfm_sessions.pfs_sys_use_dbregs--; - } - } - pfm_sessions.pfs_sys_sessions -= n; + ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); + if (ret) goto error; - DBprintk(("CPU%d sys_sessions=%u\n", - smp_processor_id(), pfm_sessions.pfs_sys_sessions)); - } else { - pfm_sessions.pfs_task_sessions--; - DBprintk(("[%d] task_sessions=%u\n", - task->pid, pfm_sessions.pfs_task_sessions)); + /* keep track of user address of buffer */ + arg->ctx_smpl_vaddr = uaddr; } + ret = pfm_buf_fmt_init(fmt, task, ctx->ctx_smpl_hdr, ctx_flags, cpu, fmt_arg); - UNLOCK_PFS(); - - return 0; +error: + return ret; } -/* - * XXX: do something better here - */ -static int -pfm_bad_permissions(struct task_struct *task) +static void +pfm_reset_pmu_state(pfm_context_t *ctx) { - /* stolen from bad_signal() */ - return (current->session != task->session) - && (current->euid ^ task->suid) && (current->euid ^ task->uid) - && (current->uid ^ task->suid) && (current->uid ^ task->uid); -} + int i; + /* + * install reset values for PMC. + */ + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + ctx->ctx_pmcs[i] = PMC_DFL_VAL(i); + DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i])); + } + /* + * PMD registers are set to 0UL when the context in memset() + */ -static int -pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx) -{ - unsigned long smpl_pmds = pfx->ctx_smpl_regs[0]; - int ctx_flags; - int cpu; + /* + * On context switched restore, we must restore ALL pmc and ALL pmd even + * when they are not actively used by the task. In UP, the incoming process + * may otherwise pick up left over PMC, PMD state from the previous process. + * As opposed to PMD, stale PMC can cause harm to the incoming + * process because they may change what is being measured. + * Therefore, we must systematically reinstall the entire + * PMC state. In SMP, the same thing is possible on the + * same CPU but also on between 2 CPUs. + * + * The problem with PMD is information leaking especially + * to user level when psr.sp=0 + * + * There is unfortunately no easy way to avoid this problem + * on either UP or SMP. This definitively slows down the + * pfm_load_regs() function. + */ - /* valid signal */ + /* + * bitmask of all PMCs accessible to this context + * + * PMC0 is treated differently. + */ + ctx->ctx_all_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1; - /* cannot send to process 1, 0 means do not notify */ - if (pfx->ctx_notify_pid == 1) { - DBprintk(("invalid notify_pid %d\n", pfx->ctx_notify_pid)); - return -EINVAL; - } - ctx_flags = pfx->ctx_flags; + /* + * bitmask of all PMDs that are accesible to this context + */ + ctx->ctx_all_pmds[0] = pmu_conf.impl_pmds[0]; - if ((ctx_flags & PFM_FL_INHERIT_MASK) == (PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)) { - DBprintk(("invalid inherit mask 0x%x\n",ctx_flags & PFM_FL_INHERIT_MASK)); - return -EINVAL; - } + DPRINT(("<%d> all_pmcs=0x%lx all_pmds=0x%lx\n", ctx->ctx_fd, ctx->ctx_all_pmcs[0],ctx->ctx_all_pmds[0])); - if (ctx_flags & PFM_FL_SYSTEM_WIDE) { - DBprintk(("cpu_mask=0x%lx\n", pfx->ctx_cpu_mask)); - /* - * cannot block in this mode - */ - if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { - DBprintk(("cannot use blocking mode when in system wide monitoring\n")); - return -EINVAL; - } - /* - * must only have one bit set in the CPU mask - */ - if (hweight64(pfx->ctx_cpu_mask) != 1UL) { - DBprintk(("invalid CPU mask specified\n")); - return -EINVAL; - } - /* - * and it must be a valid CPU - */ - cpu = ffz(~pfx->ctx_cpu_mask); -#ifdef CONFIG_SMP - if (cpu_online(cpu) == 0) { -#else - if (cpu != 0) { -#endif - DBprintk(("CPU%d is not online\n", cpu)); - return -EINVAL; - } + /* + * useful in case of re-enable after disable + */ + ctx->ctx_used_ibrs[0] = 0UL; + ctx->ctx_used_dbrs[0] = 0UL; +} - /* - * check for pre-existing pinning, if conflicting reject - */ - if (task->cpus_allowed != ~0UL && (task->cpus_allowed & (1UL<pid, - task->cpus_allowed, cpu)); - return -EINVAL; - } +static int +pfm_ctx_getsize(void *arg, size_t *sz) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + pfm_buffer_fmt_t *fmt; - } else { - /* - * must provide a target for the signal in blocking mode even when - * no counter is configured with PFM_FL_REG_OVFL_NOTIFY - */ - if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == 0) { - DBprintk(("must have notify_pid when blocking for [%d]\n", task->pid)); - return -EINVAL; - } -#if 0 - if ((ctx_flags & PFM_FL_NOTIFY_BLOCK) && pfx->ctx_notify_pid == task->pid) { - DBprintk(("cannot notify self when blocking for [%d]\n", task->pid)); - return -EINVAL; - } -#endif - } - /* verify validity of smpl_regs */ - if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) { - DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds)); + *sz = 0; + + if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0; + + /* no buffer locking here, will be called again */ + fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id, 1); + if (fmt == NULL) { + DPRINT(("cannot find buffer format\n")); return -EINVAL; } - /* probably more to add here */ + /* get just enough to copy in user parameters */ + *sz = fmt->fmt_arg_size; + DPRINT(("arg_size=%lu\n", *sz)); return 0; } + + +/* + * cannot attach if : + * - kernel task + * - task not owned by caller + * - task incompatible with context mode + */ static int -pfm_context_create(struct task_struct *task, pfm_context_t *ctx, void *req, int count, - struct pt_regs *regs) +pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) { - pfarg_context_t tmp; - void *uaddr = NULL; - int ret; - int ctx_flags; - pid_t notify_pid; + /* + * no kernel task or task not owner by caller + */ + if (task->mm == NULL) { + DPRINT(("[%d] task [%d] has not memory context (kernel thread)\n", current->pid, task->pid)); + return -EPERM; + } + if (pfm_bad_permissions(task)) { + DPRINT(("[%d] no permission to attach to [%d]\n", current->pid, task->pid)); + return -EPERM; + } + /* + * cannot block in self-monitoring mode + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && task == current) { + DPRINT(("cannot load a blocking context on self for [%d]\n", task->pid)); + return -EINVAL; + } - /* a context has already been defined */ - if (ctx) return -EBUSY; + if (task->state == TASK_ZOMBIE) { + DPRINT(("[%d] cannot attach to zombie task [%d]\n", current->pid, task->pid)); + return -EBUSY; + } /* - * not yet supported + * always ok for self */ - if (task != current) return -EINVAL; + if (task == current) return 0; - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; + if (task->state != TASK_STOPPED) { + DPRINT(("[%d] cannot attach to non-stopped task [%d] state=%ld\n", current->pid, task->pid, task->state)); + return -EBUSY; + } + /* + * make sure the task is off any CPU + */ + pfm_wait_task_inactive(task); - ret = pfx_is_sane(task, &tmp); - if (ret < 0) return ret; + /* more to come... */ - ctx_flags = tmp.ctx_flags; + return 0; +} - ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask); - if (ret) goto abort; +static int +pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task) +{ + struct task_struct *p = current; + int ret; - ret = -ENOMEM; + /* XXX: need to add more checks here */ + if (pid < 2) return -EPERM; - ctx = pfm_context_alloc(); - if (!ctx) goto error; + if (pid != current->pid) { - /* record the creator (important for inheritance) */ - ctx->ctx_owner = current; + read_lock(&tasklist_lock); - notify_pid = tmp.ctx_notify_pid; + p = find_task_by_pid(pid); - spin_lock_init(&ctx->ctx_lock); + /* make sure task cannot go away while we operate on it */ + if (p) get_task_struct(p); - if (notify_pid == current->pid) { + read_unlock(&tasklist_lock); - ctx->ctx_notify_task = current; - task->thread.pfm_context = ctx; + if (p == NULL) return -ESRCH; + } - } else if (notify_pid!=0) { - struct task_struct *notify_task; + ret = pfm_task_incompatible(ctx, p); + if (ret == 0) { + *task = p; + } else if (p != current) { + pfm_put_task(p); + } + return ret; +} - read_lock(&tasklist_lock); - notify_task = find_task_by_pid(notify_pid); - if (notify_task) { +static int +pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + struct file *filp; + int ctx_flags; + int ret; - ret = -EPERM; + /* let's check the arguments first */ + ret = pfarg_is_sane(current, req); + if (ret < 0) return ret; - /* - * check if we can send this task a signal - */ - if (pfm_bad_permissions(notify_task)) { - read_unlock(&tasklist_lock); - goto buffer_error; - } + ctx_flags = req->ctx_flags; - /* - * make visible - * must be done inside critical section - * - * if the initialization does not go through it is still - * okay because child will do the scan for nothing which - * won't hurt. - */ - task->thread.pfm_context = ctx; + ret = -ENOMEM; - /* - * will cause task to check on exit for monitored - * processes that would notify it. see release_thread() - * Note: the scan MUST be done in release thread, once the - * task has been detached from the tasklist otherwise you are - * exposed to race conditions. - */ - atomic_add(1, &ctx->ctx_notify_task->thread.pfm_notifiers_check); + ctx = pfm_context_alloc(); + if (!ctx) goto error; - ctx->ctx_notify_task = notify_task; - } - read_unlock(&tasklist_lock); - } + req->ctx_fd = ctx->ctx_fd = pfm_alloc_fd(&filp); + if (req->ctx_fd < 0) goto error_file; /* - * notification process does not exist + * attach context to file */ - if (notify_pid != 0 && ctx->ctx_notify_task == NULL) { - ret = -EINVAL; - goto buffer_error; - } - - if (tmp.ctx_smpl_entries) { - DBprintk(("sampling entries=%lu\n",tmp.ctx_smpl_entries)); - - ret = pfm_smpl_buffer_alloc(ctx, tmp.ctx_smpl_regs, - tmp.ctx_smpl_entries, &uaddr); - if (ret<0) goto buffer_error; + filp->private_data = ctx; - tmp.ctx_smpl_vaddr = uaddr; + /* + * does the user want to sample? + */ + if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { + ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); + if (ret) goto buffer_error; } - /* initialization of context's flags */ - ctx->ctx_fl_inherit = ctx_flags & PFM_FL_INHERIT_MASK; - ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; - ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; - ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; - ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; - ctx->ctx_fl_frozen = 0; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; /* - * setting this flag to 0 here means, that the creator or the task that the - * context is being attached are granted access. Given that a context can only - * be created for the calling process this, in effect only allows the creator - * to access the context. See pfm_protect() for more. + * init context protection lock */ - ctx->ctx_fl_protected = 0; - - /* for system wide mode only (only 1 bit set) */ - ctx->ctx_cpu = ffz(~tmp.ctx_cpu_mask); - - atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */ + spin_lock_init(&ctx->ctx_lock); - sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */ + /* + * context is unloaded + */ + CTX_UNLOADED(ctx); - if (__copy_to_user(req, &tmp, sizeof(tmp))) { - ret = -EFAULT; - goto buffer_error; - } + /* + * initialization of context's flags + */ + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_unsecure = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0; + ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ + ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; + /* + * will move to set properties + * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + */ - DBprintk(("context=%p, pid=%d notify_task=%p\n", - (void *)ctx, task->pid, ctx->ctx_notify_task)); + /* + * init restart semaphore to locked + */ + sema_init(&ctx->ctx_restart_sem, 0); - DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d unsecure=%d\n", - (void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, - ctx->ctx_fl_block, ctx->ctx_fl_system, - ctx->ctx_fl_excl_idle, - ctx->ctx_fl_unsecure)); + /* + * activation is used in SMP only + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); /* - * when no notification is required, we can make this visible at the last moment + * initialize notification message queue */ - if (notify_pid == 0) task->thread.pfm_context = ctx; + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + init_waitqueue_head(&ctx->ctx_msgq_wait); + init_waitqueue_head(&ctx->ctx_zombieq); + + DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d unsecure=%d no_msg=%d ctx_fd=%d \n", + ctx, + ctx_flags, + ctx->ctx_fl_system, + ctx->ctx_fl_block, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_unsecure, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + /* - * pin task to CPU and force reschedule on exit to ensure - * that when back to user level the task runs on the designated - * CPU. + * initialize soft PMU state */ - if (ctx->ctx_fl_system) { - ctx->ctx_saved_cpus_allowed = task->cpus_allowed; - set_cpus_allowed(task, tmp.ctx_cpu_mask); - DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid, task->cpus_allowed)); - } + pfm_reset_pmu_state(ctx); return 0; buffer_error: + pfm_free_fd(ctx->ctx_fd, filp); + + if (ctx->ctx_buf_fmt) { + pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); + } +error_file: pfm_context_free(ctx); -error: - pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask); -abort: - /* make sure we don't leave anything behind */ - task->thread.pfm_context = NULL; +error: return ret; } @@ -1313,6 +2880,46 @@ } static void +pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i, is_long_reset = (flag == PFM_PMD_LONG_RESET); + + DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag)); + + if (flag == PFM_PMD_NO_RESET) return; + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + if (mask & 0x1) { + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } +} + +static void pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag) { unsigned long mask = ovfl_regs[0]; @@ -1320,19 +2927,27 @@ unsigned long val; int i, is_long_reset = (flag == PFM_PMD_LONG_RESET); + DPRINT_ovfl(("ovfl_regs=0x%lx flag=%d\n", ovfl_regs[0], flag)); + + if (flag == PFM_PMD_NO_RESET) return; + + if (CTX_IS_MASKED(ctx)) { + pfm_reset_regs_masked(ctx, ovfl_regs, flag); + return; + } + /* * now restore reset value on sampling overflowed counters */ mask >>= PMU_FIRST_COUNTER; for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { if (mask & 0x1) { - val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset); - reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0]; + val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; - DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid, + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); - /* upper part is ignored on rval */ pfm_write_soft_counter(ctx, i, val); } } @@ -1344,71 +2959,86 @@ if ((reset_others & 0x1) == 0) continue; - val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset); + val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); if (PMD_IS_COUNTING(i)) { pfm_write_soft_counter(ctx, i, val); } else { ia64_set_pmd(i, val); } - DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid, + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); } ia64_srlz_d(); } static int -pfm_write_pmcs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *th = &task->thread; - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; - unsigned long value, reset_pmds; + struct thread_struct *thread = NULL; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value; + unsigned long smpl_pmds, reset_pmds; unsigned int cnum, reg_flags, flags; - int i; + int i, can_access_pmu = 0, is_loaded; + int is_monitor, is_counting; int ret = -EINVAL; +#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + if (CTX_IS_DEAD(ctx)) return -EINVAL; - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + is_loaded = CTX_IS_LOADED(ctx); - /* XXX: ctx locking may be required here */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } for (i = 0; i < count; i++, req++) { - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; - reg_flags = tmp.reg_flags; - value = tmp.reg_value; - reset_pmds = tmp.reg_reset_pmds[0]; + cnum = req->reg_num; + reg_flags = req->reg_flags; + value = req->reg_value; + smpl_pmds = req->reg_smpl_pmds[0]; + reset_pmds = req->reg_reset_pmds[0]; flags = 0; - /* + is_counting = PMC_IS_COUNTING(cnum); + is_monitor = PMC_IS_MONITOR(cnum); + + /* * we reject all non implemented PMC as well * as attempts to modify PMC[0-3] which are used * as status registers by the PMU */ if (!PMC_IS_IMPL(cnum) || cnum < 4) { - DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum)); + DPRINT(("pmc%u is unimplemented or invalid\n", cnum)); goto error; } /* - * A PMC used to configure monitors must be: - * - system-wide session: privileged monitor - * - per-task : user monitor - * any other configuration is rejected. - */ - if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) { - DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); - - if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) { - DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system)); - goto error; - } + * If the PMC is a monitor, then if the value is not the default: + * - system-wide session: PMCx.pm=1 (privileged monitor) + * - per-task : PMCx.pm=0 (user monitor) + */ + if ((is_monitor || is_counting) && value != PMC_DFL_VAL(i) && PFM_CHECK_PMC_PM(ctx, cnum, value)) { + DPRINT(("pmc%u pmc_pm=%ld fl_system=%d\n", + cnum, + PMC_PM(cnum, value), + ctx->ctx_fl_system)); + goto error; } - if (PMC_IS_COUNTING(cnum)) { + + if (is_counting) { pfm_monitor_t *p = (pfm_monitor_t *)&value; /* * enforce generation of overflow interrupt. Necessary on all @@ -1417,33 +3047,35 @@ p->pmc_oi = 1; if (reg_flags & PFM_REGFL_OVFL_NOTIFY) { - /* - * must have a target for the signal - */ - if (ctx->ctx_notify_task == NULL) { - DBprintk(("cannot set ovfl_notify: no notify_task\n")); - goto error; - } flags |= PFM_REGFL_OVFL_NOTIFY; } if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM; + /* verify validity of smpl_pmds */ + if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) { + DPRINT(("invalid smpl_pmds 0x%lx for pmc%u\n", smpl_pmds, cnum)); + goto error; + } + /* verify validity of reset_pmds */ if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) { - DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); + DPRINT(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); goto error; } - } else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { - DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum)); + } else { + if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { + DPRINT(("cannot set ovfl_notify or random on pmc%u\n", cnum)); goto error; + } + /* eventid on non-counting monitors are ignored */ } /* * execute write checker, if any */ if (PMC_WR_FUNC(cnum)) { - ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs); + ret = PMC_WR_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &value, regs); if (ret) goto error; ret = -EINVAL; } @@ -1451,297 +3083,538 @@ /* * no error on this register */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); - - /* - * update register return value, abort all if problem during copy. - * we only modify the reg_flags field. no check mode is fine because - * access has been verified upfront in sys_perfmonctl(). - * - * If this fails, then the software state is not modified - */ - if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT; + PFM_REG_RETFLAG_SET(req->reg_flags, 0); /* * Now we commit the changes to the software state */ - /* - * full flag update each time a register is programmed + /* + * update overflow information */ - ctx->ctx_soft_pmds[cnum].flags = flags; + if (is_counting) { + /* + * full flag update each time a register is programmed + */ + ctx->ctx_pmds[cnum].flags = flags; - if (PMC_IS_COUNTING(cnum)) { - ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds; + ctx->ctx_pmds[cnum].reset_pmds[0] = reset_pmds; + ctx->ctx_pmds[cnum].smpl_pmds[0] = smpl_pmds; + ctx->ctx_pmds[cnum].eventid = req->reg_smpl_eventid; - /* mark all PMDS to be accessed as used */ + /* + * Mark all PMDS to be accessed as used. + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + * + * We do not update the used_monitors mask, because + * if we have not programmed them, then will be in + * a quiescent state, therefore we will not need to + * mask/restore then when context is MASKED. + */ CTX_USED_PMD(ctx, reset_pmds); + CTX_USED_PMD(ctx, smpl_pmds); + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (CTX_IS_MASKED(ctx)) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; } - /* * Needed in case the user does not initialize the equivalent - * PMD. Clearing is done in reset_pmu() so there is no possible - * leak here. + * PMD. Clearing is done indirectly via pfm_reset_pmu_state() so there is no + * possible leak here. */ CTX_USED_PMD(ctx, pmu_conf.pmc_desc[cnum].dep_pmd[0]); - /* - * keep copy the pmc, used for register reload + /* + * keep track of the monitor PMC that we are using. + * we save the value of the pmc in ctx_pmcs[] and if + * the monitoring is not stopped for the context we also + * place it in the saved state area so that it will be + * picked up later by the context switch code. + * + * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs(). + * + * The value in t->pmc[] may be modified on overflow, i.e., when + * monitoring needs to be stopped. */ - th->pmc[cnum] = value; + if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum); - ia64_set_pmc(cnum, value); + /* + * update context state + */ + ctx->ctx_pmcs[cnum] = value; - DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", - task->pid, cnum, value, - ctx->ctx_soft_pmds[cnum].flags, - ctx->ctx_used_pmds[0])); + if (is_loaded) { + /* + * write thread state + */ + if (ctx->ctx_fl_system == 0) thread->pmcs[cnum] = value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmc(cnum, value); + } +#ifdef CONFIG_SMP + else { + /* + * per-task SMP only here + * + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmcs[0] |= 1UL << cnum; + } +#endif + } + DPRINT(("pmc[%u]=0x%lx loaded=%d access_pmu=%d all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + ctx->ctx_all_pmcs[0], + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].eventid, + smpl_pmds, + reset_pmds, + ctx->ctx_reload_pmcs[0], + ctx->ctx_used_monitors[0], + ctx->ctx_ovfl_regs[0])); } - return 0; + /* + * make sure the changes are visible + */ + if (can_access_pmu) ia64_srlz_d(); + return 0; error: - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); - if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT; + req->reg_flags = PFM_REG_RETFL_EINVAL; - DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret)); + DPRINT(("pmc[%u]=0x%lx error %d\n", cnum, value, ret)); return ret; } static int -pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; + struct thread_struct *thread = NULL; + pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned long value, hw_value; unsigned int cnum; - int i; + int i, can_access_pmu = 0; + int is_counting, is_loaded; int ret = -EINVAL; - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - preempt_disable(); + if (CTX_IS_DEAD(ctx)) return -EINVAL; - /* XXX: ctx locking may be required here */ + is_loaded = CTX_IS_LOADED(ctx); + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task ? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } for (i = 0; i < count; i++, req++) { - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; - value = tmp.reg_value; + cnum = req->reg_num; + value = req->reg_value; if (!PMD_IS_IMPL(cnum)) { - DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum)); + DPRINT(("pmd[%u] is unimplemented or invalid\n", cnum)); goto abort_mission; } + is_counting = PMD_IS_COUNTING(cnum); /* * execute write checker, if any */ if (PMD_WR_FUNC(cnum)) { unsigned long v = value; - ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs); + + ret = PMD_WR_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &v, regs); if (ret) goto abort_mission; + value = v; - ret = -EINVAL; + ret = -EINVAL; } - hw_value = value; + /* * no error on this register */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); - - if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT; + PFM_REG_RETFLAG_SET(req->reg_flags, 0); /* * now commit changes to software state */ + hw_value = value; - /* update virtualized (64bits) counter */ - if (PMD_IS_COUNTING(cnum)) { - ctx->ctx_soft_pmds[cnum].lval = value; - ctx->ctx_soft_pmds[cnum].val = value & ~pmu_conf.ovfl_val; + /* + * update virtualized (64bits) counter + */ + if (is_counting) { + /* + * write context state + */ + ctx->ctx_pmds[cnum].lval = value; - hw_value = value & pmu_conf.ovfl_val; + /* + * when context is load we use the split value + */ + if (is_loaded) { + hw_value = value & pmu_conf.ovfl_val; + value = value & ~pmu_conf.ovfl_val; + } - ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset; - ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset; + /* + * update sampling periods + */ + ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset; + ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset; - ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed; - ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask; + /* + * update randomization parameters + */ + ctx->ctx_pmds[cnum].seed = req->reg_random_seed; + ctx->ctx_pmds[cnum].mask = req->reg_random_mask; } - /* keep track of what we use */ - CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]); + /* + * update context value + */ + ctx->ctx_pmds[cnum].val = value; + + /* + * Keep track of what we use + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + */ + CTX_USED_PMD(ctx, PMD_PMD_DEP(cnum)); - /* mark this register as used as well */ + /* + * mark this PMD register used as well + */ CTX_USED_PMD(ctx, RDEP(cnum)); - /* writes to unimplemented part is ignored, so this is safe */ - ia64_set_pmd(cnum, hw_value); + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (is_counting && CTX_IS_MASKED(ctx)) { + ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } - /* to go away */ - ia64_srlz_d(); + if (is_loaded) { + /* + * write thread state + */ + if (ctx->ctx_fl_system == 0) thread->pmds[cnum] = hw_value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmd(cnum, hw_value); + } else { +#ifdef CONFIG_SMP + /* + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmds[0] |= 1UL << cnum; +#endif + } + } - DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx short_reset=0x%lx " - "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n", - task->pid, cnum, - value, hw_value, - ctx->ctx_soft_pmds[cnum].val, - ctx->ctx_soft_pmds[cnum].short_reset, - ctx->ctx_soft_pmds[cnum].long_reset, - ia64_get_pmd(cnum) & pmu_conf.ovfl_val, - PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', - ctx->ctx_used_pmds[0], - ctx->ctx_soft_pmds[cnum].reset_pmds[0])); + DPRINT(("pmd[%u]=0x%lx loaded=%d access_pmu=%d, hw_value=0x%lx ctx_pmd=0x%lx short_reset=0x%lx " + "long_reset=0x%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + hw_value, + ctx->ctx_pmds[cnum].val, + ctx->ctx_pmds[cnum].short_reset, + ctx->ctx_pmds[cnum].long_reset, + PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].reset_pmds[0], + ctx->ctx_reload_pmds[0], + ctx->ctx_all_pmds[0], + ctx->ctx_ovfl_regs[0])); } - preempt_enable(); + + /* + * make changes visible + */ + if (can_access_pmu) ia64_srlz_d(); + return 0; abort_mission: - preempt_enable(); - /* * for now, we have only one possibility for error */ - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); /* * we change the return value to EFAULT in case we cannot write register return code. * The caller first must correct this error, then a resubmission of the request will * eventually yield the EINVAL. */ - if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT; + req->reg_flags = PFM_REG_RETFL_EINVAL; - DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret)); + DPRINT(("pmd[%u]=0x%lx ret %d\n", cnum, value, ret)); return ret; } +/* + * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function. + * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an + * interrupt is delivered during the call, it will be kept pending until we leave, making + * it appears as if it had been generated at the UNPROTECT_CONTEXT(). At least we are + * guaranteed to return consistent data to the user, it may simply be old. It is not + * trivial to treat the overflow while inside the call because you may end up in + * some module sampling buffer code causing deadlocks. + */ static int -pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *th = &task->thread; - unsigned long val, lval; + struct thread_struct *thread = NULL; + unsigned long val = 0UL, lval ; pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned int cnum, reg_flags = 0; - int i, ret = 0; - -#if __GNUC__ < 3 - int foo; -#endif + int i, is_loaded, can_access_pmu = 0; + int ret = -EINVAL; - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + if (CTX_IS_ZOMBIE(ctx)) return -EINVAL; /* - * XXX: MUST MAKE SURE WE DON"T HAVE ANY PENDING OVERFLOW BEFORE READING - * This is required when the monitoring has been stoppped by user or kernel. - * If it is still going on, then that's fine because we a re not guaranteed - * to return an accurate value in this case. + * access is possible when loaded only for + * self-monitoring tasks or in UP mode */ + is_loaded = CTX_IS_LOADED(ctx); - /* XXX: ctx locking may be required here */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + /* + * this can be true when not self-monitoring only in UP + */ + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task? 1 : 0; - DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid)); + if (can_access_pmu) ia64_srlz_d(); + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } + DPRINT(("enter loaded=%d access_pmu=%d ctx_state=%d\n", + is_loaded, + can_access_pmu, + ctx->ctx_state)); + + /* + * on both UP and SMP, we can only read the PMD from the hardware register when + * the task is the owner of the local PMU. + */ for (i = 0; i < count; i++, req++) { - int me; -#if __GNUC__ < 3 - foo = __get_user(cnum, &req->reg_num); - if (foo) return -EFAULT; - foo = __get_user(reg_flags, &req->reg_flags); - if (foo) return -EFAULT; -#else - if (__get_user(cnum, &req->reg_num)) return -EFAULT; - if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT; -#endif - lval = 0UL; - if (!PMD_IS_IMPL(cnum)) goto abort_mission; + lval = 0UL; + cnum = req->reg_num; + reg_flags = req->reg_flags; + + if (!PMD_IS_IMPL(cnum)) goto error; /* * we can only read the register that we use. That includes - * the one we explicitly initialize AND the one we want included + * the one we explicitely initialize AND the one we want included * in the sampling buffer (smpl_regs). * * Having this restriction allows optimization in the ctxsw routine * without compromising security (leaks) */ - if (!CTX_IS_USED_PMD(ctx, cnum)) goto abort_mission; + if (!CTX_IS_USED_PMD(ctx, cnum)) goto error; /* * If the task is not the current one, then we check if the * PMU state is still in the local live register due to lazy ctxsw. * If true, then we read directly from the registers. */ - me = get_cpu(); - if (atomic_read(&ctx->ctx_last_cpu) == me){ - ia64_srlz_d(); + if (can_access_pmu){ val = ia64_get_pmd(cnum); - DBprintk(("reading pmd[%u]=0x%lx from hw\n", cnum, val)); } else { - val = th->pmd[cnum]; + /* + * context has been saved + * if context is zombie, then task does not exist anymore. + * In this case, we use the full value saved in the context (pfm_flush_regs()). + */ + val = CTX_IS_LOADED(ctx) ? thread->pmds[cnum] : 0UL; } - if (PMD_IS_COUNTING(cnum)) { /* - * XXX: need to check for overflow + * XXX: need to check for overflow when loaded */ val &= pmu_conf.ovfl_val; - val += ctx->ctx_soft_pmds[cnum].val; + val += ctx->ctx_pmds[cnum].val; - lval = ctx->ctx_soft_pmds[cnum].lval; - } + lval = ctx->ctx_pmds[cnum].lval; + } /* * execute read checker, if any */ if (PMD_RD_FUNC(cnum)) { unsigned long v = val; - ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs); + ret = PMD_RD_FUNC(cnum)(ctx->ctx_task, ctx, cnum, &v, regs); + if (ret) goto error; val = v; + ret = -EINVAL; } - PFM_REG_RETFLAG_SET(reg_flags, ret); - - put_cpu(); + PFM_REG_RETFLAG_SET(reg_flags, 0); - DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", - cnum, ret, val, ia64_get_pmc(cnum))); + DPRINT(("pmd[%u]=0x%lx loaded=%d access_pmu=%d ctx_state=%d\n", + cnum, + val, + is_loaded, + can_access_pmu, + ctx->ctx_state)); /* * update register return value, abort all if problem during copy. * we only modify the reg_flags field. no check mode is fine because * access has been verified upfront in sys_perfmonctl(). */ - if (__put_user(cnum, &req->reg_num)) return -EFAULT; - if (__put_user(val, &req->reg_value)) return -EFAULT; - if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT; - if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT; + req->reg_value = val; + req->reg_flags = reg_flags; + req->reg_last_reset_val = lval; } return 0; -abort_mission: +error: PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL); - /* - * XXX: if this fails, we stick with the original failure, flag not updated! + + req->reg_flags = PFM_REG_RETFL_EINVAL; + + DPRINT(("error pmd[%u]=0x%lx\n", cnum, val)); + + return ret; +} + +long +pfm_mod_write_pmcs(struct task_struct *task, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (task == NULL || req == NULL) return -EINVAL; + + ctx = task->thread.pfm_context; + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler */ - __put_user(reg_flags, &req->reg_flags); + if (task != current) return -EBUSY; - return -EINVAL; + return pfm_write_pmcs(ctx, req, nreq, regs); +} + +long +pfm_mod_read_pmds(struct task_struct *task, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (task == NULL || req == NULL) return -EINVAL; + + //ctx = task->thread.pfm_context; + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_read_pmds(ctx, req, nreq, regs); +} + +long +pfm_mod_fast_read_pmds(struct task_struct *task, unsigned long mask[4], unsigned long *addr, struct pt_regs *regs) +{ + pfm_context_t *ctx; + unsigned long m, val; + unsigned int j; + + if (task == NULL || addr == NULL) return -EINVAL; + + //ctx = task->thread.pfm_context; + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + m = mask[0]; + for (j=0; m; m >>=1, j++) { + + if ((m & 0x1) == 0) continue; + + if (!(PMD_IS_IMPL(j) && CTX_IS_USED_PMD(ctx, j)) ) return -EINVAL; + + if (PMD_IS_COUNTING(j)) { + val = pfm_read_soft_counter(ctx, j); + } else { + val = ia64_get_pmd(j); + } + + *addr++ = val; + + /* XXX: should call read checker routine? */ + DPRINT(("single_read_pmd[%u]=0x%lx\n", j, val)); + } + return 0; } -#ifdef PFM_PMU_USES_DBR /* * Only call this function when a process it trying to * write the debug registers (reading is always allowed) @@ -1752,7 +3625,9 @@ pfm_context_t *ctx = task->thread.pfm_context; int ret = 0; - DBprintk(("called for [%d]\n", task->pid)); + if (pmu_conf.use_rr_dbregs == 0) return 0; + + DPRINT(("called for [%d]\n", task->pid)); /* * do it only once @@ -1780,9 +3655,9 @@ else pfm_sessions.pfs_ptrace_use_dbregs++; - DBprintk(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", - pfm_sessions.pfs_ptrace_use_dbregs, - pfm_sessions.pfs_sys_use_dbregs, + DPRINT(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", + pfm_sessions.pfs_ptrace_use_dbregs, + pfm_sessions.pfs_sys_use_dbregs, task->pid, ret)); UNLOCK_PFS(); @@ -1803,10 +3678,11 @@ { int ret; + if (pmu_conf.use_rr_dbregs == 0) return 0; + LOCK_PFS(); if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { - printk(KERN_DEBUG "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", - task->pid); + printk(KERN_ERR "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task->pid); ret = -1; } else { pfm_sessions.pfs_ptrace_use_dbregs--; @@ -1816,388 +3692,275 @@ return ret; } -#else /* PFM_PMU_USES_DBR is true */ -/* - * in case, the PMU does not use the debug registers, these two functions are nops. - * The first function is called from arch/ia64/kernel/ptrace.c. - * The second function is called from arch/ia64/kernel/process.c. - */ -int -pfm_use_debug_registers(struct task_struct *task) -{ - return 0; -} - -int -pfm_release_debug_registers(struct task_struct *task) -{ - return 0; -} -#endif /* PFM_PMU_USES_DBR */ static int -pfm_restart(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) +pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - void *sem = &ctx->ctx_restart_sem; - - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - if (task == current) { - DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", - task->pid, - ctx->ctx_fl_frozen, - ctx->ctx_ovfl_regs[0])); - - preempt_disable(); - pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); - - ctx->ctx_ovfl_regs[0] = 0UL; - - /* - * We ignore block/don't block because we never block - * for a self-monitoring process. - */ - ctx->ctx_fl_frozen = 0; - - if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; - } - - /* simply unfreeze */ - pfm_unfreeze_pmu(); + struct task_struct *task; + pfm_buffer_fmt_t *fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int is_loaded; + int ret = 0; - preempt_enable(); + fmt = ctx->ctx_buf_fmt; + is_loaded = CTX_IS_LOADED(ctx); - return 0; - } - /* restart on another task */ + if (is_loaded && CTX_HAS_SMPL(ctx) && fmt->fmt_restart_active) goto proceed; /* - * if blocking, then post the semaphore. - * if non-blocking, then we ensure that the task will go into - * pfm_overflow_must_block() before returning to user mode. - * We cannot explicitly reset another task, it MUST always - * be done by the task itself. This works for system wide because - * the tool that is controlling the session is doing "self-monitoring". - * - * XXX: what if the task never goes back to user? - * + * restarting a terminated context is a nop */ - if (CTX_OVFL_NOBLOCK(ctx) == 0) { - DBprintk(("unblocking %d \n", task->pid)); - up(sem); - } else { - struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); - task->thread.pfm_ovfl_block_reset = 1; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; - set_bit(TIF_NOTIFY_RESUME, &info->flags); + if (unlikely(CTX_IS_TERMINATED(ctx))) { + DPRINT(("context is terminated, nothing to do\n")); + return 0; } -#if 0 + + /* - * in case of non blocking mode, then it's just a matter of - * of reseting the sampling buffer (if any) index. The PMU - * is already active. + * LOADED, UNLOADED, ZOMBIE */ + if (CTX_IS_MASKED(ctx) == 0) return -EBUSY; +proceed: /* - * must reset the header count first - */ - if (CTX_HAS_SMPL(ctx)) { - DBprintk(("resetting sampling indexes for %d \n", task->pid)); - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; } -#endif - return 0; -} -static int -pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + task = PFM_CTX_TASK(ctx); - /* - * Cannot do anything before PMU is enabled + /* sanity check */ + if (unlikely(task == NULL)) { + printk(KERN_ERR "perfmon: [%d] pfm_restart no task\n", current->pid); + return -EINVAL; + } + + /* + * this test is always true in system wide mode */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + if (task == current) { - DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", - current->pid, - ctx->ctx_fl_system, PMU_OWNER(), - current)); + fmt = ctx->ctx_buf_fmt; - preempt_disable(); - /* simply stop monitoring but not the PMU */ - if (ctx->ctx_fl_system) { + DPRINT(("restarting self %d ovfl=0x%lx\n", + task->pid, + ctx->ctx_ovfl_regs[0])); - /* disable dcr pp */ - ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + if (CTX_HAS_SMPL(ctx)) { - /* stop monitoring */ - pfm_clear_psr_pp(); + prefetch(ctx->ctx_smpl_hdr); - ia64_srlz_i(); + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_NO_RESET; - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + if (is_loaded) + ret = pfm_buf_fmt_restart_active(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); - ia64_psr(regs)->pp = 0; - } else { + } else { + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_LONG_RESET; + } - /* stop monitoring */ - pfm_clear_psr_up(); + if (ret == 0) { + if (rst_ctrl.reset_pmds) + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, rst_ctrl.reset_pmds); - ia64_srlz_i(); + if (rst_ctrl.stop_monitoring == 0) { + DPRINT(("resuming monitoring for [%d]\n", task->pid)); + if (CTX_IS_MASKED(ctx)) pfm_restore_monitoring(task); + } else { + DPRINT(("keeping monitoring stopped for [%d]\n", task->pid)); + + // cannot use pfm_stop_monitoring(task, regs); + } + } /* - * clear user level psr.up + * clear overflowed PMD mask to remove any stale information */ - ia64_psr(regs)->up = 0; - } - preempt_enable(); - return 0; -} + ctx->ctx_ovfl_regs[0] = 0UL; -static int -pfm_disable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + /* + * back to LOADED state + */ + CTX_LOADED(ctx); - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; + return 0; + } + /* restart another task */ - preempt_disable(); /* - * stop monitoring, freeze PMU, and save state in context - * this call will clear IA64_THREAD_PM_VALID for per-task sessions. + * if blocking, then post the semaphore. + * if non-blocking, then we ensure that the task will go into + * pfm_handle_work() before returning to user mode. + * We cannot explicitely reset another task, it MUST always + * be done by the task itself. This works for system wide because + * the tool that is controlling the session is doing "self-monitoring". + * + * XXX: what if the task never goes back to user? + * */ - pfm_flush_regs(task); - - if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; + if (CTX_OVFL_NOBLOCK(ctx) == 0) { + DPRINT(("unblocking [%d] \n", task->pid)); + up(&ctx->ctx_restart_sem); } else { - ia64_psr(regs)->up = 0; - } - /* - * goes back to default behavior: no user level control - * no need to change live psr.sp because useless at the kernel level - */ - ia64_psr(regs)->sp = 1; + DPRINT(("[%d] armed exit trap\n", task->pid)); - DBprintk(("enabling psr.sp for [%d]\n", current->pid)); - - ctx->ctx_flags.state = PFM_CTX_DISABLED; - preempt_enable(); - - return 0; -} - -static int -pfm_context_destroy(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; - /* - * if context was never enabled, then there is not much - * to do - */ - if (!CTX_IS_ENABLED(ctx)) goto skipped_stop; - /* - * Disable context: stop monitoring, flush regs to software state (useless here), - * and freeze PMU - * - * The IA64_THREAD_PM_VALID is cleared by pfm_flush_regs() called from pfm_disable() - */ - pfm_disable(task, ctx, arg, count, regs); + PFM_SET_WORK_PENDING(task, 1); - if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; - } else { - ia64_psr(regs)->up = 0; - } + pfm_set_task_notify(task); -skipped_stop: - /* - * remove sampling buffer mapping, if any - */ - if (ctx->ctx_smpl_vaddr) { - pfm_remove_smpl_mapping(task); - ctx->ctx_smpl_vaddr = 0UL; + /* + * XXX: send reschedule if task runs on another CPU + */ } - /* now free context and related state */ - pfm_context_exit(task); - return 0; } -/* - * does nothing at the moment - */ static int -pfm_context_unprotect(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) +pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - return 0; -} + unsigned int m = *(unsigned int *)arg; -static int -pfm_protect_context(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - DBprintk(("context from [%d] is protected\n", task->pid)); - /* - * from now on, only the creator of the context has access to it - */ - ctx->ctx_fl_protected = 1; - - /* - * reinforce secure monitoring: cannot toggle psr.up - */ - if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1; + pfm_sysctl.debug = m == 0 ? 0 : 1; - return 0; -} + pfm_debug_var = pfm_sysctl.debug; -static int -pfm_debug(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - unsigned int mode = *(unsigned int *)arg; + printk(KERN_ERR "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); - pfm_sysctl.debug = mode == 0 ? 0 : 1; - printk(KERN_INFO "perfmon debugging %s\n", pfm_sysctl.debug ? "on" : "off"); + if (m==0) { + memset(pfm_stats, 0, sizeof(pfm_stats)); + for(m=0; m < NR_CPUS; m++) pfm_stats[m].pfm_ovfl_intr_cycles_min = ~0UL; + } return 0; } -#ifdef PFM_PMU_USES_DBR - -typedef struct { - unsigned long ibr_mask:56; - unsigned long ibr_plm:4; - unsigned long ibr_ig:3; - unsigned long ibr_x:1; -} ibr_mask_reg_t; - -typedef struct { - unsigned long dbr_mask:56; - unsigned long dbr_plm:4; - unsigned long dbr_ig:2; - unsigned long dbr_w:1; - unsigned long dbr_r:1; -} dbr_mask_reg_t; - -typedef union { - unsigned long val; - ibr_mask_reg_t ibr; - dbr_mask_reg_t dbr; -} dbreg_t; static int -pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs) +pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct thread_struct *thread = &task->thread; - pfm_context_t *ctx = task->thread.pfm_context; - pfarg_dbreg_t tmp, *req = (pfarg_dbreg_t *)arg; + struct thread_struct *thread = NULL; + pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; dbreg_t dbreg; unsigned int rnum; int first_time; - int i, ret = 0; + int ret = 0; + int i, can_access_pmu = 0, is_loaded; + + if (pmu_conf.use_rr_dbregs == 0) return -EINVAL; + + if (CTX_IS_DEAD(ctx)) return -EINVAL; + + is_loaded = CTX_IS_LOADED(ctx); + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &ctx->ctx_task->thread; + can_access_pmu = GET_PMU_OWNER() == ctx->ctx_task ? 1 : 0; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + } /* * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w * ensuring that no real breakpoint can be installed via this call. + * + * IMPORTANT: regs can be NULL in this function */ first_time = ctx->ctx_fl_using_dbreg == 0; /* + * don't bother if we are loaded and task is being debugged + */ + if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { + DPRINT(("debug registers already in use for [%d]\n", ctx->ctx_task->pid)); + return -EBUSY; + } + + /* * check for debug registers in system wide mode * + * We make the reservation even when context is not loaded + * to make sure we get our slot. Note that the PFM_LOAD_CONTEXT + * may still fail if the task has DBG_VALID set. */ LOCK_PFS(); - if (ctx->ctx_fl_system && first_time) { - if (pfm_sessions.pfs_ptrace_use_dbregs) + + if (first_time && ctx->ctx_fl_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) ret = -EBUSY; else pfm_sessions.pfs_sys_use_dbregs++; } + UNLOCK_PFS(); if (ret != 0) return ret; - if (ctx->ctx_fl_system) { - /* we mark ourselves as owner of the debug registers */ - ctx->ctx_fl_using_dbreg = 1; - DBprintk(("system-wide setting fl_using_dbreg for [%d]\n", task->pid)); - } else if (first_time) { - ret= -EBUSY; - if ((thread->flags & IA64_THREAD_DBG_VALID) != 0) { - DBprintk(("debug registers already in use for [%d]\n", task->pid)); - goto abort_mission; - } - /* we mark ourselves as owner of the debug registers */ - ctx->ctx_fl_using_dbreg = 1; - - DBprintk(("setting fl_using_dbreg for [%d]\n", task->pid)); - /* - * Given debug registers cannot be used for both debugging - * and performance monitoring at the same time, we reuse - * the storage area to save and restore the registers on ctxsw. - */ - memset(task->thread.dbr, 0, sizeof(task->thread.dbr)); - memset(task->thread.ibr, 0, sizeof(task->thread.ibr)); - } + /* + * mark ourself as user of the debug registers for + * perfmon purposes. + */ + ctx->ctx_fl_using_dbreg = 1; - if (first_time) { - DBprintk(("[%d] clearing ibrs,dbrs\n", task->pid)); - /* - * clear hardware registers to make sure we don't - * pick up stale state. - * - * for a system wide session, we do not use - * thread.dbr, thread.ibr because this process - * never leaves the current CPU and the state - * is shared by all processes running on it - */ - for (i=0; i < (int) pmu_conf.num_ibrs; i++) { + /* + * clear hardware registers to make sure we don't + * pick up stale state. + * + * for a system wide session, we do not use + * thread.dbr, thread.ibr because this process + * never leaves the current CPU and the state + * is shared by all processes running on it + */ + if (first_time && can_access_pmu) { + DPRINT(("[%d] clearing ibrs, dbrs\n", ctx->ctx_task->pid)); + for (i=0; i < pmu_conf.num_ibrs; i++) { ia64_set_ibr(i, 0UL); + ia64_srlz_i(); } ia64_srlz_i(); - for (i=0; i < (int) pmu_conf.num_dbrs; i++) { + for (i=0; i < pmu_conf.num_dbrs; i++) { ia64_set_dbr(i, 0UL); + ia64_srlz_d(); } ia64_srlz_d(); } - ret = -EFAULT; - /* * Now install the values into the registers */ for (i = 0; i < count; i++, req++) { - - if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission; - - rnum = tmp.dbreg_num; - dbreg.val = tmp.dbreg_value; - + + rnum = req->dbreg_num; + dbreg.val = req->dbreg_value; + ret = -EINVAL; - if ((mode == 0 && !IBR_IS_IMPL(rnum)) || ((mode == 1) && !DBR_IS_IMPL(rnum))) { - DBprintk(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", + if ((mode == PFM_CODE_RR && !IBR_IS_IMPL(rnum)) || ((mode == PFM_DATA_RR) && !DBR_IS_IMPL(rnum))) { + DPRINT(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", rnum, dbreg.val, mode, i, count)); goto abort_mission; @@ -2207,22 +3970,13 @@ * make sure we do not install enabled breakpoint */ if (rnum & 0x1) { - if (mode == 0) + if (mode == PFM_CODE_RR) dbreg.ibr.ibr_x = 0; else dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; } - /* - * clear return flags and copy back to user - * - * XXX: fix once EAGAIN is implemented - */ - ret = -EFAULT; - - PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0); - - if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission; + PFM_REG_RETFLAG_SET(req->dbreg_flags, 0); /* * Debug registers, just like PMC, can only be modified @@ -2234,24 +3988,24 @@ * by the fact that when perfmon uses debug registers, ptrace() * won't be able to modify them concurrently. */ - if (mode == 0) { + if (mode == PFM_CODE_RR) { CTX_USED_IBR(ctx, rnum); - ia64_set_ibr(rnum, dbreg.val); - ia64_srlz_i(); + if (can_access_pmu) ia64_set_ibr(rnum, dbreg.val); - thread->ibr[rnum] = dbreg.val; + ctx->ctx_ibrs[rnum] = dbreg.val; - DBprintk(("write ibr%u=0x%lx used_ibrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_ibrs[0])); + DPRINT(("write ibr%u=0x%lx used_ibrs=0x%x is_loaded=%d access_pmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_ibrs[0], is_loaded, can_access_pmu)); } else { CTX_USED_DBR(ctx, rnum); - ia64_set_dbr(rnum, dbreg.val); - ia64_srlz_d(); + if (can_access_pmu) ia64_set_dbr(rnum, dbreg.val); - thread->dbr[rnum] = dbreg.val; + ctx->ctx_dbrs[rnum] = dbreg.val; - DBprintk(("write dbr%u=0x%lx used_dbrs=0x%lx\n", rnum, dbreg.val, ctx->ctx_used_dbrs[0])); + DPRINT(("write dbr%u=0x%lx used_dbrs=0x%x is_loaded=%d access_pmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_dbrs[0], is_loaded, can_access_pmu)); } } @@ -2272,720 +4026,1177 @@ /* * install error return flag */ - if (ret != -EFAULT) { - /* - * XXX: for now we can only come here on EINVAL - */ - PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL); - if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT; - } + PFM_REG_RETFLAG_SET(req->dbreg_flags, PFM_REG_RETFL_EINVAL); + return ret; } static int -pfm_write_ibrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - return pfm_write_ibr_dbr(0, task, arg, count, regs); +pfm_write_ibrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_CODE_RR, ctx, arg, count, regs); } static int -pfm_write_dbrs(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) -{ - /* we don't quite support this right now */ - if (task != current) return -EINVAL; - - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - - return pfm_write_ibr_dbr(1, task, arg, count, regs); +pfm_write_dbrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_DATA_RR, ctx, arg, count, regs); } -#endif /* PFM_PMU_USES_DBR */ - static int -pfm_get_features(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - pfarg_features_t tmp; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.ft_version = PFM_VERSION; - tmp.ft_smpl_version = PFM_SMPL_VERSION; - - if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT; + pfarg_features_t *req = (pfarg_features_t *)arg; + req->ft_version = PFM_VERSION; return 0; } static int -pfm_start(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) +pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + struct pt_regs *tregs; - /* - * Cannot do anything before PMU is enabled - */ - if (!CTX_IS_ENABLED(ctx)) return -EINVAL; - DBprintk(("[%d] fl_system=%d owner=%p current=%p\n", - current->pid, - ctx->ctx_fl_system, PMU_OWNER(), - current)); + if (CTX_IS_LOADED(ctx) == 0 && CTX_IS_MASKED(ctx) == 0) return -EINVAL; - if (PMU_OWNER() != task) { - printk(KERN_DEBUG "perfmon: pfm_start task [%d] not pmu owner\n", task->pid); - return -EINVAL; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; } - preempt_disable(); + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ if (ctx->ctx_fl_system) { - - PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); + /* + * Update local PMU first + * + * disable dcr pp + */ + ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + ia64_srlz_i(); - /* set user level psr.pp */ - ia64_psr(regs)->pp = 1; + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - /* start monitoring at kernel level */ - pfm_set_psr_pp(); + /* + * stop monitoring, does srlz.i + */ + pfm_clear_psr_pp(); - /* enable dcr pp */ - ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); + /* + * stop monitoring in the caller + */ + ia64_psr(regs)->pp = 0; - ia64_srlz_i(); + return 0; + } + /* + * per-task mode + */ + if (ctx->ctx_task == current) { + /* stop monitoring at kernel level */ + pfm_clear_psr_up(); + + /* + * stop monitoring at the user level + */ + ia64_psr(regs)->up = 0; } else { - if ((task->thread.flags & IA64_THREAD_PM_VALID) == 0) { - preempt_enable(); - printk(KERN_DEBUG "perfmon: pfm_start task flag not set for [%d]\n", - task->pid); - return -EINVAL; - } - /* set user level psr.up */ - ia64_psr(regs)->up = 1; + tregs = ia64_task_regs(ctx->ctx_task); - /* start monitoring at kernel level */ - pfm_set_psr_up(); + /* + * stop monitoring at the user level + */ + ia64_psr(tregs)->up = 0; - ia64_srlz_i(); + /* + * monitoring disabled in kernel at next reschedule + */ + ctx->ctx_saved_psr &= ~IA64_PSR_UP; + printk("pfm_stop: current [%d] task=[%d]\n", current->pid, ctx->ctx_task->pid); } - - preempt_enable(); return 0; } + static int -pfm_enable(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) +pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - int me; + struct pt_regs *tregs; - /* we don't quite support this right now */ - if (task != current) return -EINVAL; + if (CTX_IS_LOADED(ctx) == 0) return -EINVAL; - me = get_cpu(); /* make sure we're not migrated or preempted */ - - if (ctx->ctx_fl_system == 0 && PMU_OWNER() && PMU_OWNER() != current) - pfm_lazy_save_regs(PMU_OWNER()); - - /* reset all registers to stable quiet state */ - pfm_reset_pmu(task); + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } - /* make sure nothing starts */ + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ if (ctx->ctx_fl_system) { - ia64_psr(regs)->pp = 0; - ia64_psr(regs)->up = 0; /* just to make sure! */ - /* make sure monitoring is stopped */ - pfm_clear_psr_pp(); - ia64_srlz_i(); + /* + * set user level psr.pp for the caller + */ + ia64_psr(regs)->pp = 1; - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); - if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); - } else { /* - * needed in case the task was a passive task during - * a system wide session and now wants to have its own - * session + * now update the local PMU and cpuinfo */ - ia64_psr(regs)->pp = 0; /* just to make sure! */ - ia64_psr(regs)->up = 0; + PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); - /* make sure monitoring is stopped */ - pfm_clear_psr_up(); + /* + * start monitoring at kernel level + */ + pfm_set_psr_pp(); + + /* enable dcr pp */ + ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP); ia64_srlz_i(); - DBprintk(("clearing psr.sp for [%d]\n", current->pid)); + return 0; + } + + /* + * per-process mode + */ - /* allow user level control */ - ia64_psr(regs)->sp = 0; + if (ctx->ctx_task == current) { - /* PMU state will be saved/restored on ctxsw */ - task->thread.flags |= IA64_THREAD_PM_VALID; - } + /* start monitoring at kernel level */ + pfm_set_psr_up(); - SET_PMU_OWNER(task); + /* + * activate monitoring at user level + */ + ia64_psr(regs)->up = 1; - ctx->ctx_flags.state = PFM_CTX_ENABLED; - atomic_set(&ctx->ctx_last_cpu, me); + } else { + tregs = ia64_task_regs(ctx->ctx_task); - /* simply unfreeze */ - pfm_unfreeze_pmu(); + /* + * start monitoring at the kernel level the next + * time the task is scheduled + */ + ctx->ctx_saved_psr |= IA64_PSR_UP; - put_cpu(); + /* + * activate monitoring at user level + */ + ia64_psr(tregs)->up = 1; + } return 0; } static int -pfm_get_pmc_reset(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, - struct pt_regs *regs) +pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg; + pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned int cnum; - int i, ret = -EINVAL; + int i; + int ret = -EINVAL; for (i = 0; i < count; i++, req++) { - if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; - - cnum = tmp.reg_num; + cnum = req->reg_num; if (!PMC_IS_IMPL(cnum)) goto abort_mission; - tmp.reg_value = PMC_DFL_VAL(cnum); - - PFM_REG_RETFLAG_SET(tmp.reg_flags, 0); + req->reg_value = PMC_DFL_VAL(cnum); - DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); + PFM_REG_RETFLAG_SET(req->reg_flags, 0); - if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT; + DPRINT(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, req->reg_value)); } return 0; -abort_mission: - PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL); - if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT; +abort_mission: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); return ret; } -/* - * functions MUST be listed in the increasing order of their index (see permfon.h) - */ -static pfm_cmd_desc_t pfm_cmd_tab[]={ -/* 0 */{ NULL, 0, 0, 0}, /* not used */ -/* 1 */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 2 */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 3 */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 4 */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 5 */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 6 */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 7 */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 8 */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)}, -/* 9 */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0}, -/* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0}, -/* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)}, -/* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0}, -/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, -/* 16 */{ NULL, 0, 0, 0}, /* not used */ -/* 17 */{ NULL, 0, 0, 0}, /* not used */ -/* 18 */{ NULL, 0, 0, 0}, /* not used */ -/* 19 */{ NULL, 0, 0, 0}, /* not used */ -/* 20 */{ NULL, 0, 0, 0}, /* not used */ -/* 21 */{ NULL, 0, 0, 0}, /* not used */ -/* 22 */{ NULL, 0, 0, 0}, /* not used */ -/* 23 */{ NULL, 0, 0, 0}, /* not used */ -/* 24 */{ NULL, 0, 0, 0}, /* not used */ -/* 25 */{ NULL, 0, 0, 0}, /* not used */ -/* 26 */{ NULL, 0, 0, 0}, /* not used */ -/* 27 */{ NULL, 0, 0, 0}, /* not used */ -/* 28 */{ NULL, 0, 0, 0}, /* not used */ -/* 29 */{ NULL, 0, 0, 0}, /* not used */ -/* 30 */{ NULL, 0, 0, 0}, /* not used */ -/* 31 */{ NULL, 0, 0, 0}, /* not used */ -#ifdef PFM_PMU_USES_DBR -/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}, -/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)} -#endif -}; -#define PFM_CMD_COUNT ARRAY_SIZE(pfm_cmd_tab) - static int -check_task_state(struct task_struct *task) +pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { + struct task_struct *task; + struct thread_struct *thread; + struct pfm_context_t *old; +#ifndef CONFIG_SMP + struct task_struct *owner_task = NULL; +#endif + pfarg_load_t *req = (pfarg_load_t *)arg; + unsigned long *pmcs_source, *pmds_source; + int the_cpu; int ret = 0; -#ifdef CONFIG_SMP - /* We must wait until the state has been completely - * saved. There can be situations where the reader arrives before - * after the task is marked as STOPPED but before pfm_save_regs() - * is completed. - */ - if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY; - DBprintk(("before wait_task_inactive [%d] state %ld\n", task->pid, task->state)); - wait_task_inactive(task); - DBprintk(("after wait_task_inactive [%d] state %ld\n", task->pid, task->state)); -#else - if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) { - DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state)); - ret = -EBUSY; + + /* + * can only load from unloaded or terminated state + */ + if (CTX_IS_UNLOADED(ctx) == 0 && CTX_IS_TERMINATED(ctx) == 0) { + DPRINT(("[%d] cannot load to [%d], invalid ctx_state=%d\n", + current->pid, + req->load_pid, + ctx->ctx_state)); + return -EINVAL; } -#endif - return ret; -} -asmlinkage long -sys_perfmonctl (pid_t pid, int cmd, void *arg, int count, long arg5, long arg6, long arg7, - long arg8, long stack) -{ - struct pt_regs *regs = (struct pt_regs *)&stack; - struct task_struct *task = current; - pfm_context_t *ctx; - size_t sz; - int ret, narg; + DPRINT(("load_pid [%d]\n", req->load_pid)); - /* - * reject any call if perfmon was disabled at initialization time + if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) { + DPRINT(("cannot use blocking mode on self for [%d]\n", current->pid)); + return -EINVAL; + } + + ret = pfm_get_task(ctx, req->load_pid, &task); + if (ret) { + DPRINT(("load_pid [%d] get_task=%d\n", req->load_pid, ret)); + return ret; + } + + ret = -EINVAL; + + /* + * system wide is self monitoring only */ - if (PFM_IS_DISABLED()) return -ENOSYS; + if (ctx->ctx_fl_system && task != current) { + DPRINT(("system wide is self monitoring only current=%d load_pid=%d\n", + current->pid, + req->load_pid)); + goto error; + } - DBprintk(("cmd=%d idx=%d valid=%d narg=0x%x\n", cmd, PFM_CMD_IDX(cmd), - PFM_CMD_IS_VALID(cmd), PFM_CMD_NARG(cmd))); + thread = &task->thread; - if (PFM_CMD_IS_VALID(cmd) == 0) return -EINVAL; + ret = -EBUSY; - /* ingore arguments when command has none */ - narg = PFM_CMD_NARG(cmd); - if ((narg == PFM_CMD_ARG_MANY && count == 0) || (narg > 0 && narg != count)) return -EINVAL; + /* + * cannot load a context which is using range restrictions, + * into a task that is being debugged. + */ + if (ctx->ctx_fl_using_dbreg && (thread->flags & IA64_THREAD_DBG_VALID)) { + DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid)); + goto error; + } - sz = PFM_CMD_ARG_SIZE(cmd); + /* + * SMP system-wide monitoring implies self-monitoring. + * + * The programming model expects the task to + * be pinned on a CPU throughout the session. + * Here we take note of the current CPU at the + * time the context is loaded. No call from + * another CPU will be allowed. + * + * The pinning via shed_setaffinity() + * must be done by the calling task prior + * to this call. + * + * systemwide: keep track of CPU this session is supposed to run on + */ + the_cpu = ctx->ctx_cpu = smp_processor_id(); - if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT; + /* + * now reserve the session + */ + ret = pfm_reserve_session(current, ctx->ctx_fl_system, the_cpu); + if (ret) goto error; + + ret = -EBUSY; + /* + * task is necessarily stopped at this point. + * + * If the previous context was zombie, then it got removed in + * pfm_save_regs(). Therefore we should not see it here. + * If we see a context, then this is an active context + * + * XXX: needs to be atomic + */ + DPRINT(("[%d] before cmpxchg() old_ctx=%p new_ctx=%p\n", + current->pid, + thread->pfm_context, ctx)); - if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT; + old = ia64_cmpxchg("acq", &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *)); + if (old != NULL) { + DPRINT(("load_pid [%d] already has a context\n", req->load_pid)); + goto error_unres; + } - if (PFM_CMD_USE_PID(cmd)) { - /* - * XXX: may need to fine tune this one - */ - if (pid < 2) return -EPERM; + pfm_reset_msgq(ctx); - if (pid != current->pid) { + CTX_LOADED(ctx); - ret = -ESRCH; + /* + * link context to task + */ + ctx->ctx_task = task; - read_lock(&tasklist_lock); + if (ctx->ctx_fl_system) { - task = find_task_by_pid(pid); + /* + * we load as stopped + */ + PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - if (task) get_task_struct(task); + if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); + } else { + thread->flags |= IA64_THREAD_PM_VALID; + } - read_unlock(&tasklist_lock); + /* + * propagate into thread-state + */ + pfm_copy_pmds(task, ctx); + pfm_copy_pmcs(task, ctx); - if (!task) goto abort_call; + pmcs_source = thread->pmcs; + pmds_source = thread->pmds; - ret = -EPERM; + /* + * always the case for system-wide + */ + if (task == current) { - if (pfm_bad_permissions(task)) goto abort_call; + if (ctx->ctx_fl_system == 0) { - if (PFM_CMD_CHK(cmd)) { - ret = check_task_state(task); - if (ret != 0) goto abort_call; - } + /* allow user level control */ + ia64_psr(regs)->sp = 0; + DPRINT(("clearing psr.sp for [%d]\n", task->pid)); + + SET_LAST_CPU(ctx, smp_processor_id()); + INC_ACTIVATION(); + SET_ACTIVATION(ctx); +#ifndef CONFIG_SMP + /* + * push the other task out, if any + */ + owner_task = GET_PMU_OWNER(); + if (owner_task) pfm_lazy_save_regs(owner_task); +#endif } - } + /* + * load all PMD from ctx to PMU (as opposed to thread state) + * restore all PMC from ctx to PMU + */ + pfm_restore_pmds(pmds_source, ctx->ctx_all_pmds[0]); + pfm_restore_pmcs(pmcs_source, ctx->ctx_all_pmcs[0]); - ctx = task->thread.pfm_context; + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; - if (PFM_CMD_USE_CTX(cmd)) { - ret = -EINVAL; - if (ctx == NULL) { - DBprintk(("no context for task %d\n", task->pid)); - goto abort_call; - } - ret = -EPERM; - /* - * we only grant access to the context if: - * - the caller is the creator of the context (ctx_owner) - * OR - the context is attached to the caller AND The context IS NOT - * in protected mode - */ - if (ctx->ctx_owner != current && (ctx->ctx_fl_protected || task != current)) { - DBprintk(("context protected, no access for [%d]\n", task->pid)); - goto abort_call; - } + /* + * guaranteed safe by earlier check against DBG_VALID + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } + /* + * set new ownership + */ + SET_PMU_OWNER(task, ctx); + + DPRINT(("context loaded on PMU for [%d]\n", task->pid)); + } else { + /* + * when not current, task MUST be stopped, so this is safe + */ + regs = ia64_task_regs(task); + + /* force a full reload */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* initial saved psr (stopped) */ + ctx->ctx_saved_psr = pfm_get_psr() & ~(IA64_PSR_PP|IA64_PSR_UP); + ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; + + if (ctx->ctx_fl_unsecure) { + ia64_psr(regs)->sp = 0; + DPRINT(("context unsecured for [%d]\n", task->pid)); + } } - ret = (*pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func)(task, ctx, arg, count, regs); + ret = 0; -abort_call: - if (task && task != current) put_task_struct(task); +error_unres: + if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu); +error: + /* + * release task, there is now a link with the context + */ + if (ctx->ctx_fl_system == 0 && task != current) pfm_put_task(task); return ret; } /* - * send SIGPROF to register task, must be invoked when it - * is safe to send a signal, e.g., not holding any runqueue - * related locks. + * in this function, we do not need to increase the use count + * for the task via get_task_struct(), because we hold the + * context lock. If the task were to disappear while having + * a context attached, it would go through pfm_exit_thread() + * which also grabs the context lock and would therefore be blocked + * until we are here. */ +static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx); + static int -pfm_notify_user(pfm_context_t *ctx) +pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { - struct siginfo si; - int ret; + struct task_struct *task = ctx->ctx_task; + struct pt_regs *tregs; - if (ctx->ctx_notify_task == NULL) { - DBprintk(("[%d] no notifier\n", current->pid)); - return -EINVAL; + DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); + + /* + * unload only when necessary + */ + if (CTX_IS_TERMINATED(ctx) || CTX_IS_UNLOADED(ctx)) { + DPRINT(("[%d] ctx_state=%d, nothing to do\n", current->pid, ctx->ctx_state)); + return 0; } - si.si_errno = 0; - si.si_addr = NULL; - si.si_pid = current->pid; /* who is sending */ - si.si_signo = SIGPROF; - si.si_code = PROF_OVFL; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (ctx->ctx_fl_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("[%d] should be running on CPU%d\n", current->pid, ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * clear psr and dcr bits + */ + pfm_stop(ctx, NULL, 0, regs); - si.si_pfm_ovfl[0] = ctx->ctx_ovfl_regs[0]; + CTX_UNLOADED(ctx); /* - * when the target of the signal is not ourself, we have to be more - * careful. The notify_task may being cleared by the target task itself - * in release_thread(). We must ensure mutual exclusion here such that - * the signal is delivered (even to a dying task) safely. + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. */ + if (ctx->ctx_fl_system) { - if (ctx->ctx_notify_task != current) { /* - * grab the notification lock for this task - * This guarantees that the sequence: test + send_signal - * is atomic with regards to the ctx_notify_task field. - * - * We need a spinlock and not just an atomic variable for this. + * Update cpuinfo * + * local PMU is taken care of in pfm_stop() */ - spin_lock(&ctx->ctx_lock); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); /* - * now notify_task cannot be modified until we're done - * if NULL, they it got modified while we were in the handler + * save PMDs in context + * release ownership */ - if (ctx->ctx_notify_task == NULL) { + pfm_flush_pmds(current, ctx); - spin_unlock(&ctx->ctx_lock); + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + */ + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); - /* - * If we've lost the notified task, then we will run - * to completion wbut keep the PMU frozen. Results - * will be incorrect anyway. We do not kill task - * to leave it possible to attach perfmon context - * to already running task. - */ - printk("perfmon: pfm_notify_user() lost notify_task\n"); - DBprintk_ovfl(("notification task has disappeared !\n")); + /* + * disconnect context from task + */ + task->thread.pfm_context = NULL; + /* + * disconnect task from context + */ + ctx->ctx_task = NULL; - /* we cannot afford to block now */ - ctx->ctx_fl_block = 0; + /* + * There is nothing more to cleanup here. + */ + return 0; + } - return -EINVAL; - } + /* + * per-task mode + */ + tregs = task == current ? regs : ia64_task_regs(task); + if (task == current || ctx->ctx_fl_unsecure) { /* - * required by send_sig_info() to make sure the target - * task does not disappear on us. + * cancel user level control */ - read_lock(&tasklist_lock); + ia64_psr(regs)->sp = 1; + DPRINT(("setting psr.sp for [%d]\n", task->pid)); + } /* - * in this case, we don't stop the task, we let it go on. It will - * necessarily go to the signal handler (if any) when it goes back to - * user mode. - */ - DBprintk_ovfl(("[%d] sending notification to [%d]\n", - current->pid, ctx->ctx_notify_task->pid)); + * save PMDs to context + * release ownership + */ + pfm_flush_pmds(task, ctx); - /* - * this call is safe in an interrupt handler, so does read_lock() on tasklist_lock + /* + * at this point we are done with the PMU + * so we can unreserve the resource. */ - ret = send_sig_info(SIGPROF, &si, ctx->ctx_notify_task); - if (ret) { - printk("perfmon: send_sig_info(process %d, SIGPROF)=%d\n", - ctx->ctx_notify_task->pid, ret); - } + pfm_unreserve_session(ctx, 0 , ctx->ctx_cpu); /* - * now undo the protections in order + * reset activation counter and psr */ - if (ctx->ctx_notify_task != current) { - read_unlock(&tasklist_lock); - spin_unlock(&ctx->ctx_lock); + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * PMU state will not be restored + */ + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + /* + * break links between context and task + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + PFM_SET_WORK_PENDING(task, 0); + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + + DPRINT(("disconnected [%d] from context\n", task->pid)); + + return 0; +} + +static void +pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + if (GET_PMU_OWNER() == task) { + DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); + SET_PMU_OWNER(NULL, NULL); } - return ret; + + /* + * disconnect the task from the context and vice-versa + */ + PFM_SET_WORK_PENDING(task, 0); + + task->thread.pfm_context = NULL; + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + DPRINT(("context <%d> force cleanup for [%d] by [%d]\n", ctx->ctx_fd, task->pid, current->pid)); } + +/* + * called only from exit_thread(): task == current + */ void -pfm_ovfl_block_reset(void) +pfm_exit_thread(struct task_struct *task) { - struct thread_struct *th = ¤t->thread; - pfm_context_t *ctx = current->thread.pfm_context; - unsigned int reason; + pfm_context_t *ctx; + unsigned long flags; + struct pt_regs *regs = ia64_task_regs(task); int ret; + int free_ok = 0; + + ctx = PFM_GET_CTX(task); + + PROTECT_CTX(ctx, flags); + + DPRINT(("state=%d task [%d]\n", ctx->ctx_state, task->pid)); /* - * clear the flag, to make sure we won't get here - * again + * come here only if attached */ - th->pfm_ovfl_block_reset = 0; - clear_thread_flag(TIF_NOTIFY_RESUME); + if (unlikely(CTX_IS_UNLOADED(ctx))) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] ctx unloaded\n", task->pid); + goto skip_all; + } + + if (CTX_IS_LOADED(ctx) || CTX_IS_MASKED(ctx)) { + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, ctx->ctx_state, ret); + } + CTX_TERMINATED(ctx); + DPRINT(("ctx terminated by [%d]\n", task->pid)); + + pfm_end_notify_user(ctx); + + } else if (CTX_IS_ZOMBIE(ctx)) { + pfm_clear_psr_up(); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_force_cleanup(ctx, regs); + + free_ok = 1; + } + { u64 psr = pfm_get_psr(); + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + } +skip_all: + UNPROTECT_CTX(ctx, flags); /* - * do some sanity checks first + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. */ - if (!ctx) { - printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); - return; + if (free_ok) pfm_context_free(ctx); +} + +/* + * functions MUST be listed in the increasing order of their index (see permfon.h) + */ +#define PFM_CMD(name, flags, arg_count, arg_type, getsz) { name, #name, flags, arg_count, sizeof(arg_type), getsz } +#define PFM_CMD_S(name, flags) { name, #name, flags, 0, 0, NULL } +#define PFM_CMD_PCLRWS (PFM_CMD_FD|PFM_CMD_ARG_RW|PFM_CMD_STOP) +#define PFM_CMD_PCLRW (PFM_CMD_FD|PFM_CMD_ARG_RW) +#define PFM_CMD_NONE { NULL, "no-cmd", 0, 0, 0, NULL} + +static pfm_cmd_desc_t pfm_cmd_tab[]={ +/* 0 */PFM_CMD_NONE, +/* 1 */PFM_CMD(pfm_write_pmcs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 2 */PFM_CMD(pfm_write_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 3 */PFM_CMD(pfm_read_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 4 */PFM_CMD_S(pfm_stop, PFM_CMD_PCLRWS), +/* 5 */PFM_CMD_S(pfm_start, PFM_CMD_PCLRWS), +/* 6 */PFM_CMD_NONE, +/* 7 */PFM_CMD_NONE, +/* 8 */PFM_CMD(pfm_context_create, PFM_CMD_ARG_RW, 1, pfarg_context_t, pfm_ctx_getsize), +/* 9 */PFM_CMD_NONE, +/* 10 */PFM_CMD_S(pfm_restart, PFM_CMD_PCLRW), +/* 11 */PFM_CMD_NONE, +/* 12 */PFM_CMD(pfm_get_features, PFM_CMD_ARG_RW, 1, pfarg_features_t, NULL), +/* 13 */PFM_CMD(pfm_debug, 0, 1, unsigned int, NULL), +/* 14 */PFM_CMD_NONE, +/* 15 */PFM_CMD(pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 16 */PFM_CMD(pfm_context_load, PFM_CMD_PCLRWS, 1, pfarg_load_t, NULL), +/* 17 */PFM_CMD_S(pfm_context_unload, PFM_CMD_PCLRWS), +/* 18 */PFM_CMD_NONE, +/* 19 */PFM_CMD_NONE, +/* 20 */PFM_CMD_NONE, +/* 21 */PFM_CMD_NONE, +/* 22 */PFM_CMD_NONE, +/* 23 */PFM_CMD_NONE, +/* 24 */PFM_CMD_NONE, +/* 25 */PFM_CMD_NONE, +/* 26 */PFM_CMD_NONE, +/* 27 */PFM_CMD_NONE, +/* 28 */PFM_CMD_NONE, +/* 29 */PFM_CMD_NONE, +/* 30 */PFM_CMD_NONE, +/* 31 */PFM_CMD_NONE, +/* 32 */PFM_CMD(pfm_write_ibrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL), +/* 33 */PFM_CMD(pfm_write_dbrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL) +}; +#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) + +static int +pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags) +{ + struct task_struct *task; + + task = PFM_CTX_TASK(ctx); + if (task == NULL) { + DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, ctx->ctx_state)); + return 0; } + + DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n", + ctx->ctx_fd, + ctx->ctx_state, + task->pid, + task->state, PFM_CMD_STOPPED(cmd))); + /* - * extract reason for being here and clear + * self-monitoring always ok. + * + * for system-wide the caller can either be the creator of the + * context (to one to which the context is attached to) OR + * a task running on the same CPU as the session. */ - reason = ctx->ctx_fl_trap_reason; - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + if (task == current || ctx->ctx_fl_system) return 0; + + /* + * context is UNLOADED, MASKED, TERMINATED we are safe to go + */ + if (CTX_IS_LOADED(ctx) == 0) return 0; - DBprintk(("[%d] reason=%d\n", current->pid, reason)); + if (CTX_IS_ZOMBIE(ctx)) return -EINVAL; /* - * just here for a reset (non-blocking context only) + * context is loaded, we must make sure the task is stopped + * We could lift this restriction for UP but it would mean that + * the user has no guarantee the task would not run between + * two successive calls to perfmonctl(). That's probably OK. + * If this user wants to ensure the task does not run, then + * the task must be stopped. */ - if (reason == PFM_TRAP_REASON_RESET) goto non_blocking; + if (PFM_CMD_STOPPED(cmd) && task->state != TASK_STOPPED) { + DPRINT(("[%d] task not in stopped state\n", task->pid)); + return -EBUSY; + } + + UNPROTECT_CTX(ctx, flags); + + pfm_wait_task_inactive(task); + + PROTECT_CTX(ctx, flags); + return 0; +} + +/* + * system-call entry point (must return long) + */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, + long arg8, long stack) +{ + struct pt_regs *regs = (struct pt_regs *)&stack; + struct file *file = NULL; + pfm_context_t *ctx = NULL; + unsigned long flags = 0UL; + void *args_k = NULL; + long ret; /* will expand int return types */ + size_t base_sz, sz, xtra_sz = 0; + int narg, completed_args = 0, call_made = 0; +#define PFM_MAX_ARGSIZE 4096 /* - * first notify user. This can fail if notify_task has disappeared. + * reject any call if perfmon was disabled at initialization time */ - if (reason == PFM_TRAP_REASON_SIG || reason == PFM_TRAP_REASON_BLOCKSIG) { - ret = pfm_notify_user(ctx); - if (ret) return; + if (PFM_IS_DISABLED()) return -ENOSYS; + + if (unlikely(PFM_CMD_IS_VALID(cmd) == 0)) { + DPRINT(("[%d] invalid cmd=%d\n", current->pid, cmd)); + return -EINVAL; } + DPRINT(("cmd=%s idx=%d valid=%d narg=0x%x argsz=%lu count=%d\n", + PFM_CMD_NAME(cmd), + PFM_CMD_IDX(cmd), + PFM_CMD_IS_VALID(cmd), + PFM_CMD_NARG(cmd), + PFM_CMD_ARG_SIZE(cmd), count)); + /* - * came here just to signal (non-blocking) + * check if number of arguments matches what the command expects */ - if (reason == PFM_TRAP_REASON_SIG) return; + narg = PFM_CMD_NARG(cmd); + if ((narg == PFM_CMD_ARG_MANY && count <= 0) || (narg > 0 && narg != count)) + return -EINVAL; - DBprintk(("[%d] before sleeping\n", current->pid)); + /* get single argument size */ + base_sz = PFM_CMD_ARG_SIZE(cmd); +restart_args: + sz = xtra_sz + base_sz*count; /* - * may go through without blocking on SMP systems - * if restart has been received already by the time we call down() + * limit abuse to min page size */ - ret = down_interruptible(&ctx->ctx_restart_sem); + if (unlikely(sz > PFM_MAX_ARGSIZE)) { + printk(KERN_ERR "perfmon: [%d] argument too big %lu\n", current->pid, sz); + return -E2BIG; + } - DBprintk(("[%d] after sleeping ret=%d\n", current->pid, ret)); + /* + * allocate default-sized argument buffer + */ + if (count && args_k == NULL) { + args_k = kmalloc(PFM_MAX_ARGSIZE, GFP_KERNEL); + if (args_k == NULL) return -ENOMEM; + } + + ret = -EFAULT; /* - * in case of interruption of down() we don't restart anything + * copy arguments + * + * assume sz = 0 for command without parameters */ - if (ret >= 0) { + if (sz && copy_from_user(args_k, arg, sz)) { + DPRINT(("[%d] cannot copy_from_user %lu bytes @%p\n", current->pid, sz, arg)); + goto error_args; + } -non_blocking: - /* we reactivate on context switch */ - ctx->ctx_fl_frozen = 0; + /* + * check if command supports extra parameters + */ + if (completed_args == 0 && PFM_CMD_GETSIZE(cmd)) { /* - * the ovfl_sem is cleared by the restart task and this is safe because we always - * use the local reference + * get extra parameters size (based on main argument) */ + ret = PFM_CMD_GETSIZE(cmd)(args_k, &xtra_sz); + if (ret) goto error_args; - pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); + completed_args = 1; - ctx->ctx_ovfl_regs[0] = 0UL; + DPRINT(("[%d] restart_args sz=%lu xtra_sz=%lu\n", current->pid, sz, xtra_sz)); + + /* retry if necessary */ + if (xtra_sz) goto restart_args; + } + + if (PFM_CMD_USE_FD(cmd)) { + + ret = -EBADF; + + file = fget(fd); + if (file == NULL) { + DPRINT(("[%d] invalid fd %d\n", current->pid, fd)); + goto error_args; + } + if (PFM_IS_FILE(file) == 0) { + DPRINT(("[%d] fd %d not related to perfmon\n", current->pid, fd)); + goto error_args; + } + + + ctx = (pfm_context_t *)file->private_data; + if (ctx == NULL) { + DPRINT(("[%d] no context for fd %d\n", current->pid, fd)); + goto error_args; + } + + PROTECT_CTX(ctx, flags); /* - * Unlock sampling buffer and reset index atomically - * XXX: not really needed when blocking + * check task is stopped */ - if (CTX_HAS_SMPL(ctx)) { - ctx->ctx_psb->psb_hdr->hdr_count = 0; - ctx->ctx_psb->psb_index = 0; - } + ret = pfm_check_task_state(ctx, cmd, flags); + if (ret) goto abort_locked; + } - pfm_unfreeze_pmu(); + ret = (*pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func)(ctx, args_k, count, regs); + + call_made = 1; + +abort_locked: + if (ctx) { + DPRINT(("[%d] context unlocked\n", current->pid)); + UNPROTECT_CTX(ctx, flags); + fput(file); + } - /* state restored, can go back to work (user mode) */ + /* copy argument back to user, if needed */ + if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT; + +error_args: + if (args_k) kfree(args_k); + + return ret; +} + +static void +pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_regs *regs) +{ + pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int ret = 0; + + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + + rst_ctrl.stop_monitoring = 1; + rst_ctrl.reset_pmds = PFM_PMD_NO_RESET; + + /* XXX: check return value */ + if (fmt->fmt_restart) + ret = (*fmt->fmt_restart)(current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.stop_monitoring = 0; + rst_ctrl.reset_pmds = PFM_PMD_LONG_RESET; + } + + if (ret == 0) { + if (rst_ctrl.reset_pmds != PFM_PMD_NO_RESET) + pfm_reset_regs(ctx, &ovfl_regs, rst_ctrl.reset_pmds); + + if (rst_ctrl.stop_monitoring == 0) { + DPRINT(("resuming monitoring\n")); + if (CTX_IS_MASKED(ctx)) pfm_restore_monitoring(current); + } else { + DPRINT(("stopping monitoring\n")); + //pfm_stop_monitoring(current, regs); + } + CTX_LOADED(ctx); } } + /* - * This function will record an entry in the sampling if it is not full already. - * Return: - * 0 : buffer is not full (did not BECOME full: still space or was already full) - * 1 : buffer is full (recorded the last entry) + * context MUST BE LOCKED when calling + * can only be called for current */ -static int -pfm_record_sample(struct task_struct *task, pfm_context_t *ctx, unsigned long ovfl_mask, struct pt_regs *regs) +static void +pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) { - pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; - unsigned long *e, m, idx; - perfmon_smpl_entry_t *h; - int j; - + if (ctx->ctx_fl_system) { + printk(KERN_ERR "perfmon: pfm_context_force_terminate [%d] is system-wide\n", current->pid); + return; + } + /* + * we stop the whole thing, we do no need to flush + * we know we WERE masked + */ + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; - idx = ia64_fetch_and_add(1, &psb->psb_index); - DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries)); + /* + * disconnect the task from the context and vice-versa + */ + current->thread.pfm_context = NULL; + current->thread.flags &= ~IA64_THREAD_PM_VALID; + ctx->ctx_task = NULL; /* - * XXX: there is a small chance that we could run out on index before resetting - * but index is unsigned long, so it will take some time..... - * We use > instead of == because fetch_and_add() is off by one (see below) - * - * This case can happen in non-blocking mode or with multiple processes. - * For non-blocking, we need to reload and continue. - */ - if (idx > psb->psb_entries) return 0; + * switch to terminated state + */ + CTX_TERMINATED(ctx); - /* first entry is really entry 0, not 1 caused by fetch_and_add */ - idx--; + DPRINT(("context <%d> terminated for [%d]\n", ctx->ctx_fd, current->pid)); - h = (perfmon_smpl_entry_t *)(((char *)psb->psb_addr) + idx*(psb->psb_entry_size)); + /* + * and wakeup controlling task, indicating we are now disconnected + */ + wake_up_interruptible(&ctx->ctx_zombieq); /* - * initialize entry header + * given that context is still locked, the controlling + * task will only get access when we return from + * pfm_handle_work(). */ - h->pid = current->pid; - h->cpu = get_cpu(); - h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL; - h->ip = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL; - h->regs = ovfl_mask; /* which registers overflowed */ +} + +static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); + +void +pfm_handle_work(void) +{ + pfm_context_t *ctx; + struct pt_regs *regs; + unsigned long flags; + unsigned long ovfl_regs; + unsigned int reason; + int ret; - /* guaranteed to monotonically increase on each cpu */ - h->stamp = pfm_get_stamp(); + ctx = PFM_GET_CTX(current); + if (ctx == NULL) { + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); + return; + } + + PROTECT_CTX(ctx, flags); + + PFM_SET_WORK_PENDING(current, 0); - /* position for first pmd */ - e = (unsigned long *)(h+1); + pfm_clear_task_notify(); + + regs = ia64_task_regs(current); /* - * selectively store PMDs in increasing index number + * extract reason for being here and clear */ - m = ctx->ctx_smpl_regs[0]; - for (j=0; m; m >>=1, j++) { + reason = ctx->ctx_fl_trap_reason; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - if ((m & 0x1) == 0) continue; + DPRINT(("[%d] reason=%d\n", current->pid, reason)); - if (PMD_IS_COUNTING(j)) { - *e = pfm_read_soft_counter(ctx, j); - } else { - *e = ia64_get_pmd(j); /* slow */ - } - DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e)); - e++; - } - pfm_stats[h->cpu].pfm_recorded_samples_count++; + /* + * must be done before we check non-blocking mode + */ + if (ctx->ctx_fl_going_zombie || CTX_IS_ZOMBIE(ctx)) goto do_zombie; + + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; + if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("before block sleeping\n")); /* - * make the new entry visible to user, needs to be atomic + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() */ - ia64_fetch_and_add(1, &psb->psb_hdr->hdr_count); + ret = down_interruptible(&ctx->ctx_restart_sem); - DBprintk_ovfl(("index=%ld entries=%ld hdr_count=%ld\n", - idx, psb->psb_entries, psb->psb_hdr->hdr_count)); - /* - * sampling buffer full ? + DPRINT(("after block sleeping ret=%d\n", ret)); + + PROTECT_CTX(ctx, flags); + + if (ctx->ctx_fl_going_zombie) { +do_zombie: + DPRINT(("context is zombie, bailing out\n")); + pfm_context_force_terminate(ctx, regs); + goto nothing_to_do; + } + /* + * in case of interruption of down() we don't restart anything */ - if (idx == (psb->psb_entries-1)) { - DBprintk_ovfl(("sampling buffer full\n")); - /* - * XXX: must reset buffer in blocking mode and lost notified - */ - pfm_stats[h->cpu].pfm_full_smpl_buffer_count++; - put_cpu(); - return 1; + if (ret < 0) goto nothing_to_do; + +skip_blocking: + pfm_resume_after_ovfl(ctx, ovfl_regs, regs); + ctx->ctx_ovfl_regs[0] = 0UL; + +nothing_to_do: + + UNPROTECT_CTX(ctx, flags); +} + +static int +pfm_notify_user(pfm_context_t *ctx, pfm_msg_t *msg) +{ + if (CTX_IS_ZOMBIE(ctx)) { + DPRINT(("ignoring overflow notification, owner is zombie\n")); + return 0; } - put_cpu(); + + DPRINT(("[%d] waking up somebody\n", current->pid)); + + if (msg) wake_up_interruptible(&ctx->ctx_msgq_wait); + + /* + * safe, we are not in intr handler, nor in ctxsw when + * we come here + */ + kill_fasync (&ctx->ctx_async_queue, SIGIO, POLL_IN); + return 0; } +static int +pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds) +{ + pfm_msg_t *msg = NULL; + + if (ctx->ctx_fl_no_msg == 0) { + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_ovfl_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_ovfl_msg.msg_type = PFM_MSG_OVFL; + msg->pfm_ovfl_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = ia64_get_itc(); /* relevant on UP only */ + msg->pfm_ovfl_msg.msg_active_set = 0; + msg->pfm_ovfl_msg.msg_ovfl_pmds[0] = ovfl_pmds; + msg->pfm_ovfl_msg.msg_ovfl_pmds[1] = msg->pfm_ovfl_msg.msg_ovfl_pmds[2] = msg->pfm_ovfl_msg.msg_ovfl_pmds[3] = 0UL; + + } + + DPRINT(("ovfl msg: msg=%p no_msg=%d fd=%d pid=%d ovfl_pmds=0x%lx\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, + current->pid, + ovfl_pmds)); + + return pfm_notify_user(ctx, msg); +} + +static int +pfm_end_notify_user(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_end_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_end_msg.msg_type = PFM_MSG_END; + msg->pfm_end_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = ia64_get_itc(); /* relevant on UP only */ + + DPRINT(("end msg: msg=%p no_msg=%d ctx_fd=%d pid=%d\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, current->pid)); + + return pfm_notify_user(ctx, msg); +} + /* * main overflow processing routine. - * it can be called from the interrupt path or explicitly during the context switch code - * Arguments: - * mode: 0=coming from PMU interrupt, 1=coming from ctxsw - * - * Return: - * new value of pmc[0]. if 0x0 then unfreeze, else keep frozen + * it can be called from the interrupt path or explicitely during the context switch code */ -static unsigned long -pfm_overflow_handler(int mode, struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +static void +pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) { - struct thread_struct *t; + pfm_ovfl_arg_t ovfl_arg; unsigned long mask; unsigned long old_val; - unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL; - int i; - int ret = 1; - /* - * It is never safe to access the task for which the overflow interrupt is destinated - * using the current variable as the interrupt may occur in the middle of a context switch - * where current does not hold the task that is running yet. - * - * For monitoring, however, we do need to get access to the task which caused the overflow - * to account for overflow on the counters. - * - * We accomplish this by maintaining a current owner of the PMU per CPU. During context - * switch the ownership is changed in a way such that the reflected owner is always the - * valid one, i.e. the one that caused the interrupt. - */ + unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL; + pfm_ovfl_ctrl_t ovfl_ctrl; + unsigned int i, j, has_smpl, first_pmd = ~0U; + int must_notify = 0; - preempt_disable(); - - t = &task->thread; + if (unlikely(CTX_IS_ZOMBIE(ctx))) goto stop_monitoring; /* - * XXX: debug test - * Don't think this could happen given upfront tests - */ - if ((t->flags & IA64_THREAD_PM_VALID) == 0 && ctx->ctx_fl_system == 0) { - printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d not " - "using perfmon\n", task->pid); - preempt_enable_no_resched(); - return 0x1; - } - /* * sanity test. Should never happen */ - if ((pmc0 & 0x1) == 0) { - printk(KERN_DEBUG "perfmon: pid %d pmc0=0x%lx assumption error for freeze bit\n", - task->pid, pmc0); - preempt_enable_no_resched(); - return 0x0; - } + if (unlikely((pmc0 & 0x1) == 0)) goto sanity_check; mask = pmc0 >> PMU_FIRST_COUNTER; - DBprintk_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s" - " mode used_pmds=0x%lx used_pmcs=0x%lx reload_pmcs=0x%lx\n", - pmc0, task->pid, (regs ? regs->cr_iip : 0), + DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s" + "used_pmds=0x%lx reload_pmcs=0x%lx\n", + pmc0, + task ? task->pid: -1, + (regs ? regs->cr_iip : 0), CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", ctx->ctx_used_pmds[0], - ctx->ctx_used_pmcs[0], ctx->ctx_reload_pmcs[0])); + has_smpl = CTX_HAS_SMPL(ctx); + /* - * First we update the virtual counters + * first we update the virtual counters + * assume there was a prior ia64_srlz_d() issued */ for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { /* skip pmd which did not overflow */ if ((mask & 0x1) == 0) continue; - DBprintk_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx soft_pmd=0x%lx\n", - i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val)); + DPRINT_ovfl(("pmd[%d] overflowed hw_pmd=0x%lx ctx_pmd=0x%lx\n", + i, ia64_get_pmd(i), ctx->ctx_pmds[i].val)); /* * Note that the pmd is not necessarily 0 at this point as qualified events @@ -2993,250 +5204,350 @@ * taken into consideration here but will be with any read of the pmd via * pfm_read_pmds(). */ - old_val = ctx->ctx_soft_pmds[i].val; - ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val; + old_val = ctx->ctx_pmds[i].val; + ctx->ctx_pmds[i].val += 1 + pmu_conf.ovfl_val; /* * check for overflow condition */ - if (old_val > ctx->ctx_soft_pmds[i].val) { + if (likely(old_val > ctx->ctx_pmds[i].val)) { ovfl_pmds |= 1UL << i; - if (PMC_OVFL_NOTIFY(ctx, i)) { - ovfl_notify |= 1UL << i; + /* + * keep track of pmds of interest for samples + */ + if (has_smpl) { + if (first_pmd == ~0U) first_pmd = i; + smpl_pmds |= ctx->ctx_pmds[i].smpl_pmds[0]; } + + if (PMC_OVFL_NOTIFY(ctx, i)) ovfl_notify |= 1UL << i; } - DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", - i, ctx->ctx_soft_pmds[i].val, old_val, - ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify)); + + DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx first_pmd=%u smpl_pmds=0x%lx\n", + i, ctx->ctx_pmds[i].val, old_val, + ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify, first_pmd, smpl_pmds)); } + ovfl_ctrl.notify_user = ovfl_notify ? 1 : 0; + ovfl_ctrl.reset_pmds = ovfl_pmds && ovfl_notify == 0UL ? 1 : 0; + ovfl_ctrl.block = ovfl_notify ? 1 : 0; + ovfl_ctrl.stop_monitoring = ovfl_notify ? 1 : 0; + /* - * check for sampling buffer - * - * if present, record sample only when a 64-bit counter has overflowed. - * We propagate notification ONLY when buffer becomes full. + * when a overflow is detected, check for sampling buffer, if present, invoke + * record() callback. */ - if(CTX_HAS_SMPL(ctx) && ovfl_pmds) { - ret = pfm_record_sample(task, ctx, ovfl_pmds, regs); - if (ret == 1) { - /* - * Sampling buffer became full - * If no notication was requested, then we reset buffer index - * and reset registers (done below) and resume. - * If notification requested, then defer reset until pfm_restart() - */ - if (ovfl_notify == 0UL) { - ctx->ctx_psb->psb_hdr->hdr_count = 0UL; - ctx->ctx_psb->psb_index = 0UL; + if (ovfl_pmds && has_smpl) { + unsigned long start_cycles; + int this_cpu = smp_processor_id(); + + ovfl_arg.ovfl_pmds[0] = ovfl_pmds; + ovfl_arg.ovfl_notify[0] = ovfl_notify; + ovfl_arg.ovfl_ctrl = ovfl_ctrl; + ovfl_arg.smpl_pmds[0] = smpl_pmds; + + prefetch(ctx->ctx_smpl_hdr); + + ovfl_arg.pmd_value = ctx->ctx_pmds[first_pmd].val; + ovfl_arg.pmd_last_reset = ctx->ctx_pmds[first_pmd].lval; + ovfl_arg.pmd_eventid = ctx->ctx_pmds[first_pmd].eventid; + + /* + * copy values of pmds of interest. Sampling format may copy them + * into sampling buffer. + */ + if (smpl_pmds) { + for(i=0, j=0; smpl_pmds; i++, smpl_pmds >>=1) { + if ((smpl_pmds & 0x1) == 0) continue; + ovfl_arg.smpl_pmds_values[j++] = PMD_IS_COUNTING(i) ? pfm_read_soft_counter(ctx, i) : ia64_get_pmd(i); } - } else { - /* - * sample recorded in buffer, no need to notify user - */ - ovfl_notify = 0UL; } - } - /* - * No overflow requiring a user level notification - */ - if (ovfl_notify == 0UL) { - if (ovfl_pmds) - pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET); - preempt_enable_no_resched(); - return 0x0UL; - } + pfm_stats[this_cpu].pfm_smpl_handler_calls++; + start_cycles = ia64_get_itc(); - /* - * keep track of what to reset when unblocking - */ - ctx->ctx_ovfl_regs[0] = ovfl_pmds; + /* + * call custom buffer format record (handler) routine + */ + (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, &ovfl_arg, regs); - DBprintk_ovfl(("block=%d notify [%d] current [%d]\n", - ctx->ctx_fl_block, - ctx->ctx_notify_task ? ctx->ctx_notify_task->pid: -1, - current->pid )); + pfm_stats[this_cpu].pfm_smpl_handler_cycles += ia64_get_itc() - start_cycles; - /* - * ctx_notify_task could already be NULL, checked in pfm_notify_user() - */ - if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_notify_task != task) { - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCKSIG; - } else { - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG; + ovfl_pmds = ovfl_arg.ovfl_pmds[0]; + ovfl_notify = ovfl_arg.ovfl_notify[0]; + ovfl_ctrl = ovfl_arg.ovfl_ctrl; + } + + if (ovfl_pmds && ovfl_ctrl.reset_pmds) { + pfm_reset_regs(ctx, &ovfl_pmds, ovfl_ctrl.reset_pmds); } - /* - * we cannot block in system wide mode and we do not go - * through the PMU ctxsw code. Therefore we can generate - * the notification here. In system wide mode, the current - * task maybe different from the task controlling the session - * on this CPU, therefore owner can be different from current. - * - * In per-process mode, this function gets called from - * the interrupt handler or pfm_load_regs(). The mode argument - * tells where we are coming from. When coming from the interrupt - * handler, it is safe to notify (send signal) right here because - * we do not hold any runqueue locks needed by send_sig_info(). - * - * However when coming from ctxsw, we cannot send the signal here. - * It must be deferred until we are sure we do not hold any runqueue - * related locks. The current task maybe different from the owner - * only in UP mode. The deferral is implemented using the - * TIF_NOTIFY_RESUME mechanism. In this case, the pending work - * is checked when the task is about to leave the kernel (see - * entry.S). As of this version of perfmon, a kernel only - * task cannot be monitored in per-process mode. Therefore, - * when this function gets called from pfm_load_regs(), we know - * we have a user level task which will eventually either exit - * or leave the kernel, and thereby go through the checkpoint - * for TIF_*. - */ - if (ctx->ctx_fl_system || mode == 0) { - pfm_notify_user(ctx); - ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - } else { - struct thread_info *info; + if (ovfl_notify && ovfl_ctrl.notify_user) { /* - * given that TIF_NOTIFY_RESUME is not specific to - * perfmon, we need to have a second level check to - * verify the source of the notification. + * keep track of what to reset when unblocking */ - task->thread.pfm_ovfl_block_reset = 1; + ctx->ctx_ovfl_regs[0] = ovfl_pmds; + + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ovfl_ctrl.block) { + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCK; + + /* + * set the perfmon specific checking pending work + */ + PFM_SET_WORK_PENDING(task, 1); + + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + pfm_set_task_notify(task); + } /* - * when coming from ctxsw, current still points to the - * previous task, therefore we must work with task and not current. + * defer until state is changed (shorten spin window). the context is locked + * anyway, so the signal receiver would come spin for nothing. */ - info = ((struct thread_info *) ((char *) task + IA64_TASK_SIZE)); - set_bit(TIF_NOTIFY_RESUME, &info->flags); + must_notify = 1; } + DPRINT_ovfl(("current [%d] owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx stopped=%d\n", + current->pid, + GET_PMU_OWNER() ? GET_PMU_OWNER()->pid : -1, + PFM_GET_WORK_PENDING(task), + ctx->ctx_fl_trap_reason, + ovfl_pmds, + ovfl_notify, + ovfl_ctrl.stop_monitoring ? 1 : 0)); + /* + * in case monitoring must be stopped, we toggle the psr bits + */ + if (ovfl_ctrl.stop_monitoring) { + pfm_mask_monitoring(task); + CTX_MASKED(ctx); + } /* - * keep the PMU frozen until either pfm_restart() or - * task completes (non-blocking or notify_task gone). + * send notification now */ - ctx->ctx_fl_frozen = 1; + if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify); - DBprintk_ovfl(("current [%d] owner [%d] mode=%d return pmc0=0x%x must_block=%ld reason=%d\n", - current->pid, - PMU_OWNER() ? PMU_OWNER()->pid : -1, - mode, - ctx->ctx_fl_frozen ? 0x1 : 0x0, - t->pfm_ovfl_block_reset, - ctx->ctx_fl_trap_reason)); + return; - preempt_enable_no_resched(); - return 0x1UL; + +sanity_check: + printk(KERN_ERR "perfmon: CPU%d overflow handler [%d] pmc0=0x%lx\n", + smp_processor_id(), + task ? task->pid : -1, + pmc0); + return; + +stop_monitoring: + /* + * in SMP, zombie context is never restored but reclaimed in pfm_load_regs(). + * Moreover, zombies are also reclaimed in pfm_save_regs(). Therefore we can + * come here as zombie only if the task is the current task. In which case, we + * can access the PMU hardware directly. + * + * Note that zombies do have PM_VALID set. So here we do the minimal. + * + * In case the context was zombified it could not be reclaimed at the time + * the monitoring program exited. At this point, the PMU reservation has been + * returned, the sampiing buffer has been freed. We must convert this call + * into a spurious interrupt. However, we must also avoid infinite overflows + * by stopping monitoring for this task. We can only come here for a per-task + * context. All we need to do is to stop monitoring using the psr bits which + * are always task private. By re-enabling secure montioring, we ensure that + * the monitored task will not be able to re-activate monitoring. + * The task will eventually be context switched out, at which point the context + * will be reclaimed (that includes releasing ownership of the PMU). + * + * So there might be a window of time where the number of per-task session is zero + * yet one PMU might have a owner and get at most one overflow interrupt for a zombie + * context. This is safe because if a per-task session comes in, it will push this one + * out and by the virtue on pfm_save_regs(), this one will disappear. If a system wide + * session is force on that CPU, given that we use task pinning, pfm_save_regs() will + * also push our zombie context out. + * + * Overall pretty hairy stuff.... + */ + DPRINT(("ctx is zombie for [%d], converted to spurious\n", task ? task->pid: -1)); + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + return; } -static irqreturn_t -pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +static int +pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) { - u64 pmc0; struct task_struct *task; pfm_context_t *ctx; + unsigned long flags; + u64 pmc0; + int this_cpu = smp_processor_id(); + int retval = 0; - pfm_stats[get_cpu()].pfm_ovfl_intr_count++; + pfm_stats[this_cpu].pfm_ovfl_intr_count++; /* - * if an alternate handler is registered, just bypass the default one - */ - if (pfm_alternate_intr_handler) { - (*pfm_alternate_intr_handler->handler)(irq, arg, regs); - put_cpu(); - return IRQ_HANDLED; - } - - /* * srlz.d done before arriving here - * - * This is slow */ - pmc0 = ia64_get_pmc(0); + pmc0 = ia64_get_pmc(0); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); /* * if we have some pending bits set - * assumes : if any PM[0].bit[63-1] is set, then PMC[0].fr = 1 + * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1 */ - if ((pmc0 & ~0x1UL)!=0UL && (task=PMU_OWNER())!= NULL) { - /* + if (PMC0_HAS_OVFL(pmc0) && task) { + /* * we assume that pmc0.fr is always set here */ - ctx = task->thread.pfm_context; /* sanity check */ - if (!ctx) { - printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d has " - "no PFM context\n", task->pid); - put_cpu(); - return IRQ_HANDLED; - } + if (!ctx) goto report_spurious; - /* - * assume PMC[0].fr = 1 at this point - */ - pmc0 = pfm_overflow_handler(0, task, ctx, pmc0, regs); - /* - * we can only update pmc0 when the overflow - * is for the current context or we are in system - * wide mode. In UP (per-task) the current - * task may not be the one owning the PMU, - * same thing for system-wide. - */ - if (task == current || ctx->ctx_fl_system) { - /* - * We always clear the overflow status bits and either unfreeze - * or keep the PMU frozen. - */ - ia64_set_pmc(0, pmc0); - ia64_srlz_d(); - } else { - task->thread.pmc[0] = pmc0; + if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) { + printk("perfmon: current [%d] owner = [%d] PMVALID=0 state=%d\n", current->pid, task->pid, ctx->ctx_state); + goto report_spurious; } + + PROTECT_CTX_NOPRINT(ctx, flags); + + pfm_overflow_handler(task, ctx, pmc0, regs); + + UNPROTECT_CTX_NOPRINT(ctx, flags); + } else { - pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++; + pfm_stats[this_cpu].pfm_spurious_ovfl_intr_count++; + retval = -1; + } + /* + * keep it unfrozen at all times + */ + pfm_unfreeze_pmu(); + + return retval; + +report_spurious: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n", + this_cpu, task->pid); + pfm_unfreeze_pmu(); + return -1; +} + +static pfm_irq_handler_t +pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + unsigned long m; + unsigned long min, max; + int this_cpu; + int ret; + + this_cpu = smp_processor_id(); + min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; + max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; + + m = ia64_get_itc(); + + ret = pfm_do_interrupt_handler(irq, arg, regs); + + m = ia64_get_itc() - m; + + /* + * don't measure spurious interrupts + */ + if (ret == 0) { + if (m < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = m; + if (m > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = m; + pfm_stats[this_cpu].pfm_ovfl_intr_cycles += m; } - put_cpu_no_resched(); - return IRQ_HANDLED; + PFM_IRQ_HANDLER_RET(); } + /* for debug only */ static int pfm_proc_info(char *page) { char *p = page; + pfm_buffer_fmt_t *b; + unsigned long psr; int i; - p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); - p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val); + p += sprintf(p, "model : %s\n", pmu_conf.pmu_name); + p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); + p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val); for(i=0; i < NR_CPUS; i++) { - if (cpu_online(i) == 0) continue; - p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count); - p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count); - p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count); - p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count); - p += sprintf(p, "CPU%-2d syst_wide : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_SYST_WIDE ? 1 : 0); - p += sprintf(p, "CPU%-2d dcr_pp : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_DCR_PP ? 1 : 0); - p += sprintf(p, "CPU%-2d exclude idle : %d\n", i, per_cpu(pfm_syst_info, i) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0); - p += sprintf(p, "CPU%-2d owner : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); + if (cpu_is_online(i) == 0) continue; + p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count); + p += sprintf(p, "CPU%-2d overflow cycles : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles); + p += sprintf(p, "CPU%-2d overflow min : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles_min); + p += sprintf(p, "CPU%-2d overflow max : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_cycles_max); + p += sprintf(p, "CPU%-2d smpl handler calls : %lu\n", i, pfm_stats[i].pfm_smpl_handler_calls); + p += sprintf(p, "CPU%-2d smpl handler cycles : %lu\n", i, pfm_stats[i].pfm_smpl_handler_cycles); + p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count); + p += sprintf(p, "CPU%-2d sysupdt count : %lu\n", i, pfm_stats[i].pfm_sysupdt_count); + p += sprintf(p, "CPU%-2d sysupdt cycles : %lu\n", i, pfm_stats[i].pfm_sysupdt_cycles); + p += sprintf(p, "CPU%-2d syst_wide : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_SYST_WIDE ? 1 : 0); + p += sprintf(p, "CPU%-2d dcr_pp : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_DCR_PP ? 1 : 0); + p += sprintf(p, "CPU%-2d exclude idle : %d\n" , i, pfm_get_cpu_data(pfm_syst_info, i) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0); + p += sprintf(p, "CPU%-2d owner : %d\n" , i, pfm_get_cpu_data(pmu_owner, i) ? pfm_get_cpu_data(pmu_owner, i)->pid: -1); + p += sprintf(p, "CPU%-2d context : %p\n" , i, pfm_get_cpu_data(pmu_ctx, i)); + p += sprintf(p, "CPU%-2d activations : %lu\n", i, pfm_get_cpu_data(pmu_activation_number,i)); + } + + if (hweight64(PFM_CPU_ONLINE_MAP) == 1) + { + psr = pfm_get_psr(); + ia64_srlz_d(); + p += sprintf(p, "CPU%-2d psr : 0x%lx\n", smp_processor_id(), psr); + p += sprintf(p, "CPU%-2d pmc0 : 0x%lx\n", smp_processor_id(), ia64_get_pmc(0)); + for(i=4; i < 8; i++) { + p += sprintf(p, "CPU%-2d pmc%u : 0x%lx\n", smp_processor_id(), i, ia64_get_pmc(i)); + p += sprintf(p, "CPU%-2d pmd%u : 0x%lx\n", smp_processor_id(), i, ia64_get_pmd(i)); + } } LOCK_PFS(); - - p += sprintf(p, "proc_sessions : %u\n" - "sys_sessions : %u\n" - "sys_use_dbregs : %u\n" - "ptrace_use_dbregs : %u\n", - pfm_sessions.pfs_task_sessions, + p += sprintf(p, "proc_sessions : %u\n" + "sys_sessions : %u\n" + "sys_use_dbregs : %u\n" + "ptrace_use_dbregs : %u\n", + pfm_sessions.pfs_task_sessions, pfm_sessions.pfs_sys_sessions, pfm_sessions.pfs_sys_use_dbregs, pfm_sessions.pfs_ptrace_use_dbregs); - UNLOCK_PFS(); + LOCK_BUF_FMT_LIST(); + + for (b = pfm_buffer_fmt_list; b ; b = b->fmt_next) { + p += sprintf(p, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n", + b->fmt_uuid[0], + b->fmt_uuid[1], + b->fmt_uuid[2], + b->fmt_uuid[3], + b->fmt_uuid[4], + b->fmt_uuid[5], + b->fmt_uuid[6], + b->fmt_uuid[7], + b->fmt_uuid[8], + b->fmt_uuid[9], + b->fmt_uuid[10], + b->fmt_uuid[11], + b->fmt_uuid[12], + b->fmt_uuid[13], + b->fmt_uuid[14], + b->fmt_uuid[15], + b->fmt_name); + } + UNLOCK_BUF_FMT_LIST(); + return p - page; } @@ -3258,30 +5569,27 @@ } /* - * we come here as soon as PFM_CPUINFO_SYST_WIDE is set. This happens + * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens * during pfm_enable() hence before pfm_start(). We cannot assume monitoring - * is active or inactive based on mode. We must rely on the value in - * cpu_data(i)->pfm_syst_info + * is active or inactive based on mode. We must rely on the value in + * local_cpu_data->pfm_syst_info */ void -pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +pfm_do_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) { struct pt_regs *regs; unsigned long dcr; unsigned long dcr_pp; - preempt_disable(); dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0; /* - * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 + * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 * on every CPU, so we can rely on the pid to identify the idle task. */ if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) { - regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET); - regs--; + regs = ia64_task_regs(task); ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0; - preempt_enable(); return; } /* @@ -3289,43 +5597,89 @@ */ if (dcr_pp) { dcr = ia64_get_dcr(); - /* - * context switching in? + /* + * context switching in? */ if (is_ctxswin) { /* mask monitoring for the idle task */ ia64_set_dcr(dcr & ~IA64_DCR_PP); pfm_clear_psr_pp(); ia64_srlz_i(); - preempt_enable(); return; } - /* + /* * context switching out - * restore monitoring for next task + * restore monitoring for next task * - * Due to inlining this odd if-then-else construction generates + * Due to inlining this odd if-then-else construction generates * better code. */ ia64_set_dcr(dcr |IA64_DCR_PP); pfm_set_psr_pp(); ia64_srlz_i(); } - preempt_enable(); } void -pfm_save_regs (struct task_struct *task) +pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +{ + unsigned long start, end; + pfm_stats[smp_processor_id()].pfm_sysupdt_count++; + start = ia64_get_itc(); + pfm_do_syst_wide_update_task(task, info, is_ctxswin); + end = ia64_get_itc(); + pfm_stats[smp_processor_id()].pfm_sysupdt_cycles += end-start; +} + +#ifdef CONFIG_SMP +void +pfm_save_regs(struct task_struct *task) { pfm_context_t *ctx; - unsigned long mask; + struct thread_struct *t; + unsigned long flags; u64 psr; - int i; - preempt_disable(); + ctx = PFM_GET_CTX(task); + if (ctx == NULL) goto save_error; + t = &task->thread; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + + if (CTX_IS_ZOMBIE(ctx)) { + struct pt_regs *regs = ia64_task_regs(task); + + pfm_clear_psr_up(); + + DPRINT(("ctx zombie, forcing cleanup for [%d]\n", task->pid)); + + pfm_force_cleanup(ctx, regs); + + BUG_ON(ctx->ctx_smpl_hdr); - ctx = task->thread.pfm_context; + pfm_unprotect_ctx_ctxsw(ctx, flags); + pfm_context_free(ctx); + return; + } + + /* + * sanity check + */ + if (ctx->ctx_last_activation != GET_ACTIVATION()) { + DPRINT(("ctx_activation=%lu activation=%lu state=%d: no save\n", + ctx->ctx_last_activation, + GET_ACTIVATION(), ctx->ctx_state)); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + return; + } /* * save current PSR: needed because we modify it @@ -3334,1018 +5688,623 @@ /* * stop monitoring: - * This is the last instruction which can generate an overflow + * This is the last instruction which may generate an overflow * * We do not need to set psr.sp because, it is irrelevant in kernel. * It will be restored from ipsr when going back to user level */ pfm_clear_psr_up(); - ia64_srlz_i(); + /* + * keep a copy of the saved psr (for reload) + */ ctx->ctx_saved_psr = psr; -#ifdef CONFIG_SMP /* - * We do not use a lazy scheme in SMP because - * of the new scheduler which masks interrupts - * during low-level context switch. So we save - * all the PMD register we use and restore on - * ctxsw in. - * * release ownership of this PMU. - * must be done before we save the registers. + * PM interrupts are masked, so nothing + * can happen. */ - SET_PMU_OWNER(NULL); + SET_PMU_OWNER(NULL, NULL); /* - * save PMDs - */ - ia64_srlz_d(); - - mask = ctx->ctx_used_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) task->thread.pmd[i] =ia64_get_pmd(i); - } - - /* - * save pmc0 + * we systematically save the PMD as we have no + * guarantee we will be schedule at that same + * CPU again. */ - task->thread.pmc[0] = ia64_get_pmc(0); + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); - /* - * force a full reload + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * we will need it on the restore path to check + * for pending overflow. */ - atomic_set(&ctx->ctx_last_cpu, -1); -#endif - preempt_enable(); -} - -static void -pfm_lazy_save_regs (struct task_struct *task) -{ - pfm_context_t *ctx; - struct thread_struct *t; - unsigned long mask; - int i; - - preempt_disable(); - DBprintk(("on [%d] by [%d]\n", task->pid, current->pid)); - - t = &task->thread; - ctx = task->thread.pfm_context; + t->pmcs[0] = ia64_get_pmc(0); /* - * do not own the PMU + * unfreeze PMU if had pending overflows */ - SET_PMU_OWNER(NULL); - - ia64_srlz_d(); + if (t->pmcs[0] & ~1UL) pfm_unfreeze_pmu(); /* - * XXX needs further optimization. - * Also must take holes into account + * finally, unmask interrupts and allow context + * access. + * Any pended overflow interrupt may be delivered + * here and will be treated as spurious because we + * have have no PMU owner anymore. */ - mask = ctx->ctx_used_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) t->pmd[i] =ia64_get_pmd(i); - } + pfm_unprotect_ctx_ctxsw(ctx, flags); - /* save pmc0 */ - t->pmc[0] = ia64_get_pmc(0); + return; - /* not owned by this CPU */ - atomic_set(&ctx->ctx_last_cpu, -1); - preempt_enable(); +save_error: + printk(KERN_ERR "perfmon: pfm_save_regs CPU%d [%d] NULL context PM_VALID=%ld\n", + smp_processor_id(), task->pid, + task->thread.flags & IA64_THREAD_PM_VALID); } +#else /* !CONFIG_SMP */ + +/* + * in 2.5, interrupts are masked when we come here + */ void -pfm_load_regs (struct task_struct *task) +pfm_save_regs(struct task_struct *task) { - struct thread_struct *t; pfm_context_t *ctx; - struct task_struct *owner; - unsigned long mask; u64 psr; - int i; - - preempt_disable(); - - owner = PMU_OWNER(); - ctx = task->thread.pfm_context; - t = &task->thread; - - if (ctx == NULL) { - preempt_enable(); - printk("perfmon: pfm_load_regs: null ctx for [%d]\n", task->pid); - return; - } - /* - * we restore ALL the debug registers to avoid picking up - * stale state. - * - * This must be done even when the task is still the owner - * as the registers may have been modified via ptrace() - * (not perfmon) by the previous task. - * - * XXX: dealing with this in a lazy fashion requires modifications - * to the way the the debug registers are managed. This is will done - * in the next version of perfmon. - */ - if (ctx->ctx_fl_using_dbreg) { - for (i=0; i < (int) pmu_conf.num_ibrs; i++) { - ia64_set_ibr(i, t->ibr[i]); - } - ia64_srlz_i(); - for (i=0; i < (int) pmu_conf.num_dbrs; i++) { - ia64_set_dbr(i, t->dbr[i]); - } - ia64_srlz_d(); - } + ctx = PFM_GET_CTX(task); + if (ctx == NULL) goto save_error; /* - * if we were the last user, then nothing to do except restore psr - * this path cannot be used in SMP + * save current PSR: needed because we modify it */ - if (owner == task) { - if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) - DBprintk(("invalid last_cpu=%d for [%d]\n", - atomic_read(&ctx->ctx_last_cpu), task->pid)); - - psr = ctx->ctx_saved_psr; - pfm_set_psr_l(psr); - preempt_enable(); - return; - } + psr = pfm_get_psr(); /* - * someone else is still using the PMU, first push it out and - * then we'll be able to install our stuff ! + * stop monitoring: + * This is the last instruction which may generate an overflow * - * not possible in SMP + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level */ - if (owner) pfm_lazy_save_regs(owner); + pfm_clear_psr_up(); /* - * To avoid leaking information to the user level when psr.sp=0, - * we must reload ALL implemented pmds (even the ones we don't use). - * In the kernel we only allow PFM_READ_PMDS on registers which - * we initialized or requested (sampling) so there is no risk there. - * - * As an optimization, we will only reload the PMD that we use when - * the context is in protected mode, i.e. psr.sp=1 because then there - * is no leak possible. + * keep a copy of the saved psr (for reload) */ - mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ? ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val); - } + ctx->ctx_saved_psr = psr; - /* - * PMC0 is never set in the mask because it is always restored - * separately. - * - * ALL PMCs are systematically reloaded, unused registers - * get their default (PAL reset) values to avoid picking up - * stale configuration. - */ - mask = ctx->ctx_reload_pmcs[0]; - for (i=0; mask; i++, mask>>=1) { - if (mask & 0x1) ia64_set_pmc(i, t->pmc[i]); + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_save_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, GET_PMU_OWNER()->pid, psr); } - - /* - * manually invoke core interrupt handler - * if the task had a pending overflow when it was ctxsw out. - * Side effect on ctx_fl_frozen is possible. - */ - if (t->pmc[0] & ~0x1) { - t->pmc[0] = pfm_overflow_handler(1, task, ctx, t->pmc[0], NULL); + if (psr & IA64_PSR_I) { + printk(KERN_ERR " perfmon: pfm_save_regs: psr.i set current [%d] owner [%d] psr=0x%lx\n", current->pid, GET_PMU_OWNER()->pid, psr); } - /* - * unfreeze PMU if possible - */ - if (ctx->ctx_fl_frozen == 0) pfm_unfreeze_pmu(); - - atomic_set(&ctx->ctx_last_cpu, smp_processor_id()); - - SET_PMU_OWNER(task); - - /* - * restore the psr we changed in pfm_save_regs() - */ - psr = ctx->ctx_saved_psr; - preempt_enable(); - pfm_set_psr_l(psr); + return; +save_error: + printk(KERN_ERR "perfmon: pfm_save_regs CPU%d [%d] NULL context PM_VALID=%ld\n", + smp_processor_id(), task->pid, + task->thread.flags & IA64_THREAD_PM_VALID); } -/* - * XXX: make this routine able to work with non current context - */ static void -pfm_reset_pmu(struct task_struct *task) +pfm_lazy_save_regs (struct task_struct *task) { - struct thread_struct *t = &task->thread; - pfm_context_t *ctx = t->pfm_context; - int i; + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + unsigned long psr; - if (task != current) { - printk("perfmon: invalid task in pfm_reset_pmu()\n"); - return; +#if 1 + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_lazy_save_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, task->pid, psr); + pfm_clear_psr_up(); } - preempt_disable(); +#endif - /* Let's make sure the PMU is frozen */ - pfm_freeze_pmu(); + ctx = PFM_GET_CTX(task); + t = &task->thread; - /* - * install reset values for PMC. We skip PMC0 (done above) - * XX: good up to 64 PMCS - */ - for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) { - if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue; - ia64_set_pmc(i, PMC_DFL_VAL(i)); - /* - * When restoring context, we must restore ALL pmcs, even the ones - * that the task does not use to avoid leaks and possibly corruption - * of the sesion because of configuration conflicts. So here, we - * initialize the entire set used in the context switch restore routine. - */ - t->pmc[i] = PMC_DFL_VAL(i); - DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i])); - } + DPRINT(("on [%d] used_pmds=0x%lx\n", task->pid, ctx->ctx_used_pmds[0])); /* - * clear reset values for PMD. - * XXX: good up to 64 PMDS. + * we need to mask PMU overflow here to + * make sure that we maintain pmc0 until + * we save it. overflow interrupts are + * treated as spurious if there is no + * owner. + * + * XXX: I don't think this is necessary */ - for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) { - if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue; - ia64_set_pmd(i, 0UL); - t->pmd[i] = 0UL; - } + PROTECT_CTX(ctx,flags); /* - * On context switched restore, we must restore ALL pmc and ALL pmd even - * when they are not actively used by the task. In UP, the incoming process - * may otherwise pick up left over PMC, PMD state from the previous process. - * As opposed to PMD, stale PMC can cause harm to the incoming - * process because they may change what is being measured. - * Therefore, we must systematically reinstall the entire - * PMC state. In SMP, the same thing is possible on the - * same CPU but also on between 2 CPUs. - * - * The problem with PMD is information leaking especially - * to user level when psr.sp=0 + * release ownership of this PMU. + * must be done before we save the registers. * - * There is unfortunately no easy way to avoid this problem - * on either UP or SMP. This definitively slows down the - * pfm_load_regs() function. + * after this call any PMU interrupt is treated + * as spurious. */ - - /* - * We must include all the PMC in this mask to make sure we don't - * see any side effect of a stale state, such as opcode matching - * or range restrictions, for instance. - * - * We never directly restore PMC0 so we do not include it in the mask. - */ - ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1; + SET_PMU_OWNER(NULL, NULL); + /* - * We must include all the PMD in this mask to avoid picking - * up stale value and leak information, especially directly - * at the user level when psr.sp=0 + * save all the pmds we use */ - ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0]; + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); - /* - * Keep track of the pmds we want to sample - * XXX: may be we don't need to save/restore the DEAR/IEAR pmds - * but we do need the BTB for sure. This is because of a hardware - * buffer of 1 only for non-BTB pmds. - * - * We ignore the unimplemented pmds specified by the user + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * it is needed to check for pended overflow + * on the restore path */ - ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0]; - ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */ + t->pmcs[0] = ia64_get_pmc(0); /* - * useful in case of re-enable after disable + * unfreeze PMU if had pending overflows */ - ctx->ctx_used_ibrs[0] = 0UL; - ctx->ctx_used_dbrs[0] = 0UL; + if (t->pmcs[0] & ~1UL) pfm_unfreeze_pmu(); - ia64_srlz_d(); - preempt_enable(); + /* + * now get can unmask PMU interrupts, they will + * be treated as purely spurious and we will not + * lose any information + */ + UNPROTECT_CTX(ctx,flags); } +#endif /* CONFIG_SMP */ -/* - * This function is called when a thread exits (from exit_thread()). - * This is a simplified pfm_save_regs() that simply flushes the current - * register state into the save area taking into account any pending - * overflow. This time no notification is sent because the task is dying - * anyway. The inline processing of overflows avoids loosing some counts. - * The PMU is frozen on exit from this call and is to never be reenabled - * again for this task. - * - */ +#ifdef CONFIG_SMP void -pfm_flush_regs (struct task_struct *task) +pfm_load_regs (struct task_struct *task) { pfm_context_t *ctx; - u64 pmc0; - unsigned long mask2, val; - int i; + struct thread_struct *t; + struct task_struct *owner; + unsigned long pmc_mask = 0UL, pmd_mask = 0UL; + unsigned long flags; + u64 psr; - ctx = task->thread.pfm_context; + ctx = PFM_GET_CTX(task); + if (unlikely(ctx == NULL)) { + printk(KERN_ERR "perfmon: pfm_load_regs() null context\n"); + return; + } - if (ctx == NULL) return; + owner = GET_PMU_OWNER(); + t = &task->thread; + +#if 1 + psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_UP); + psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_I); +#endif - /* - * that's it if context already disabled - */ - if (ctx->ctx_flags.state == PFM_CTX_DISABLED) return; - preempt_disable(); /* - * stop monitoring: - * This is the only way to stop monitoring without destroying overflow - * information in PMC[0]. - * This is the last instruction which can cause overflow when monitoring - * in kernel. - * By now, we could still have an overflow interrupt in-flight. + * possible on unload */ - if (ctx->ctx_fl_system) { + if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) { + DPRINT(("[%d] PM_VALID=0, nothing to do\n", task->pid)); + return; + } + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); - /* disable dcr pp */ - ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP); + if (unlikely(CTX_IS_ZOMBIE(ctx))) { + struct pt_regs *regs = ia64_task_regs(task); - /* stop monitoring */ - pfm_clear_psr_pp(); + BUG_ON(ctx->ctx_smpl_hdr); - ia64_srlz_i(); + DPRINT(("ctx zombie, forcing cleanup for [%d]\n", task->pid)); - PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); - PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); - PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); - } else { + pfm_force_cleanup(ctx, regs); - /* stop monitoring */ - pfm_clear_psr_up(); + pfm_unprotect_ctx_ctxsw(ctx, flags); - ia64_srlz_i(); + /* + * this one (kmalloc'ed) is fine with interrupts disabled + */ + pfm_context_free(ctx); - /* no more save/restore on ctxsw */ - current->thread.flags &= ~IA64_THREAD_PM_VALID; + return; } /* - * Mark the PMU as not owned - * This will cause the interrupt handler to do nothing in case an overflow - * interrupt was in-flight - * This also guarantees that pmc0 will contain the final state - * It virtually gives us full control on overflow processing from that point - * on. - * It must be an atomic operation. + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } + /* + * retrieve saved psr */ - SET_PMU_OWNER(NULL); + psr = ctx->ctx_saved_psr; /* - * read current overflow status: - * - * we are guaranteed to read the final stable state + * if we were the last user of the PMU on that CPU, + * then nothing to do except restore psr */ - ia64_srlz_d(); - pmc0 = ia64_get_pmc(0); /* slow */ + if (GET_LAST_CPU(ctx) == smp_processor_id() && ctx->ctx_last_activation == GET_ACTIVATION()) { + /* + * retrieve partial reload masks (due to user modifications) + */ + pmc_mask = ctx->ctx_reload_pmcs[0]; + pmd_mask = ctx->ctx_reload_pmds[0]; + + if (pmc_mask || pmd_mask) DPRINT(("partial reload [%d] pmd_mask=0x%lx pmc_mask=0x%lx\n", task->pid, pmd_mask, pmc_mask)); + } else { + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately. + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + + DPRINT(("full reload for [%d] owner=%d activation=%lu last_activation=%lu last_cpu=%d pmd_mask=0x%lx pmc_mask=0x%lx\n", + task->pid, owner ? owner->pid : -1, + GET_ACTIVATION(), ctx->ctx_last_activation, + GET_LAST_CPU(ctx), pmd_mask, pmc_mask)); + + } /* - * freeze PMU: + * when context is MASKED, we will restore PMC with plm=0 + * and PMD with stale information, but that's ok, nothing + * will be captured. * - * This destroys the overflow information. This is required to make sure - * next process does not start with monitoring on if not requested + * XXX: optimize here */ - pfm_freeze_pmu(); + if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask); + if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask); /* - * We don't need to restore psr, because we are on our way out + * check for pending overflow at the time the state + * was saved. */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + struct pt_regs *regs = ia64_task_regs(task); + pfm_overflow_handler(task, ctx, t->pmcs[0], regs); + } /* - * This loop flushes the PMD into the PFM context. - * It also processes overflow inline. - * - * IMPORTANT: No notification is sent at this point as the process is dying. - * The implicit notification will come from a SIGCHILD or a return from a - * waitpid(). - * + * we clear PMC0, to ensure that any in flight interrupt + * will not be attributed to the new context we are installing + * because the actual overflow has been processed above already. + * No real effect until we unmask interrupts at the end of the + * function. */ - - if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id()) - printk(KERN_DEBUG "perfmon: [%d] last_cpu=%d\n", - task->pid, atomic_read(&ctx->ctx_last_cpu)); + pfm_unfreeze_pmu(); /* - * we save all the used pmds - * we take care of overflows for pmds used as counters + * we just did a reload, so we reset the partial reload fields */ - mask2 = ctx->ctx_used_pmds[0]; - for (i = 0; mask2; i++, mask2>>=1) { + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; - /* skip non used pmds */ - if ((mask2 & 0x1) == 0) continue; - - val = ia64_get_pmd(i); + SET_LAST_CPU(ctx, smp_processor_id()); - if (PMD_IS_COUNTING(i)) { - DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", - task->pid, - i, - ctx->ctx_soft_pmds[i].val, - val & pmu_conf.ovfl_val)); + /* + * dump activation value for this PMU + */ + INC_ACTIVATION(); + /* + * record current activation for this context + */ + SET_ACTIVATION(ctx); - /* collect latest results */ - ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val; + /* + * establish new ownership. Interrupts + * are still masked at this point. + */ + SET_PMU_OWNER(task, ctx); - /* - * now everything is in ctx_soft_pmds[] and we need - * to clear the saved context from save_regs() such that - * pfm_read_pmds() gets the correct value - */ - task->thread.pmd[i] = 0; + /* + * restore the psr we changed + */ + pfm_set_psr_l(psr); - /* - * take care of overflow inline - */ - if (pmc0 & (1UL << i)) { - ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val; - DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n", - task->pid, i, ctx->ctx_soft_pmds[i].val)); - } - } else { - DBprintk(("[%d] pmd[%d] hw_pmd=0x%lx\n", task->pid, i, val)); - /* - * not a counter, just save value as is - */ - task->thread.pmd[i] = val; - } - } - /* - * indicates that context has been saved + /* + * allow concurrent access to context */ - atomic_set(&ctx->ctx_last_cpu, -1); - preempt_enable(); + pfm_unprotect_ctx_ctxsw(ctx, flags); } - - +#else /* !CONFIG_SMP */ /* - * task is the newly created task, pt_regs for new child + * reload PMU state for UP kernels + * in 2.5 we come here with interrupts disabled */ -int -pfm_inherit(struct task_struct *task, struct pt_regs *regs) +void +pfm_load_regs (struct task_struct *task) { + struct thread_struct *t; pfm_context_t *ctx; - pfm_context_t *nctx; - struct thread_struct *thread; - unsigned long m; - int i; + struct task_struct *owner; + unsigned long pmd_mask, pmc_mask; + u64 psr; - /* - * the new task was copied from parent and therefore points - * to the parent's context at this point - */ - ctx = task->thread.pfm_context; - thread = &task->thread; + owner = GET_PMU_OWNER(); + ctx = PFM_GET_CTX(task); + t = &task->thread; - preempt_disable(); - /* - * for secure sessions, make sure child cannot mess up - * the monitoring session. - */ - if (ctx->ctx_fl_unsecure == 0) { - ia64_psr(regs)->sp = 1; - DBprintk(("enabling psr.sp for [%d]\n", task->pid)); - } else { - DBprintk(("psr.sp=%d [%d]\n", ia64_psr(regs)->sp, task->pid)); +#if 1 + psr = pfm_get_psr(); + if (psr & IA64_PSR_UP) { + printk(KERN_ERR " perfmon: pfm_load_regs: psr.up set current [%d] owner [%d] psr=0x%lx\n", current->pid, owner->pid, psr); } + psr = pfm_get_psr(); + if (psr & IA64_PSR_I) { + printk(KERN_ERR " perfmon: pfm_load_regs: psr.i set current [%d] owner [%d] psr=0x%lx\n", current->pid, owner->pid, psr); + } +#endif /* - * if there was a virtual mapping for the sampling buffer - * the mapping is NOT inherited across fork() (see VM_DONTCOPY), - * so we don't have to explicitly remove it here. - * + * we restore ALL the debug registers to avoid picking up + * stale state. * - * Part of the clearing of fields is also done in - * copy_thread() because the fiels are outside the - * pfm_context structure and can affect tasks not - * using perfmon. + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. */ - - /* clear pending notification */ - task->thread.pfm_ovfl_block_reset = 0; + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf.num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf.num_dbrs); + } /* - * clear cpu pinning restriction for child + * retrieved save psr */ - if (ctx->ctx_fl_system) { - set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); - - DBprintk(("setting cpus_allowed for [%d] to 0x%lx from 0x%lx\n", - task->pid, - ctx->ctx_saved_cpus_allowed, - current->cpus_allowed)); - } + psr = ctx->ctx_saved_psr; /* - * takes care of easiest case first + * short path, our state is still there, just + * need to restore psr and we go + * + * we do not touch either PMC nor PMD. the psr is not touched + * by the overflow_handler. So we are safe w.r.t. to interrupt + * concurrency even without interrupt masking. */ - if (CTX_INHERIT_MODE(ctx) == PFM_FL_INHERIT_NONE) { - - DBprintk(("removing PFM context for [%d]\n", task->pid)); - - task->thread.pfm_context = NULL; - - /* - * we must clear psr.up because the new child does - * not have a context and the PM_VALID flag is cleared - * in copy_thread(). - * - * we do not clear psr.pp because it is always - * controlled by the system wide logic and we should - * never be here when system wide is running anyway - */ - ia64_psr(regs)->up = 0; - - preempt_enable(); - - /* copy_thread() clears IA64_THREAD_PM_VALID */ - return 0; + if (likely(owner == task)) { + pfm_set_psr_l(psr); + return; } - nctx = pfm_context_alloc(); - if (nctx == NULL) return -ENOMEM; - - /* copy content */ - *nctx = *ctx; + DPRINT(("reload for [%d] owner=%d\n", task->pid, owner ? owner->pid : -1)); - 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)); - } /* - * task is not yet visible in the tasklist, so we do - * not need to lock the newly created context. - * However, we must grab the tasklist_lock to ensure - * that the ctx_owner or ctx_notify_task do not disappear - * while we increment their check counters. + * someone else is still using the PMU, first push it out and + * then we'll be able to install our stuff ! + * + * Upon return, there will be no owner for the current PMU */ - read_lock(&tasklist_lock); - - if (nctx->ctx_notify_task) - atomic_inc(&nctx->ctx_notify_task->thread.pfm_notifiers_check); - - if (nctx->ctx_owner) - atomic_inc(&nctx->ctx_owner->thread.pfm_owners_check); - - read_unlock(&tasklist_lock); - - - LOCK_PFS(); - pfm_sessions.pfs_task_sessions++; - UNLOCK_PFS(); - - /* initialize counters in new context */ - m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER; - for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) { - if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) { - nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val; - thread->pmd[i] = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val; - } else { - thread->pmd[i] = 0UL; /* reset to initial state */ - } - } + if (owner) pfm_lazy_save_regs(owner); - nctx->ctx_fl_frozen = 0; - nctx->ctx_ovfl_regs[0] = 0UL; - nctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; - atomic_set(&nctx->ctx_last_cpu, -1); + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; /* - * here nctx->ctx_psb == ctx->ctx_psb + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. * - * increment reference count to sampling - * buffer, if any. Note that this is independent - * from the virtual mapping. The latter is never - * inherited while the former will be if context - * is setup to something different from PFM_FL_INHERIT_NONE + * PMC0 is never in the mask. It is always restored separately */ - if (nctx->ctx_psb) { - LOCK_PSB(nctx->ctx_psb); + pmc_mask = ctx->ctx_all_pmcs[0]; - nctx->ctx_psb->psb_refcnt++; + pfm_restore_pmds(t->pmds, pmd_mask); + pfm_restore_pmcs(t->pmcs, pmc_mask); - DBprintk(("updated smpl @ %p refcnt=%lu psb_flags=0x%x\n", - ctx->ctx_psb->psb_hdr, - ctx->ctx_psb->psb_refcnt, - ctx->ctx_psb->psb_flags)); - - UNLOCK_PSB(nctx->ctx_psb); - - /* - * remove any pointer to sampling buffer mapping - */ - nctx->ctx_smpl_vaddr = 0; + /* + * Check for pending overflow when state was last saved. + * invoked handler is overflow status bits set. + * + * Any PMU overflow in flight at this point, will still + * be treated as spurious because we have no declared + * owner. Note that the first level interrupt handler + * DOES NOT TOUCH any PMC except PMC0 for which we have + * a copy already. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + struct pt_regs *regs = ia64_task_regs(task); + pfm_overflow_handler(task, ctx, t->pmcs[0], regs); } - sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */ - /* - * propagate kernel psr in new context (used for first ctxsw in + * we clear PMC0, to ensure that any in flight interrupt + * will not be attributed to the new context we are installing + * because the actual overflow has been processed above already. + * + * This is an atomic operation. */ - nctx->ctx_saved_psr = pfm_get_psr(); + pfm_unfreeze_pmu(); /* - * propagate kernel psr in new context (used for first ctxsw in + * establish new ownership. If there was an in-flight + * overflow interrupt, it will be treated as spurious + * before and after the call, because no overflow + * status bit can possibly be set. No new overflow + * can be generated because, at this point, psr.up + * is still cleared. */ - nctx->ctx_saved_psr = pfm_get_psr(); - - /* link with new task */ - thread->pfm_context = nctx; - - DBprintk(("nctx=%p for process [%d]\n", (void *)nctx, task->pid)); + SET_PMU_OWNER(task, ctx); /* - * the copy_thread routine automatically clears - * IA64_THREAD_PM_VALID, so we need to reenable it, if it was used by the caller + * restore the psr. This is the point at which + * new overflow interrupts can be generated again. */ - if (current->thread.flags & IA64_THREAD_PM_VALID) { - DBprintk(("setting PM_VALID for [%d]\n", task->pid)); - thread->flags |= IA64_THREAD_PM_VALID; - } - - preempt_enable(); + pfm_set_psr_l(psr); - return 0; } +#endif /* CONFIG_SMP */ -/* - * - * We cannot touch any of the PMU registers at this point as we may - * not be running on the same CPU the task was last run on. Therefore - * it is assumed that the PMU has been stopped appropriately in - * pfm_flush_regs() called from exit_thread(). - * - * The function is called in the context of the parent via a release_thread() - * and wait4(). The task is not in the tasklist anymore. +/* + * this function assumes monitoring is stopped */ -void -pfm_context_exit(struct task_struct *task) +static void +pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) { - pfm_context_t *ctx = task->thread.pfm_context; + u64 pmc0; + unsigned long mask2, val, pmd_val; + int i, can_access_pmu = 0; + int is_self; /* - * check sampling buffer + * is the caller the task being monitored (or which initiated the + * session for system wide measurements) */ - preempt_disable(); - if (ctx->ctx_psb) { - pfm_smpl_buffer_desc_t *psb = ctx->ctx_psb; - - LOCK_PSB(psb); - - DBprintk(("sampling buffer from [%d] @%p size %ld refcnt=%lu psb_flags=0x%x\n", - task->pid, - psb->psb_hdr, psb->psb_size, psb->psb_refcnt, psb->psb_flags)); + is_self = ctx->ctx_task == task ? 1 : 0; +#ifdef CONFIG_SMP + if (task == current) { +#else + /* + * in UP, the state can still be in the registers + */ + if (task == current || GET_PMU_OWNER() == task) { +#endif + can_access_pmu = 1; /* - * in the case where we are the last user, we may be able to free - * the buffer + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. */ - psb->psb_refcnt--; - - if (psb->psb_refcnt == 0) { - - /* - * The flag is cleared in pfm_vm_close(). which gets - * called from do_exit() via exit_mm(). - * By the time we come here, the task has no more mm context. - * - * We can only free the psb and buffer here after the vm area - * describing the buffer has been removed. This normally happens - * as part of do_exit() but the entire mm context is ONLY removed - * once its reference counts goes to zero. This is typically - * the case except for multi-threaded (several tasks) processes. - * - * See pfm_vm_close() and pfm_cleanup_smpl_buf() for more details. - */ - if ((psb->psb_flags & PSB_HAS_VMA) == 0) { - - DBprintk(("cleaning sampling buffer from [%d] @%p size %ld\n", - task->pid, - psb->psb_hdr, psb->psb_size)); - - /* - * free the buffer and psb - */ - pfm_rvfree(psb->psb_hdr, psb->psb_size); - kfree(psb); - psb = NULL; - } - } - /* psb may have been deleted */ - if (psb) UNLOCK_PSB(psb); - } - - DBprintk(("cleaning [%d] pfm_context @%p notify_task=%p check=%d mm=%p\n", - task->pid, ctx, - ctx->ctx_notify_task, - atomic_read(&task->thread.pfm_notifiers_check), task->mm)); - - /* - * To avoid getting the notified task or owner task scan the entire process - * list when they exit, we decrement notifiers_check and owners_check respectively. - * - * Of course, there is race condition between decreasing the value and the - * task exiting. The danger comes from the fact that, in both cases, we have a - * direct pointer to a task structure thereby bypassing the tasklist. - * We must make sure that, if we have task!= NULL, the target task is still - * present and is identical to the initial task specified - * during pfm_context_create(). It may already be detached from the tasklist but - * that's okay. Note that it is okay if we miss the deadline and the task scans - * the list for nothing, it will affect performance but not correctness. - * The correctness is ensured by using the ctx_lock which prevents the - * notify_task from changing the fields in our context. - * Once holdhing this lock, if we see task!= NULL, then it will stay like - * that until we release the lock. If it is NULL already then we came too late. - */ - LOCK_CTX(ctx); - - if (ctx->ctx_notify_task != NULL) { - DBprintk(("[%d], [%d] atomic_sub on [%d] notifiers=%u\n", current->pid, - task->pid, - ctx->ctx_notify_task->pid, - atomic_read(&ctx->ctx_notify_task->thread.pfm_notifiers_check))); - - atomic_dec(&ctx->ctx_notify_task->thread.pfm_notifiers_check); - } - - if (ctx->ctx_owner != NULL) { - DBprintk(("[%d], [%d] atomic_sub on [%d] owners=%u\n", - current->pid, - task->pid, - ctx->ctx_owner->pid, - atomic_read(&ctx->ctx_owner->thread.pfm_owners_check))); - - atomic_dec(&ctx->ctx_owner->thread.pfm_owners_check); - } - - UNLOCK_CTX(ctx); - preempt_enable(); + SET_PMU_OWNER(NULL, NULL); - pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu); - - if (ctx->ctx_fl_system) { /* - * remove any CPU pinning - */ - set_cpus_allowed(task, ctx->ctx_saved_cpus_allowed); - } - - pfm_context_free(ctx); - /* - * clean pfm state in thread structure, - */ - task->thread.pfm_context = NULL; - task->thread.pfm_ovfl_block_reset = 0; - - /* pfm_notifiers is cleaned in pfm_cleanup_notifiers() */ -} - -/* - * function invoked from release_thread when pfm_smpl_buf_list is not NULL - */ -int -pfm_cleanup_smpl_buf(struct task_struct *task) -{ - pfm_smpl_buffer_desc_t *tmp, *psb = task->thread.pfm_smpl_buf_list; + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ - if (psb == NULL) { - printk(KERN_DEBUG "perfmon: psb is null in [%d]\n", current->pid); - return -1; + /* + * reset freeze bit, overflow status information destroyed + */ + pfm_unfreeze_pmu(); + } else { + pmc0 = task->thread.pmcs[0]; + /* + * clear whatever overflow status bits there were + */ + task->thread.pmcs[0] &= ~0x1; } + /* - * Walk through the list and free the sampling buffer and psb + * we save all the used pmds + * we take care of overflows for counting PMDs + * + * XXX: sampling situation is not taken into account here */ - while (psb) { - DBprintk(("[%d] freeing smpl @%p size %ld\n", current->pid, psb->psb_hdr, psb->psb_size)); - - pfm_rvfree(psb->psb_hdr, psb->psb_size); - tmp = psb->psb_next; - kfree(psb); - psb = tmp; - } - - /* just in case */ - task->thread.pfm_smpl_buf_list = NULL; - - return 0; -} - -/* - * function invoked from release_thread to make sure that the ctx_owner field does not - * point to an unexisting task. - */ -void -pfm_cleanup_owners(struct task_struct *task) -{ - struct task_struct *g, *p; - pfm_context_t *ctx; - - DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); + mask2 = ctx->ctx_used_pmds[0]; + for (i = 0; mask2; i++, mask2>>=1) { - read_lock(&tasklist_lock); + /* skip non used pmds */ + if ((mask2 & 0x1) == 0) continue; - do_each_thread(g, p) { /* - * It is safe to do the 2-step test here, because thread.ctx - * is cleaned up only in release_thread() and at that point - * the task has been detached from the tasklist which is an - * operation which uses the write_lock() on the tasklist_lock - * so it cannot run concurrently to this loop. So we have the - * guarantee that if we find p and it has a perfmon ctx then - * it is going to stay like this for the entire execution of this - * loop. + * can access PMU always true in system wide mode */ - ctx = p->thread.pfm_context; + val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i]; - //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); + if (PMD_IS_COUNTING(i)) { + DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n", + task->pid, + i, + ctx->ctx_pmds[i].val, + val & pmu_conf.ovfl_val)); - if (ctx && ctx->ctx_owner == task) { - DBprintk(("trying for owner [%d] in [%d]\n", task->pid, p->pid)); /* - * the spinlock is required to take care of a race condition - * with the send_sig_info() call. We must make sure that - * either the send_sig_info() completes using a valid task, - * or the notify_task is cleared before the send_sig_info() - * can pick up a stale value. Note that by the time this - * function is executed the 'task' is already detached from the - * tasklist. The problem is that the notifiers have a direct - * pointer to it. It is okay to send a signal to a task in this - * stage, it simply will have no effect. But it is better than sending - * to a completely destroyed task or worse to a new task using the same - * task_struct address. + * we rebuild the full 64 bit value of the counter */ - LOCK_CTX(ctx); - - ctx->ctx_owner = NULL; - - UNLOCK_CTX(ctx); - - DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); - } - } while_each_thread(g, p); - - read_unlock(&tasklist_lock); - - atomic_set(&task->thread.pfm_owners_check, 0); -} - - -/* - * function called from release_thread to make sure that the ctx_notify_task is not pointing - * to an unexisting task - */ -void -pfm_cleanup_notifiers(struct task_struct *task) -{ - struct task_struct *g, *p; - pfm_context_t *ctx; - - DBprintk(("called by [%d] for [%d]\n", current->pid, task->pid)); - - read_lock(&tasklist_lock); + val = ctx->ctx_pmds[i].val + (val & pmu_conf.ovfl_val); - do_each_thread(g, p) { - /* - * It is safe to do the 2-step test here, because thread.ctx is cleaned up - * only in release_thread() and at that point the task has been detached - * from the tasklist which is an operation which uses the write_lock() on - * the tasklist_lock so it cannot run concurrently to this loop. So we - * have the guarantee that if we find p and it has a perfmon ctx then it - * is going to stay like this for the entire execution of this loop. - */ - ctx = p->thread.pfm_context; - - //DBprintk(("[%d] scanning task [%d] ctx=%p\n", task->pid, p->pid, ctx)); - - if (ctx && ctx->ctx_notify_task == task) { - DBprintk(("trying for notifier [%d] in [%d]\n", task->pid, p->pid)); /* - * the spinlock is required to take care of a race condition - * with the send_sig_info() call. We must make sure that - * either the send_sig_info() completes using a valid task, - * or the notify_task is cleared before the send_sig_info() - * can pick up a stale value. Note that by the time this - * function is executed the 'task' is already detached from the - * tasklist. The problem is that the notifiers have a direct - * pointer to it. It is okay to send a signal to a task in this - * stage, it simply will have no effect. But it is better than sending - * to a completely destroyed task or worse to a new task using the same - * task_struct address. + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value */ - LOCK_CTX(ctx); - - ctx->ctx_notify_task = NULL; - - UNLOCK_CTX(ctx); + pmd_val = 0UL; - DBprintk(("done for notifier [%d] in [%d]\n", task->pid, p->pid)); + /* + * take care of overflow inline + */ + if (pmc0 & (1UL << i)) { + val += 1 + pmu_conf.ovfl_val; + DPRINT(("[%d] pmd[%d] overflowed\n", task->pid, i)); + } } - } while_each_thread(g, p); - read_unlock(&tasklist_lock); + DPRINT(("[%d] is_self=%d ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, is_self, i, val, pmd_val)); - atomic_set(&task->thread.pfm_notifiers_check, 0); + if (is_self) task->thread.pmds[i] = pmd_val; + ctx->ctx_pmds[i].val = val; + } } static struct irqaction perfmon_irqaction = { - .handler = pfm_interrupt_handler, - .flags = SA_INTERRUPT, - .name = "perfmon" + .handler = pfm_interrupt_handler, + .flags = SA_INTERRUPT, + .name = "perfmon" }; -int -pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl) -{ - int ret; - - - /* some sanity checks */ - if (hdl == NULL || hdl->handler == NULL) { - return -EINVAL; - } - - /* do the easy test first */ - if (pfm_alternate_intr_handler) { - return -EBUSY; - } - - preempt_disable(); - /* reserve our session */ - ret = pfm_reserve_session(NULL, 1, cpu_online_map); - if (ret) { - preempt_enable(); - return ret; - } - - if (pfm_alternate_intr_handler) { - preempt_enable(); - printk(KERN_DEBUG "perfmon: install_alternate, intr_handler not NULL " - "after reserve\n"); - return -EINVAL; - } - - pfm_alternate_intr_handler = hdl; - - preempt_enable(); - return 0; -} - -int -pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl) -{ - if (hdl == NULL) - return -EINVAL; - - /* cannot remove someone else's handler! */ - if (pfm_alternate_intr_handler != hdl) - return -EINVAL; - - preempt_disable(); - pfm_alternate_intr_handler = NULL; - - /* - * XXX: assume cpu_online_map has not changed since reservation - */ - pfm_unreserve_session(NULL, 1, cpu_online_map); - - preempt_enable(); - - return 0; -} - /* * perfmon initialization routine, called from the initcall() table */ +static int init_pfm_fs(void); + int __init pfm_init(void) { unsigned int n, n_counters, i; - pmu_conf.disabled = 1; + printk("perfmon: version %u.%u IRQ %u\n", + PFM_VERSION_MAJ, + PFM_VERSION_MIN, + IA64_PERFMON_VECTOR); - printk(KERN_INFO "perfmon: version %u.%u IRQ %u\n", PFM_VERSION_MAJ, PFM_VERSION_MIN, - IA64_PERFMON_VECTOR); + /* + * PMU type sanity check + * XXX: maybe better to implement autodetection (but then we have a larger kernel) + */ + if (local_cpu_data->family != pmu_conf.pmu_family) { + printk(KERN_INFO "perfmon: disabled, kernel only supports %s PMU family\n", pmu_conf.pmu_name); + return -ENODEV; + } /* * compute the number of implemented PMD/PMC from the @@ -4369,7 +6328,22 @@ pmu_conf.num_pmds = n; pmu_conf.num_counters = n_counters; - printk(KERN_INFO "perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", + /* + * sanity checks on the number of debug registers + */ + if (pmu_conf.use_rr_dbregs) { + if (pmu_conf.num_ibrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of code debug registers (%u)\n", pmu_conf.num_ibrs); + return -1; + } + if (pmu_conf.num_dbrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of data debug registers (%u)\n", pmu_conf.num_ibrs); + return -1; + } + } + + printk("perfmon: %s PMU detected, %u PMCs, %u PMDs, %u counters (%lu bits)\n", + pmu_conf.pmu_name, pmu_conf.num_pmcs, pmu_conf.num_pmds, pmu_conf.num_counters, @@ -4382,7 +6356,7 @@ } /* - * for now here for debug purposes + * create /proc/perfmon (mostly for debugging purposes) */ perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); if (perfmon_dir == NULL) { @@ -4391,7 +6365,7 @@ } /* - * create /proc/perfmon + * create /proc/sys/kernel/perfmon (for debugging purposes) */ pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); @@ -4399,21 +6373,34 @@ * initialize all our spinlocks */ spin_lock_init(&pfm_sessions.pfs_lock); + spin_lock_init(&pfm_smpl_fmt_lock); + + init_pfm_fs(); + + for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL; /* we are all set */ - pmu_conf.disabled = 0; + pmu_conf.enabled = 1; return 0; } + __initcall(pfm_init); void -pfm_init_percpu(void) +pfm_init_percpu (void) { int i; - int me = get_cpu(); - if (me == 0) + /* + * make sure no measurement is active + * (may inherit programmed PMCs from EFI). + */ + pfm_clear_psr_pp(); + pfm_clear_psr_up(); + + + if (smp_processor_id() == 0) register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); ia64_set_pmv(IA64_PERFMON_VECTOR); @@ -4426,28 +6413,102 @@ * * At this point, pmu_conf has not yet been initialized * - * On McKinley, this code is ineffective until PMC4 is initialized. + * On McKinley, this code is ineffective until PMC4 is initialized + * but that's all right because we take care of pmc0 later. + * + * XXX: potential problems with pmc1. */ for (i=1; PMC_IS_LAST(i) == 0; i++) { if (PMC_IS_IMPL(i) == 0) continue; ia64_set_pmc(i, PMC_DFL_VAL(i)); } - for (i=0; PMD_IS_LAST(i); i++) { + for (i=0; PMD_IS_LAST(i) == 0; i++) { if (PMD_IS_IMPL(i) == 0) continue; ia64_set_pmd(i, 0UL); } - put_cpu(); - pfm_freeze_pmu(); + + /* + * we run with the PMU not frozen at all times + */ + pfm_unfreeze_pmu(); +} + +/* + * used for debug purposes only + */ +void +dump_pmu_state(void) +{ + struct task_struct *task; + struct thread_struct *t; + pfm_context_t *ctx; + unsigned long psr; + int i; + + printk("current [%d] %s\n", current->pid, current->comm); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + printk("owner [%d] ctx=%p\n", task ? task->pid : -1, ctx); + + psr = pfm_get_psr(); + + printk("psr.pp=%ld psr.up=%ld\n", (psr >> IA64_PSR_PP_BIT) &0x1UL, (psr >> IA64_PSR_PP_BIT)&0x1UL); + + t = ¤t->thread; + + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + printk("pmc[%d]=0x%lx tpmc=0x%lx\n", i, ia64_get_pmc(i), t->pmcs[i]); + } + + for (i=1; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + printk("pmd[%d]=0x%lx tpmd=0x%lx\n", i, ia64_get_pmd(i), t->pmds[i]); + } + if (ctx) { + printk("ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr=0x%lx\n", + ctx->ctx_state, + ctx->ctx_smpl_vaddr, + ctx->ctx_smpl_hdr, + ctx->ctx_msgq_head, + ctx->ctx_msgq_tail, + ctx->ctx_saved_psr); + } } -#else /* !CONFIG_PERFMON */ +/* + * called from process.c:copy_thread(). task is new child. + */ +void +pfm_inherit(struct task_struct *task, struct pt_regs *regs) +{ + struct thread_struct *thread; + + DPRINT(("perfmon: pfm_inherit clearing state for [%d] current [%d]\n", task->pid, current->pid)); + + thread = &task->thread; + + /* + * cut links inherited from parent (current) + */ + thread->pfm_context = NULL; + + PFM_SET_WORK_PENDING(task, 0); + /* + * restore default psr settings + */ + ia64_psr(regs)->pp = ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; +} +#else /* !CONFIG_PERFMON */ asmlinkage long -sys_perfmonctl (int pid, int cmd, void *req, int count, long arg5, long arg6, - long arg7, long arg8, long stack) +sys_perfmonctl (int fd, int cmd, void *arg, int count, long arg5, long arg6, long arg7, + long arg8, long stack) { return -ENOSYS; } - -#endif /* !CONFIG_PERFMON */ +#endif /* CONFIG_PERFMON */ diff -Nru a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/kernel/perfmon_default_smpl.c Fri Jun 6 07:20:30 2003 @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for the Linux/ia64 perfmon-2 subsystem. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Stephane Eranian "); +MODULE_DESCRIPTION("perfmon default sampling format"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "debug"); + +MODULE_PARM(debug_ovfl, "i"); +MODULE_PARM_DESC(debug_ovfl, "debug ovfl"); + + +#define DEFAULT_DEBUG 1 + +#ifdef DEFAULT_DEBUG +#define DPRINT(a) \ + do { \ + if (unlikely(debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#else +#define DPRINT(a) +#define DPRINT_ovfl(a) +#endif + +static int debug, debug_ovfl; + +static int +default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data; + int ret = 0; + + if (data == NULL) { + DPRINT(("[%d] no argument passed\n", task->pid)); + return -EINVAL; + } + + DPRINT(("[%d] validate flags=0x%x CPU%d\n", task->pid, flags, cpu)); + + /* + * must hold at least the buffer header + one minimally sized entry + */ + if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL; + + DPRINT(("buf_size=%lu\n", arg->buf_size)); + + return ret; +} + +static int +default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + /* + * size has been validated in default_validate + */ + *size = arg->buf_size; + + return 0; +} + +static int +default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION; + hdr->hdr_buf_size = arg->buf_size; + hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr); + hdr->hdr_last_pos = (void *)((unsigned long)buf)+arg->buf_size; + hdr->hdr_overflows = 0UL; + hdr->hdr_count = 0UL; + + DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u\n", + task->pid, + buf, + hdr->hdr_buf_size, + sizeof(*hdr), + hdr->hdr_version)); + + return 0; +} + +static int +default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_entry_t *ent; + void *cur, *last; + unsigned long *e; + unsigned long ovfl_mask; + unsigned long ovfl_notify; + unsigned long stamp; + unsigned int npmds, i; + + /* + * some time stamp + */ + stamp = ia64_get_itc(); + + if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) { + DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg)); + return -EINVAL; + } + + hdr = (pfm_default_smpl_hdr_t *)buf; + cur = hdr->hdr_cur_pos; + last = hdr->hdr_last_pos; + ovfl_mask = arg->ovfl_pmds[0]; + ovfl_notify = arg->ovfl_notify[0]; + + /* + * check for space against largest possibly entry. + * We may waste space at the end of the buffer. + */ + if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; + + npmds = hweight64(arg->smpl_pmds[0]); + + ent = (pfm_default_smpl_entry_t *)cur; + + prefetch(arg->smpl_pmds_values); + + /* position for first pmd */ + e = (unsigned long *)(ent+1); + + hdr->hdr_count++; + + DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmds=0x%lx ovfl_notify=0x%lx npmds=%u\n", + task->pid, + hdr->hdr_count, + cur, last, + last-cur, + ovfl_mask, + ovfl_notify, npmds)); + + /* + * current = task running at the time of the overflow. + * + * per-task mode: + * - this is ususally the task being monitored. + * Under certain conditions, it might be a different task + * + * system-wide: + * - this is not necessarily the task controlling the session + */ + ent->pid = current->pid; + ent->cpu = smp_processor_id(); + ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; + + /* + * where did the fault happen (includes slot number) + */ + ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3); + + /* + * which registers overflowed + */ + ent->ovfl_pmds = ovfl_mask; + ent->tstamp = stamp; + ent->set = arg->active_set; + ent->reserved1 = 0; + + /* + * selectively store PMDs in increasing index number + */ + if (npmds) { + unsigned long *val = arg->smpl_pmds_values; + for(i=0; i < npmds; i++) { + *e++ = *val++; + } + } + + /* + * update position for next entry + */ + hdr->hdr_cur_pos = cur + sizeof(*ent) + (npmds << 3); + + /* + * keep same ovfl_pmds, ovfl_notify + */ + arg->ovfl_ctrl.notify_user = 0; + arg->ovfl_ctrl.block = 0; + arg->ovfl_ctrl.stop_monitoring = 0; + arg->ovfl_ctrl.reset_pmds = 1; + + return 0; +full: + DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=0x%lx\n", last-cur, hdr->hdr_count, ovfl_notify)); + + /* + * increment number of buffer overflow. + * important to detect duplicate set of samples. + */ + hdr->hdr_overflows++; + + /* + * if no notification is needed, then we just reset the buffer index. + */ + if (ovfl_notify == 0UL) { + hdr->hdr_count = 0UL; + arg->ovfl_ctrl.notify_user = 0; + arg->ovfl_ctrl.block = 0; + arg->ovfl_ctrl.stop_monitoring = 0; + arg->ovfl_ctrl.reset_pmds = 1; + } else { + /* keep same ovfl_pmds, ovfl_notify */ + arg->ovfl_ctrl.notify_user = 1; + arg->ovfl_ctrl.block = 1; + arg->ovfl_ctrl.stop_monitoring = 1; + arg->ovfl_ctrl.reset_pmds = 0; + } + return 0; +} + +static int +default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + pfm_default_smpl_hdr_t *hdr; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_count = 0UL; + hdr->hdr_cur_pos = (void *)((unsigned long)buf)+sizeof(*hdr); + + ctrl->stop_monitoring = 0; + ctrl->reset_pmds = PFM_PMD_LONG_RESET; + + return 0; +} + +static int +default_exit(struct task_struct *task, void *buf, struct pt_regs *regs) +{ + DPRINT(("[%d] exit(%p)\n", task->pid, buf)); + return 0; +} + +static pfm_buffer_fmt_t default_fmt={ + .fmt_name = "default_format", + .fmt_uuid = PFM_DEFAULT_SMPL_UUID, + .fmt_arg_size = sizeof(pfm_default_smpl_arg_t), + .fmt_validate = default_validate, + .fmt_getsize = default_get_size, + .fmt_init = default_init, + .fmt_handler = default_handler, + .fmt_restart = default_restart, + .fmt_exit = default_exit, +}; + +static int __init +pfm_default_smpl_init_module(void) +{ + int ret; + + ret = pfm_register_buffer_fmt(&default_fmt); + if (ret == 0) { + printk("perfmon_default_smpl: %s v%u.%u registered\n", + default_fmt.fmt_name, + PFM_DEFAULT_SMPL_VERSION_MAJ, + PFM_DEFAULT_SMPL_VERSION_MIN); + } else { + printk("perfmon_default_smpl: %s cannot register ret=%d\n", + default_fmt.fmt_name, + ret); + } + + return ret; +} + +static void __exit +pfm_default_smpl_cleanup_module(void) +{ + int ret; + ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid); + + printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret); +} + +module_init(pfm_default_smpl_init_module); +module_exit(pfm_default_smpl_cleanup_module); + diff -Nru a/arch/ia64/kernel/perfmon_generic.h b/arch/ia64/kernel/perfmon_generic.h --- a/arch/ia64/kernel/perfmon_generic.h Fri Jan 24 17:23:18 2003 +++ b/arch/ia64/kernel/perfmon_generic.h Mon Jun 9 09:55:35 2003 @@ -1,17 +1,19 @@ /* - * This file contains the architected PMU register description tables + * This file contains the generic PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ + + #define RDEP(x) (1UL<<(x)) #if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY) #error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined" #endif -static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={ +static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -23,7 +25,7 @@ { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ }; -static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={ +static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={ /* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, @@ -39,10 +41,13 @@ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 32) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_gen_pmd_desc, - .pmc_desc = pfm_gen_pmc_desc + .pmu_name = "Generic", + .pmu_family = 0xff, /* any */ + .enabled = 0, + .ovfl_val = (1UL << 32) - 1, + .num_ibrs = 0, /* does not use */ + .num_dbrs = 0, /* does not use */ + .pmd_desc = pfm_gen_pmd_desc, + .pmc_desc = pfm_gen_pmc_desc }; + diff -Nru a/arch/ia64/kernel/perfmon_itanium.h b/arch/ia64/kernel/perfmon_itanium.h --- a/arch/ia64/kernel/perfmon_itanium.h Fri Jan 24 17:22:11 2003 +++ b/arch/ia64/kernel/perfmon_itanium.h Fri Jun 6 07:20:30 2003 @@ -2,7 +2,7 @@ * This file contains the Itanium PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ @@ -12,8 +12,8 @@ #error "This file is only valid when CONFIG_ITANIUM is defined" #endif -static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); +static int pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -59,52 +59,53 @@ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 32) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_ita_pmd_desc, - .pmc_desc = pfm_ita_pmc_desc + .pmu_name = "Itanium", + .pmu_family = 0x7, + .enabled = 0, + .ovfl_val = (1UL << 32) - 1, + .pmd_desc = pfm_ita_pmd_desc, + .pmc_desc = pfm_ita_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ }; - static int -pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) { - pfm_context_t *ctx = task->thread.pfm_context; int ret; /* * we must clear the (instruction) debug registers if pmc13.ta bit is cleared - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 13 && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); if (ret) return ret; } /* * we must clear the (data) debug registers if pmc11.pt bit is cleared - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 11 && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); if (ret) return ret; } return 0; diff -Nru a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h --- a/arch/ia64/kernel/perfmon_mckinley.h Thu Apr 10 06:46:37 2003 +++ b/arch/ia64/kernel/perfmon_mckinley.h Tue Jun 10 07:39:51 2003 @@ -2,7 +2,7 @@ * This file contains the McKinley PMU register description tables * and pmc checker used by perfmon.c. * - * Copyright (C) 2002 Hewlett Packard Co + * Copyright (C) 2002-2003 Hewlett Packard Co * Stephane Eranian */ @@ -12,9 +12,8 @@ #error "This file is only valid when CONFIG_MCKINLEY is defined" #endif -static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs); -static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs); +static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={ /* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, @@ -22,17 +21,17 @@ /* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, /* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, -/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ }; @@ -62,20 +61,22 @@ * impl_pmcs, impl_pmds are computed at runtime to minimize errors! */ static pmu_config_t pmu_conf={ - .disabled = 1, - .ovfl_val = (1UL << 47) - 1, - .num_ibrs = 8, - .num_dbrs = 8, - .pmd_desc = pfm_mck_pmd_desc, - .pmc_desc = pfm_mck_pmc_desc + .pmu_name = "Itanium 2", + .pmu_family = 0x1f, + .enabled = 0, + .ovfl_val = (1UL << 47) - 1, + .pmd_desc = pfm_mck_pmd_desc, + .pmc_desc = pfm_mck_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ }; - /* * PMC reserved fields must have their power-up values preserved */ static int -pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) { unsigned long tmp1, tmp2, ival = *val; @@ -87,52 +88,56 @@ *val = tmp1 | tmp2; - DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", - cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); + DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", + cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); return 0; } +/* + * task can be NULL if the context is unloaded + */ static int -pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) { - struct thread_struct *th = &task->thread; - pfm_context_t *ctx = task->thread.pfm_context; int ret = 0, check_case1 = 0; unsigned long val8 = 0, val14 = 0, val13 = 0; /* first preserve the reserved fields */ - pfm_mck_reserved(task, cnum, val, regs); + pfm_mck_reserved(cnum, val, regs); + + /* sanitfy check */ + if (ctx == NULL) return -EINVAL; /* - * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled - * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 13 && (*val & (0xfUL << 45)) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(1, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); if (ret) return ret; } - /* - * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled - * before they are (fl_using_dbreg==0) to avoid picking up stale information. + /* + * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled + * before they are (fl_using_dbreg==0) to avoid picking up stale information. */ if (cnum == 14 && ((*val & 0x2222) != 0x2222) && ctx->ctx_fl_using_dbreg == 0) { /* don't mix debug with perfmon */ - if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; - /* + /* * a count of 0 will mark the debug registers as in use and also * ensure that they are properly cleared. */ - ret = pfm_write_ibr_dbr(0, task, NULL, 0, regs); + ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); if (ret) return ret; } @@ -141,17 +146,17 @@ case 4: *val |= 1UL << 23; /* force power enable bit */ break; case 8: val8 = *val; - val13 = th->pmc[13]; - val14 = th->pmc[14]; + val13 = ctx->ctx_pmcs[13]; + val14 = ctx->ctx_pmcs[14]; check_case1 = 1; break; - case 13: val8 = th->pmc[8]; + case 13: val8 = ctx->ctx_pmcs[8]; val13 = *val; - val14 = th->pmc[14]; + val14 = ctx->ctx_pmcs[14]; check_case1 = 1; break; - case 14: val8 = th->pmc[13]; - val13 = th->pmc[13]; + case 14: val8 = ctx->ctx_pmcs[13]; + val13 = ctx->ctx_pmcs[13]; val14 = *val; check_case1 = 1; break; @@ -165,7 +170,7 @@ && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); - if (ret) printk(KERN_DEBUG "perfmon: failure check_case1\n"); + if (ret) printk("perfmon: failure check_case1\n"); } return ret ? -EINVAL : 0; diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/process.c Fri Jun 13 08:41:32 2003 @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -33,16 +32,15 @@ #include #include -#ifdef CONFIG_IA64_SGI_SN -#include -#endif - #ifdef CONFIG_PERFMON # include #endif #include "sigframe.h" +void (*ia64_mark_idle)(int); + + void ia64_do_show_stack (struct unw_frame_info *info, void *arg) { @@ -64,13 +62,7 @@ } void -show_trace_task (struct task_struct *task) -{ - show_stack(task); -} - -void -show_stack (struct task_struct *task) +show_stack (struct task_struct *task, unsigned long *sp) { if (!task) unw_init_running(ia64_do_show_stack, 0); @@ -85,7 +77,7 @@ void dump_stack (void) { - show_stack(NULL); + show_stack(NULL, NULL); } void @@ -103,6 +95,7 @@ regs->ar_rnat, regs->ar_bspstore, regs->pr); printk("ldrs: %016lx ccv : %016lx fpsr: %016lx\n", regs->loadrs, regs->ar_ccv, regs->ar_fpsr); + printk("csd : %016lx ssd : %016lx\n", regs->ar_csd, regs->ar_ssd); printk("b0 : %016lx b6 : %016lx b7 : %016lx\n", regs->b0, regs->b6, regs->b7); printk("f6 : %05lx%016lx f7 : %05lx%016lx\n", regs->f6.u.bits[1], regs->f6.u.bits[0], @@ -110,6 +103,9 @@ printk("f8 : %05lx%016lx f9 : %05lx%016lx\n", regs->f8.u.bits[1], regs->f8.u.bits[0], regs->f9.u.bits[1], regs->f9.u.bits[0]); + printk("f10 : %05lx%016lx f11 : %05lx%016lx\n", + regs->f10.u.bits[1], regs->f10.u.bits[0], + regs->f11.u.bits[1], regs->f11.u.bits[0]); printk("r1 : %016lx r2 : %016lx r3 : %016lx\n", regs->r1, regs->r2, regs->r3); printk("r8 : %016lx r9 : %016lx r10 : %016lx\n", regs->r8, regs->r9, regs->r10); @@ -135,24 +131,22 @@ ((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); } } else - show_stack(NULL); + show_stack(NULL, NULL); } void do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall) { -#ifdef CONFIG_FSYS if (fsys_mode(current, &scr->pt)) { /* defer signal-handling etc. until we return to privilege-level 0. */ if (!ia64_psr(&scr->pt)->lp) ia64_psr(&scr->pt)->lp = 1; return; } -#endif #ifdef CONFIG_PERFMON - if (current->thread.pfm_ovfl_block_reset) - pfm_ovfl_block_reset(); + if (current->thread.pfm_needs_checking) + pfm_handle_work(); #endif /* deal with pending signal delivery */ @@ -175,6 +169,8 @@ void __attribute__((noreturn)) cpu_idle (void *unused) { + void (*mark_idle)(int) = ia64_mark_idle; + /* endless idle loop with no priority at all */ while (1) { void (*idle)(void) = pm_idle; @@ -187,15 +183,13 @@ #endif while (!need_resched()) { -#ifdef CONFIG_IA64_SGI_SN - snidle(); -#endif + if (mark_idle) + (*mark_idle)(1); (*idle)(); } -#ifdef CONFIG_IA64_SGI_SN - snidleoff(); -#endif + if (mark_idle) + (*mark_idle)(0); #ifdef CONFIG_SMP normal_xtp(); @@ -379,7 +373,7 @@ # define THREAD_FLAGS_TO_SET 0 p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR) | THREAD_FLAGS_TO_SET); - p->thread.last_fph_cpu = -1; + ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */ #ifdef CONFIG_IA32_SUPPORT /* * If we're cloning an IA32 task then save the IA32 extra @@ -390,16 +384,8 @@ #endif #ifdef CONFIG_PERFMON - /* - * reset notifiers and owner check (may not have a perfmon context) - */ - atomic_set(&p->thread.pfm_notifiers_check, 0); - atomic_set(&p->thread.pfm_owners_check, 0); - /* clear list of sampling buffer to free for new task */ - p->thread.pfm_smpl_buf_list = NULL; - if (current->thread.pfm_context) - retval = pfm_inherit(p, child_ptregs); + pfm_inherit(p, child_ptregs); #endif return retval; } @@ -472,6 +458,8 @@ dst[52] = pt->ar_pfs; /* UNW_AR_PFS is == to pt->cr_ifs for interrupt frames */ unw_get_ar(info, UNW_AR_LC, &dst[53]); unw_get_ar(info, UNW_AR_EC, &dst[54]); + unw_get_ar(info, UNW_AR_CSD, &dst[55]); + unw_get_ar(info, UNW_AR_SSD, &dst[56]); } void @@ -579,7 +567,8 @@ kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { struct task_struct *parent = current; - int result, tid; + int result; + pid_t tid; tid = clone(flags | CLONE_VM | CLONE_UNTRACED, 0); if (parent != current) { @@ -606,41 +595,9 @@ { /* drop floating-point and debug-register state if it exists: */ current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID); - -#ifndef CONFIG_SMP - if (ia64_get_fpu_owner() == current) - ia64_set_fpu_owner(0); -#endif + ia64_drop_fpu(current); } -#ifdef CONFIG_PERFMON -/* - * by the time we get here, the task is detached from the tasklist. This is important - * because it means that no other tasks can ever find it as a notified task, therfore there - * is no race condition between this code and let's say a pfm_context_create(). - * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if this - * other task is in the middle of its own pfm_context_exit() because it would already be out of - * the task list. Note that this case is very unlikely between a direct child and its parents - * (if it is the notified process) because of the way the exit is notified via SIGCHLD. - */ - -void -release_thread (struct task_struct *task) -{ - if (task->thread.pfm_context) - pfm_context_exit(task); - - if (atomic_read(&task->thread.pfm_notifiers_check) > 0) - pfm_cleanup_notifiers(task); - - if (atomic_read(&task->thread.pfm_owners_check) > 0) - pfm_cleanup_owners(task); - - if (task->thread.pfm_smpl_buf_list) - pfm_cleanup_smpl_buf(task); -} -#endif - /* * Clean up state associated with current thread. This is called when * the thread calls exit(). @@ -648,14 +605,11 @@ void exit_thread (void) { -#ifndef CONFIG_SMP - if (ia64_get_fpu_owner() == current) - ia64_set_fpu_owner(0); -#endif + ia64_drop_fpu(current); #ifdef CONFIG_PERFMON /* if needed, stop monitoring and flush state to perfmon context */ - if (current->thread.pfm_context) - pfm_flush_regs(current); + if (current->thread.pfm_context) + pfm_exit_thread(current); /* free debug register resources */ if (current->thread.flags & IA64_THREAD_DBG_VALID) @@ -739,30 +693,4 @@ if (pm_power_off) pm_power_off(); machine_halt(); -} - -void __init -init_task_struct_cache (void) -{ -} - -struct task_struct * -dup_task_struct(struct task_struct *orig) -{ - struct task_struct *tsk; - - tsk = (void *) __get_free_pages(GFP_KERNEL, KERNEL_STACK_SIZE_ORDER); - if (!tsk) - return NULL; - - memcpy(tsk, orig, sizeof(struct task_struct) + sizeof(struct thread_info)); - tsk->thread_info = (struct thread_info *) ((char *) tsk + IA64_TASK_SIZE); - atomic_set(&tsk->usage, 2); - return tsk; -} - -void -free_task_struct (struct task_struct *tsk) -{ - free_pages((unsigned long) tsk, KERNEL_STACK_SIZE_ORDER); } diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/ptrace.c Fri May 30 12:58:57 2003 @@ -200,14 +200,20 @@ */ static unsigned long get_rnat (struct pt_regs *pt, struct switch_stack *sw, - unsigned long *krbs, unsigned long *urnat_addr) + unsigned long *krbs, unsigned long *urnat_addr, unsigned long *urbs_end) { - unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0UL; + unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0, mask, m; unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; - long num_regs; + long num_regs, nbits; kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; + + if (urbs_end < urnat_addr) + nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_end); + else + nbits = 63; + mask = (1UL << nbits) - 1; /* * First, figure out which bit number slot 0 in user-land maps to in the kernel * rnat. Do this by figuring out how many register slots we're beyond the user's @@ -221,20 +227,26 @@ if (ubspstore + 63 > urnat_addr) { /* some bits need to be merged in from pt->ar_rnat */ - umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1); + umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1) & mask; urnat = (pt->ar_rnat & umask); + mask &= ~umask; + if (!mask) + return urnat; } - if (rnat0_kaddr >= kbsp) { + + m = mask << shift; + if (rnat0_kaddr >= kbsp) rnat0 = sw->ar_rnat; - } else if (rnat0_kaddr > krbs) { + else if (rnat0_kaddr > krbs) rnat0 = *rnat0_kaddr; - } - if (rnat1_kaddr >= kbsp) { + urnat |= (rnat0 & m) >> shift; + + m = mask >> (63 - shift); + if (rnat1_kaddr >= kbsp) rnat1 = sw->ar_rnat; - } else if (rnat1_kaddr > krbs) { + else if (rnat1_kaddr > krbs) rnat1 = *rnat1_kaddr; - } - urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & ~umask; + urnat |= (rnat1 & m) << (63 - shift); return urnat; } @@ -243,60 +255,58 @@ */ static void put_rnat (struct pt_regs *pt, struct switch_stack *sw, - unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat) + unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat, + unsigned long *urbs_end) { unsigned long rnat0 = 0, rnat1 = 0, *slot0_kaddr, umask = 0, mask, m; - unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift, slot, ndirty; + unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift; long num_regs, nbits; - ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); - nbits = ndirty % 63; - kbsp = (unsigned long *) sw->ar_bspstore; ubspstore = (unsigned long *) pt->ar_bspstore; + + if (urbs_end < urnat_addr) + nbits = ia64_rse_num_regs(urnat_addr - 63, urbs_end); + else + nbits = 63; + mask = (1UL << nbits) - 1; + /* * First, figure out which bit number slot 0 in user-land maps to in the kernel * rnat. Do this by figuring out how many register slots we're beyond the user's * backingstore and then computing the equivalent address in kernel space. */ - num_regs = (long) ia64_rse_num_regs(ubspstore, urnat_addr + 1); + num_regs = ia64_rse_num_regs(ubspstore, urnat_addr + 1); slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs); shift = ia64_rse_slot_num(slot0_kaddr); rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr); rnat0_kaddr = rnat1_kaddr - 64; -printk("%s: ubspstore=%p urnat_addr=%p\n", __FUNCTION__, ubspstore, urnat_addr); if (ubspstore + 63 > urnat_addr) { /* some bits need to be place in pt->ar_rnat: */ - slot = ia64_rse_slot_num(ubspstore); - umask = ((1UL << slot) - 1); + umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1) & mask; pt->ar_rnat = (pt->ar_rnat & ~umask) | (urnat & umask); - nbits -= slot; - if (nbits <= 0) + mask &= ~umask; + if (!mask) return; } - mask = (1UL << nbits) - 1; /* * Note: Section 11.1 of the EAS guarantees that bit 63 of an * rnat slot is ignored. so we don't have to clear it here. */ rnat0 = (urnat << shift); m = mask << shift; -printk("%s: rnat0=%016lx, m=%016lx, rnat0_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat0, m, rnat0_kaddr, kbsp); - if (rnat0_kaddr >= kbsp) { + if (rnat0_kaddr >= kbsp) sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat0 & m); - } else if (rnat0_kaddr > krbs) { + else if (rnat0_kaddr > krbs) *rnat0_kaddr = ((*rnat0_kaddr & ~m) | (rnat0 & m)); - } rnat1 = (urnat >> (63 - shift)); m = mask >> (63 - shift); -printk("%s: rnat1=%016lx, m=%016lx, rnat1_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat1, m, rnat1_kaddr, kbsp); - if (rnat1_kaddr >= kbsp) { + if (rnat1_kaddr >= kbsp) sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat1 & m); - } else if (rnat1_kaddr > krbs) { + else if (rnat1_kaddr > krbs) *rnat1_kaddr = ((*rnat1_kaddr & ~m) | (rnat1 & m)); - } } /* @@ -329,7 +339,7 @@ * read the corresponding bits in the kernel RBS. */ rnat_addr = ia64_rse_rnat_addr(laddr); - ret = get_rnat(child_regs, child_stack, krbs, rnat_addr); + ret = get_rnat(child_regs, child_stack, krbs, rnat_addr, urbs_end); if (laddr == rnat_addr) { /* return NaT collection word itself */ @@ -380,7 +390,7 @@ * => write the corresponding bits in the kernel RBS. */ if (ia64_rse_is_rnat_slot(laddr)) - put_rnat(child_regs, child_stack, krbs, laddr, val); + put_rnat(child_regs, child_stack, krbs, laddr, val, urbs_end); else { if (laddr < urbs_end) { regnum = ia64_rse_num_regs(bspstore, laddr); @@ -588,17 +598,11 @@ ia64_flush_fph (struct task_struct *task) { struct ia64_psr *psr = ia64_psr(ia64_task_regs(task)); -#ifdef CONFIG_SMP - struct task_struct *fpu_owner = current; -#else - struct task_struct *fpu_owner = ia64_get_fpu_owner(); -#endif - if (task == fpu_owner && psr->mfh) { + if (ia64_is_local_fpu_owner(task) && psr->mfh) { psr->mfh = 0; - ia64_save_fpu(&task->thread.fph[0]); task->thread.flags |= IA64_THREAD_FPH_VALID; - task->thread.last_fph_cpu = smp_processor_id(); + ia64_save_fpu(&task->thread.fph[0]); } } @@ -618,11 +622,9 @@ ia64_flush_fph(task); if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) { task->thread.flags |= IA64_THREAD_FPH_VALID; - task->thread.last_fph_cpu = -1; /* force reload */ memset(&task->thread.fph, 0, sizeof(task->thread.fph)); } - if (ia64_get_fpu_owner() == task) - ia64_set_fpu_owner(0); + ia64_drop_fpu(task); psr->dfh = 1; } @@ -667,9 +669,13 @@ else ia64_flush_fph(child); ptr = (unsigned long *) ((unsigned long) &child->thread.fph + addr); - } else if (addr >= PT_F10 && addr < PT_F15 + 16) { + } else if ((addr >= PT_F10) && (addr < PT_F11 + 16)) { + /* scratch registers untouched by kernel (saved in pt_regs) */ + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, f10) + addr - PT_F10); + } else if (addr >= PT_F12 && addr < PT_F15 + 16) { /* scratch registers untouched by kernel (saved in switch_stack) */ - ptr = (unsigned long *) ((long) sw + addr - PT_NAT_BITS); + ptr = (unsigned long *) ((long) sw + (addr - PT_NAT_BITS - 32)); } else if (addr < PT_AR_LC + 8) { /* preserved state: */ unsigned long nat_bits, scratch_unat, dummy = 0; @@ -805,22 +811,75 @@ else return ia64_peek(child, sw, urbs_end, rnat_addr, data); - case PT_R1: case PT_R2: case PT_R3: + case PT_R1: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r1)); + break; + + case PT_R2: case PT_R3: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r2) + addr - PT_R2); + break; case PT_R8: case PT_R9: case PT_R10: case PT_R11: - case PT_R12: case PT_R13: case PT_R14: case PT_R15: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r8)+ addr - PT_R8); + break; + case PT_R12: case PT_R13: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r12)+ addr - PT_R12); + break; + case PT_R14: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r14)); + break; + case PT_R15: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, r15)); + break; case PT_R16: case PT_R17: case PT_R18: case PT_R19: case PT_R20: case PT_R21: case PT_R22: case PT_R23: case PT_R24: case PT_R25: case PT_R26: case PT_R27: case PT_R28: case PT_R29: case PT_R30: case PT_R31: - case PT_B0: case PT_B6: case PT_B7: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, r16) + addr - PT_R16); + break; + case PT_B0: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b0)); + break; + case PT_B6: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b6)); + break; + case PT_B7: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, b7)); + break; case PT_F6: case PT_F6+8: case PT_F7: case PT_F7+8: case PT_F8: case PT_F8+8: case PT_F9: case PT_F9+8: + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, f6) + addr - PT_F6); + break; case PT_AR_BSPSTORE: - case PT_AR_RSC: case PT_AR_UNAT: case PT_AR_PFS: - case PT_AR_CCV: case PT_AR_FPSR: case PT_CR_IIP: case PT_PR: - /* scratch register */ - ptr = (unsigned long *) ((long) pt + addr - PT_CR_IPSR); + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, ar_bspstore)); + break; + case PT_AR_RSC: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_rsc)); + break; + case PT_AR_UNAT: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_unat)); + break; + case PT_AR_PFS: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_pfs)); break; + case PT_AR_CCV: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_ccv)); + break; + case PT_AR_FPSR: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, ar_fpsr)); + break; + case PT_CR_IIP: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, cr_iip)); + break; + case PT_PR: + ptr = (unsigned long *) ((long) pt + offsetof(struct pt_regs, pr)); + break; + /* scratch register */ default: /* disallow accessing anything else... */ @@ -828,6 +887,9 @@ addr); return -1; } + } else if (addr <= PT_AR_SSD) { + ptr = (unsigned long *) + ((long) pt + offsetof(struct pt_regs, ar_csd) + addr - PT_AR_CSD); } else { /* access debug registers */ @@ -934,7 +996,8 @@ /* gr1-gr3 */ - retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long) * 3); + retval |= __copy_to_user(&ppr->gr[1], &pt->r1, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[2], &pt->r2, sizeof(long) *2); /* gr4-gr7 */ @@ -948,7 +1011,9 @@ /* gr12-gr15 */ - retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 4); + retval |= __copy_to_user(&ppr->gr[12], &pt->r12, sizeof(long) * 2); + retval |= __copy_to_user(&ppr->gr[14], &pt->r14, sizeof(long)); + retval |= __copy_to_user(&ppr->gr[15], &pt->r15, sizeof(long)); /* gr16-gr31 */ @@ -976,13 +1041,13 @@ retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 0); } - /* fr6-fr9 */ + /* fr6-fr11 */ - retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 4); + retval |= __copy_to_user(&ppr->fr[6], &pt->f6, sizeof(struct ia64_fpreg) * 6); - /* fp scratch regs(10-15) */ + /* fp scratch regs(12-15) */ - retval |= __copy_to_user(&ppr->fr[10], &sw->f10, sizeof(struct ia64_fpreg) * 6); + retval |= __copy_to_user(&ppr->fr[12], &sw->f12, sizeof(struct ia64_fpreg) * 4); /* fr16-fr31 */ @@ -1059,7 +1124,8 @@ /* gr1-gr3 */ - retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long) * 3); + retval |= __copy_from_user(&pt->r1, &ppr->gr[1], sizeof(long)); + retval |= __copy_from_user(&pt->r2, &ppr->gr[2], sizeof(long) * 2); /* gr4-gr7 */ @@ -1077,7 +1143,9 @@ /* gr12-gr15 */ - retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 4); + retval |= __copy_from_user(&pt->r12, &ppr->gr[12], sizeof(long) * 2); + retval |= __copy_from_user(&pt->r14, &ppr->gr[14], sizeof(long)); + retval |= __copy_from_user(&pt->r15, &ppr->gr[15], sizeof(long)); /* gr16-gr31 */ @@ -1105,13 +1173,13 @@ retval |= access_fr(&info, i, 1, (unsigned long *) &ppr->fr[i] + 1, 1); } - /* fr6-fr9 */ + /* fr6-fr11 */ - retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 4); + retval |= __copy_from_user(&pt->f6, &ppr->fr[6], sizeof(ppr->fr[6]) * 6); - /* fp scratch regs(10-15) */ + /* fp scratch regs(12-15) */ - retval |= __copy_from_user(&sw->f10, &ppr->fr[10], sizeof(ppr->fr[10]) * 6); + retval |= __copy_from_user(&sw->f12, &ppr->fr[12], sizeof(ppr->fr[12]) * 4); /* fr16-fr31 */ diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c --- a/arch/ia64/kernel/setup.c Sun May 25 17:00:00 2003 +++ b/arch/ia64/kernel/setup.c Mon Jun 16 17:03:24 2003 @@ -34,14 +34,16 @@ #include #include +#include +#include #include +#include #include -#include #include #include -#include -#include #include +#include +#include #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE) # error "struct cpuinfo_ia64 too big!" @@ -66,6 +68,17 @@ unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ +/* + * The merge_mask variable needs to be set to (max(iommu_page_size(iommu)) - 1). This + * mask specifies a mask of address bits that must be 0 in order for two buffers to be + * mergeable by the I/O MMU (i.e., the end address of the first buffer and the start + * address of the second buffer must be aligned to (merge_mask+1) in order to be + * mergeable). By default, we assume there is no I/O MMU which can merge physically + * discontiguous buffers, so we set the merge_mask to ~0UL, which corresponds to a iommu + * page-size of 2^64. + */ +unsigned long ia64_max_iommu_merge_mask = ~0UL; + #define COMMAND_LINE_SIZE 512 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ @@ -102,11 +115,11 @@ static int find_max_pfn (unsigned long start, unsigned long end, void *arg) { - unsigned long *max_pfn = arg, pfn; + unsigned long *max_pfnp = arg, pfn; pfn = (PAGE_ALIGN(end - 1) - PAGE_OFFSET) >> PAGE_SHIFT; - if (pfn > *max_pfn) - *max_pfn = pfn; + if (pfn > *max_pfnp) + *max_pfnp = pfn; return 0; } @@ -265,9 +278,8 @@ static void find_memory (void) { -# define KERNEL_END ((unsigned long) &_end) +# define KERNEL_END (&_end) unsigned long bootmap_size; - unsigned long max_pfn; int n = 0; /* @@ -286,8 +298,8 @@ + strlen(__va(ia64_boot_param->command_line)) + 1); n++; - rsvd_region[n].start = KERNEL_START; - rsvd_region[n].end = KERNEL_END; + rsvd_region[n].start = (unsigned long) ia64_imva((void *)KERNEL_START); + rsvd_region[n].end = (unsigned long) ia64_imva(KERNEL_END); n++; #ifdef CONFIG_BLK_DEV_INITRD @@ -350,11 +362,14 @@ void __init setup_arch (char **cmdline_p) { + extern unsigned long *__start___vtop_patchlist[], *__end____vtop_patchlist[]; extern unsigned long ia64_iobase; unsigned long phys_iobase; unw_init(); + ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end____vtop_patchlist); + *cmdline_p = __va(ia64_boot_param->command_line); strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); @@ -459,8 +474,6 @@ platform_setup(cmdline_p); paging_init(); - - unw_create_gate_table(); } /* @@ -735,6 +748,8 @@ /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); + ia64_set_kr(IA64_KR_FPU_OWNER, 0); + /* * Initialize default control register to defer all speculative faults. The * kernel MUST NOT depend on a particular setting of these bits (in other words, @@ -745,20 +760,15 @@ */ ia64_set_dcr( IA64_DCR_DP | IA64_DCR_DK | IA64_DCR_DX | IA64_DCR_DR | IA64_DCR_DA | IA64_DCR_DD | IA64_DCR_LC); -#ifndef CONFIG_SMP - ia64_set_fpu_owner(0); -#endif - atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if (current->mm) BUG(); - ia64_mmu_init(cpu_data); + ia64_mmu_init(ia64_imva(cpu_data)); #ifdef CONFIG_IA32_SUPPORT - /* initialize global ia32 state - CR0 and CR4 */ - asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); + ia32_cpu_init(); #endif /* disable all local interrupt sources: */ @@ -800,27 +810,9 @@ void check_bugs (void) { - extern int __start___mckinley_e9_bundles[]; - extern int __end___mckinley_e9_bundles[]; - u64 *bundle; - int *wp; + extern char __start___mckinley_e9_bundles[]; + extern char __end___mckinley_e9_bundles[]; - if (local_cpu_data->family == 0x1f && local_cpu_data->model == 0) - printk(KERN_INFO "check_bugs: leaving McKinley Errata 9 workaround enabled\n"); - else { - printk(KERN_INFO "check_bugs: McKinley Errata 9 workaround not needed; " - "disabling it\n"); - for (wp = __start___mckinley_e9_bundles; wp < __end___mckinley_e9_bundles; ++wp) { - bundle = (u64 *) ((char *) wp + *wp); - /* install a bundle of NOPs: */ - bundle[0] = 0x0000000100000000; - bundle[1] = 0x0004000000000200; - ia64_fc(bundle); - } - ia64_insn_group_barrier(); - ia64_sync_i(); - ia64_insn_group_barrier(); - ia64_srlz_i(); - ia64_insn_group_barrier(); - } + ia64_patch_mckinley_e9((unsigned long) __start___mckinley_e9_bundles, + (unsigned long) __end___mckinley_e9_bundles); } diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c --- a/arch/ia64/kernel/signal.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/signal.c Thu Jun 12 01:09:18 2003 @@ -108,25 +108,22 @@ long err; /* restore scratch that always needs gets updated during signal delivery: */ - err = __get_user(flags, &sc->sc_flags); - + err = __get_user(flags, &sc->sc_flags); err |= __get_user(nat, &sc->sc_nat); err |= __get_user(ip, &sc->sc_ip); /* instruction pointer */ err |= __get_user(cfm, &sc->sc_cfm); err |= __get_user(um, &sc->sc_um); /* user mask */ err |= __get_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); - err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); err |= __get_user(scr->pt.ar_unat, &sc->sc_ar_unat); err |= __get_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); err |= __get_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); err |= __get_user(scr->pt.pr, &sc->sc_pr); /* predicates */ err |= __get_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ err |= __get_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ - err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ - err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 3*8); /* r1-r3 */ + err |= __copy_from_user(&scr->pt.r1, &sc->sc_gr[1], 8); /* r1 */ err |= __copy_from_user(&scr->pt.r8, &sc->sc_gr[8], 4*8); /* r8-r11 */ - err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 4*8); /* r12-r15 */ - err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + err |= __copy_from_user(&scr->pt.r12, &sc->sc_gr[12], 2*8); /* r12-r13 */ + err |= __copy_from_user(&scr->pt.r15, &sc->sc_gr[15], 8); /* r15 */ scr->pt.cr_ifs = cfm | (1UL << 63); @@ -137,17 +134,27 @@ scr->scratch_unat = ia64_put_scratch_nat_bits(&scr->pt, nat); + if (!(flags & IA64_SC_FLAG_IN_SYSCALL)) { + /* Restore most scratch-state only when not in syscall. */ + err |= __get_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __get_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + err |= __get_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ + err |= __copy_from_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_from_user(&scr->pt.r2, &sc->sc_gr[2], 2*8); /* r2-r3 */ + err |= __copy_from_user(&scr->pt.r16, &sc->sc_gr[16], 16*8); /* r16-r31 */ + } + if ((flags & IA64_SC_FLAG_FPH_VALID) != 0) { struct ia64_psr *psr = ia64_psr(&scr->pt); __copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16); psr->mfh = 0; /* drop signal handler's fph contents... */ if (psr->dfh) - current->thread.last_fph_cpu = -1; + ia64_drop_fpu(current); else { + /* We already own the local fph, otherwise psr->dfh wouldn't be 0. */ __ia64_load_fpu(current->thread.fph); - ia64_set_fpu_owner(current); - current->thread.last_fph_cpu = smp_processor_id(); + ia64_set_local_fpu_owner(current); } } return err; @@ -166,11 +173,10 @@ int err; /* - * If you change siginfo_t structure, please be sure - * this code is fixed accordingly. It should never - * copy any pad contained in the structure to avoid - * security leaks, but must copy the generic 3 ints - * plus the relevant union member. + * If you change siginfo_t structure, please be sure this code is fixed + * accordingly. It should never copy any pad contained in the structure + * to avoid security leaks, but must copy the generic 3 ints plus the + * relevant union member. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); @@ -183,24 +189,15 @@ err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_imm, &to->si_imm); break; - case __SI_CHLD >> 16: - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - err |= __put_user(from->si_status, &to->si_status); - case __SI_PROF >> 16: - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_pid, &to->si_pid); - if (from->si_code == PROF_OVFL) { - err |= __put_user(from->si_pfm_ovfl[0], &to->si_pfm_ovfl[0]); - err |= __put_user(from->si_pfm_ovfl[1], &to->si_pfm_ovfl[1]); - err |= __put_user(from->si_pfm_ovfl[2], &to->si_pfm_ovfl[2]); - err |= __put_user(from->si_pfm_ovfl[3], &to->si_pfm_ovfl[3]); - } case __SI_TIMER >> 16: err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_value, &to->si_value); break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); default: err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_pid, &to->si_pid); @@ -237,10 +234,6 @@ to->si_code |= __SI_POLL; break; - case SIGPROF: - to->si_code |= __SI_PROF; - break; - default: break; } @@ -352,27 +345,40 @@ nat = ia64_get_scratch_nat_bits(&scr->pt, scr->scratch_unat); err = __put_user(flags, &sc->sc_flags); - err |= __put_user(nat, &sc->sc_nat); err |= PUT_SIGSET(mask, &sc->sc_mask); err |= __put_user(cfm, &sc->sc_cfm); err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um); err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc); - err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); err |= __put_user(scr->pt.ar_unat, &sc->sc_ar_unat); /* ar.unat */ err |= __put_user(scr->pt.ar_fpsr, &sc->sc_ar_fpsr); /* ar.fpsr */ err |= __put_user(scr->pt.ar_pfs, &sc->sc_ar_pfs); err |= __put_user(scr->pt.pr, &sc->sc_pr); /* predicates */ err |= __put_user(scr->pt.b0, &sc->sc_br[0]); /* b0 (rp) */ err |= __put_user(scr->pt.b6, &sc->sc_br[6]); /* b6 */ - err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ - - err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 3*8); /* r1-r3 */ + err |= __copy_to_user(&sc->sc_gr[1], &scr->pt.r1, 8); /* r1 */ err |= __copy_to_user(&sc->sc_gr[8], &scr->pt.r8, 4*8); /* r8-r11 */ - err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 4*8); /* r12-r15 */ - err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ - + err |= __copy_to_user(&sc->sc_gr[12], &scr->pt.r12, 2*8); /* r12-r13 */ + err |= __copy_to_user(&sc->sc_gr[15], &scr->pt.r15, 8); /* r15 */ err |= __put_user(scr->pt.cr_iip + ia64_psr(&scr->pt)->ri, &sc->sc_ip); + + if (flags & IA64_SC_FLAG_IN_SYSCALL) { + /* Clear scratch registers if the signal interrupted a system call. */ + err |= __put_user(0, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __put_user(0, &sc->sc_br[7]); /* b7 */ + err |= __put_user(0, &sc->sc_gr[14]); /* r14 */ + err |= __clear_user(&sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __clear_user(&sc->sc_gr[2], 2*8); /* r2-r3 */ + err |= __clear_user(&sc->sc_gr[16], 16*8); /* r16-r31 */ + } else { + /* Copy scratch regs to sigcontext if the signal didn't interrupt a syscall. */ + err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv); /* ar.ccv */ + err |= __put_user(scr->pt.b7, &sc->sc_br[7]); /* b7 */ + err |= __put_user(scr->pt.r14, &sc->sc_gr[14]); /* r14 */ + err |= __copy_to_user(&scr->pt.ar_csd, &sc->sc_ar25, 2*8); /* ar.csd & ar.ssd */ + err |= __copy_to_user(&sc->sc_gr[2], &scr->pt.r2, 2*8); /* r2-r3 */ + err |= __copy_to_user(&sc->sc_gr[16], &scr->pt.r16, 16*8); /* r16-r31 */ + } return err; } @@ -389,14 +395,14 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct sigscratch *scr) { - extern char ia64_sigtramp[], __start_gate_section[]; + extern char __kernel_sigtramp[]; unsigned long tramp_addr, new_rbs = 0; struct sigframe *frame; struct siginfo si; long err; frame = (void *) scr->pt.r12; - tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section); + tramp_addr = (unsigned long) __kernel_sigtramp; if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) { frame = (void *) ((current->sas_ss_sp + current->sas_ss_size) & ~(STACK_ALIGN - 1)); @@ -406,7 +412,7 @@ * in the kernel, register stack is switched in the signal trampoline). */ if (!rbs_on_sig_stack(scr->pt.ar_bspstore)) - new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); + new_rbs = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1); } frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1)); @@ -451,8 +457,8 @@ scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */ #if DEBUG_SIG - printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", - current->comm, current->pid, sig, scr->pt.r12, scr->pt.cr_iip, scr->pt.r3); + printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%p\n", + current->comm, current->pid, sig, scr->pt.r12, frame->sc.sc_ip, frame->handler); #endif return 1; diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c Sat May 10 02:28:46 2003 +++ b/arch/ia64/kernel/smpboot.c Tue Jun 17 23:50:17 2003 @@ -352,10 +352,10 @@ fork_by_hand (void) { /* - * don't care about the eip and regs settings since we'll never reschedule the + * Don't care about the IP and regs settings since we'll never reschedule the * forked task. */ - return do_fork(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL); + return copy_process(CLONE_VM|CLONE_IDLETASK, 0, 0, 0, NULL, NULL); } static int __init @@ -370,6 +370,7 @@ idle = fork_by_hand(); if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); + wake_up_forked_process(idle); /* * We remove it from the pidhash and the runqueue @@ -449,7 +450,7 @@ for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) { sapicid = smp_boot_data.cpu_phys_id[i]; - if (sapicid == -1 || sapicid == boot_cpu_id) + if (sapicid == boot_cpu_id) continue; phys_cpu_present_map |= (1 << cpu); ia64_cpu_to_sapicid[cpu] = sapicid; @@ -598,7 +599,7 @@ /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, - __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0); + ia64_tpa(ap_startup->fp), ia64_tpa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) printk(KERN_ERR "SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); diff -Nru a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c --- a/arch/ia64/kernel/sys_ia64.c Wed Feb 26 06:03:08 2003 +++ b/arch/ia64/kernel/sys_ia64.c Tue Jun 10 14:00:47 2003 @@ -2,7 +2,7 @@ * This file contains various system calls that have different calling * conventions on different platforms. * - * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co + * Copyright (C) 1999-2000, 2002-2003 Hewlett-Packard Co * David Mosberger-Tang */ #include diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c --- a/arch/ia64/kernel/time.c Sat Jun 14 16:16:01 2003 +++ b/arch/ia64/kernel/time.c Wed Jun 18 00:37:28 2003 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,10 +26,11 @@ #include extern unsigned long wall_jiffies; -extern unsigned long last_nsec_offset; u64 jiffies_64 = INITIAL_JIFFIES; +#define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */ + #ifdef CONFIG_IA64_DEBUG_IRQ unsigned long last_cli_ip; @@ -59,19 +61,32 @@ atomic_inc((atomic_t *) &prof_buffer[ip]); } +static void +itc_reset (void) +{ +} + +/* + * Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or + * larger than NSEC_PER_SEC. + */ +static void +itc_update (long delta_nsec) +{ +} + /* * Return the number of nano-seconds that elapsed since the last update to jiffy. The * xtime_lock must be at least read-locked when calling this routine. */ -static inline unsigned long -gettimeoffset (void) +unsigned long +itc_get_offset (void) { unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; unsigned long now, last_tick; -# define time_keeper_id 0 /* smp_processor_id() of time-keeper */ - last_tick = (cpu_data(time_keeper_id)->itm_next - - (lost + 1)*cpu_data(time_keeper_id)->itm_delta); + last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next + - (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta); now = ia64_get_itc(); if (unlikely((long) (now - last_tick) < 0)) { @@ -83,6 +98,12 @@ return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; } +static struct time_interpolator itc_interpolator = { + .get_offset = itc_get_offset, + .update = itc_update, + .reset = itc_reset +}; + static inline void set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) { @@ -115,7 +136,7 @@ * Discover what correction gettimeofday would have done, and then undo * it! */ - nsec -= gettimeoffset(); + nsec -= time_interpolator_get_offset(); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); @@ -127,6 +148,7 @@ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; + time_interpolator_reset(); } write_sequnlock_irq(&xtime_lock); clock_was_set(); @@ -138,14 +160,11 @@ { unsigned long seq, nsec, usec, sec, old, offset; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - while (1) { seq = read_seqbegin(&xtime_lock); { old = last_nsec_offset; - offset = gettimeoffset(); + offset = time_interpolator_get_offset(); sec = xtime.tv_sec; nsec = xtime.tv_nsec; } @@ -221,7 +240,7 @@ #endif new_itm += local_cpu_data->itm_delta; - if (smp_processor_id() == 0) { + if (smp_processor_id() == TIME_KEEPER_ID) { /* * Here we are in the timer irq handler. We have irqs locally * disabled, but we don't know if the timer_bh is running on @@ -283,16 +302,17 @@ void __init ia64_init_itm (void) { - unsigned long platform_base_freq, itc_freq, drift; + unsigned long platform_base_freq, itc_freq; struct pal_freq_ratio itc_ratio, proc_ratio; - long status; + long status, platform_base_drift, itc_drift; /* * According to SAL v2.6, we need to use a SAL call to determine the platform base * frequency and then a PAL call to determine the frequency ratio between the ITC * and the base frequency. */ - status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift); + status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, + &platform_base_freq, &platform_base_drift); if (status != 0) { printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); } else { @@ -305,6 +325,7 @@ printk(KERN_ERR "SAL/PAL failed to obtain frequency info---inventing reasonable values\n"); platform_base_freq = 100000000; + platform_base_drift = -1; /* no drift info */ itc_ratio.num = 3; itc_ratio.den = 1; } @@ -312,6 +333,7 @@ printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n", platform_base_freq); platform_base_freq = 75000000; + platform_base_drift = -1; } if (!proc_ratio.den) proc_ratio.den = 1; /* avoid division by zero */ @@ -319,17 +341,29 @@ itc_ratio.den = 1; /* avoid division by zero */ itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; + if (platform_base_drift != -1) + itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den; + else + itc_drift = -1; + local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " - "ITC freq=%lu.%03luMHz\n", smp_processor_id(), + "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, - itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); + itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000, + itc_drift); local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; local_cpu_data->itc_freq = itc_freq; local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC; local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<itc_freq; + itc_interpolator.drift = itc_drift; + register_time_interpolator(&itc_interpolator); + } /* Setup the CPU local timer tick */ ia64_cpu_local_tick(); diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c --- a/arch/ia64/kernel/traps.c Tue May 6 10:56:54 2003 +++ b/arch/ia64/kernel/traps.c Thu Jun 12 01:09:18 2003 @@ -247,16 +247,17 @@ psr->dfh = 0; #ifndef CONFIG_SMP { - struct task_struct *fpu_owner = ia64_get_fpu_owner(); + struct task_struct *fpu_owner + = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); - if (fpu_owner == current) + if (ia64_is_local_fpu_owner(current)) return; if (fpu_owner) ia64_flush_fph(fpu_owner); } #endif /* !CONFIG_SMP */ - ia64_set_fpu_owner(current); + ia64_set_local_fpu_owner(current); if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { __ia64_load_fpu(current->thread.fph); psr->mfh = 0; @@ -274,7 +275,6 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, struct pt_regs *regs) { - struct ia64_fpreg f6_11[6]; fp_state_t fp_state; fpswa_ret_t ret; @@ -289,11 +289,8 @@ * pointer to point to these registers. */ fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ - f6_11[0] = regs->f6; f6_11[1] = regs->f7; - f6_11[2] = regs->f8; f6_11[3] = regs->f9; - __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4])); - __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5])); - fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11; + + fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, @@ -309,10 +306,7 @@ (unsigned long *) ipsr, (unsigned long *) fpsr, (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); - regs->f6 = f6_11[0]; regs->f7 = f6_11[1]; - regs->f8 = f6_11[2]; regs->f9 = f6_11[3]; - __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_11[4])); - __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_11[5])); + return ret.status; } @@ -336,8 +330,9 @@ if (jiffies - last_time > 5*HZ) fpu_swa_count = 0; - if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { + if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { last_time = jiffies; + ++fpu_swa_count; printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr); } @@ -533,9 +528,8 @@ case 29: /* Debug */ case 35: /* Taken Branch Trap */ case 36: /* Single Step Trap */ -#ifdef CONFIG_FSYS if (fsys_mode(current, regs)) { - extern char syscall_via_break[], __start_gate_section[]; + extern char __kernel_syscall_via_break[]; /* * Got a trap in fsys-mode: Taken Branch Trap and Single Step trap * need special handling; Debug trap is not supposed to happen. @@ -546,12 +540,11 @@ return; } /* re-do the system call via break 0x100000: */ - regs->cr_iip = GATE_ADDR + (syscall_via_break - __start_gate_section); + regs->cr_iip = (unsigned long) __kernel_syscall_via_break; ia64_psr(regs)->ri = 0; ia64_psr(regs)->cpl = 3; return; } -#endif switch (vector) { case 29: siginfo.si_code = TRAP_HWBKPT; diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c --- a/arch/ia64/kernel/unaligned.c Tue Apr 22 19:46:02 2003 +++ b/arch/ia64/kernel/unaligned.c Wed May 21 19:48:55 2003 @@ -218,8 +218,9 @@ RSW(f2), RSW(f3), RSW(f4), RSW(f5), RPT(f6), RPT(f7), RPT(f8), RPT(f9), + RPT(f10), RPT(f11), - RSW(f10), RSW(f11), RSW(f12), RSW(f13), RSW(f14), + RSW(f12), RSW(f13), RSW(f14), RSW(f15), RSW(f16), RSW(f17), RSW(f18), RSW(f19), RSW(f20), RSW(f21), RSW(f22), RSW(f23), RSW(f24), RSW(f25), RSW(f26), RSW(f27), RSW(f28), RSW(f29), diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c --- a/arch/ia64/kernel/unwind.c Sat May 10 02:28:47 2003 +++ b/arch/ia64/kernel/unwind.c Tue Jun 17 23:50:17 2003 @@ -1,6 +1,8 @@ /* * Copyright (C) 1999-2003 Hewlett-Packard Co * David Mosberger-Tang + * Copyright (C) 2003 Fenghua Yu + * - Change pt_regs_off() to make it less dependant on pt_regs structure. */ /* * This file implements call frame unwind support for the Linux @@ -25,6 +27,7 @@ * acquired, then the read-write lock must be acquired first. */ #include +#include #include #include #include @@ -76,7 +79,7 @@ # define STAT(x...) #endif -#define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) +#define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) @@ -84,8 +87,6 @@ typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; -#define struct_offset(str,fld) ((char *)&((str *)NULL)->fld - (char *) 0) - static struct { spinlock_t lock; /* spinlock for unwind data */ @@ -104,6 +105,8 @@ /* index into unw_frame_info for preserved register i */ unsigned short preg_index[UNW_NUM_REGS]; + short pt_regs_offsets[32]; + /* unwind table for the kernel: */ struct unw_table kernel_table; @@ -153,47 +156,78 @@ UNW_REG_UNAT, UNW_REG_LC, UNW_REG_FPSR, UNW_REG_PRI_UNAT_GR }, .preg_index = { - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ - struct_offset(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ - struct_offset(struct unw_frame_info, bsp_loc)/8, - struct_offset(struct unw_frame_info, bspstore_loc)/8, - struct_offset(struct unw_frame_info, pfs_loc)/8, - struct_offset(struct unw_frame_info, rnat_loc)/8, - struct_offset(struct unw_frame_info, psp)/8, - struct_offset(struct unw_frame_info, rp_loc)/8, - struct_offset(struct unw_frame_info, r4)/8, - struct_offset(struct unw_frame_info, r5)/8, - struct_offset(struct unw_frame_info, r6)/8, - struct_offset(struct unw_frame_info, r7)/8, - struct_offset(struct unw_frame_info, unat_loc)/8, - struct_offset(struct unw_frame_info, pr_loc)/8, - struct_offset(struct unw_frame_info, lc_loc)/8, - struct_offset(struct unw_frame_info, fpsr_loc)/8, - struct_offset(struct unw_frame_info, b1_loc)/8, - struct_offset(struct unw_frame_info, b2_loc)/8, - struct_offset(struct unw_frame_info, b3_loc)/8, - struct_offset(struct unw_frame_info, b4_loc)/8, - struct_offset(struct unw_frame_info, b5_loc)/8, - struct_offset(struct unw_frame_info, f2_loc)/8, - struct_offset(struct unw_frame_info, f3_loc)/8, - struct_offset(struct unw_frame_info, f4_loc)/8, - struct_offset(struct unw_frame_info, f5_loc)/8, - struct_offset(struct unw_frame_info, fr_loc[16 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[17 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[18 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[19 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[20 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[21 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[22 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[23 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[24 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[25 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[26 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[27 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[28 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[29 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[30 - 16])/8, - struct_offset(struct unw_frame_info, fr_loc[31 - 16])/8, + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_GR */ + offsetof(struct unw_frame_info, pri_unat_loc)/8, /* PRI_UNAT_MEM */ + offsetof(struct unw_frame_info, bsp_loc)/8, + offsetof(struct unw_frame_info, bspstore_loc)/8, + offsetof(struct unw_frame_info, pfs_loc)/8, + offsetof(struct unw_frame_info, rnat_loc)/8, + offsetof(struct unw_frame_info, psp)/8, + offsetof(struct unw_frame_info, rp_loc)/8, + offsetof(struct unw_frame_info, r4)/8, + offsetof(struct unw_frame_info, r5)/8, + offsetof(struct unw_frame_info, r6)/8, + offsetof(struct unw_frame_info, r7)/8, + offsetof(struct unw_frame_info, unat_loc)/8, + offsetof(struct unw_frame_info, pr_loc)/8, + offsetof(struct unw_frame_info, lc_loc)/8, + offsetof(struct unw_frame_info, fpsr_loc)/8, + offsetof(struct unw_frame_info, b1_loc)/8, + offsetof(struct unw_frame_info, b2_loc)/8, + offsetof(struct unw_frame_info, b3_loc)/8, + offsetof(struct unw_frame_info, b4_loc)/8, + offsetof(struct unw_frame_info, b5_loc)/8, + offsetof(struct unw_frame_info, f2_loc)/8, + offsetof(struct unw_frame_info, f3_loc)/8, + offsetof(struct unw_frame_info, f4_loc)/8, + offsetof(struct unw_frame_info, f5_loc)/8, + offsetof(struct unw_frame_info, fr_loc[16 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[17 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[18 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[19 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[20 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[21 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[22 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[23 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[24 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[25 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[26 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[27 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[28 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[29 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[30 - 16])/8, + offsetof(struct unw_frame_info, fr_loc[31 - 16])/8, + }, + .pt_regs_offsets = { + [0] = -1, + offsetof(struct pt_regs, r1), + offsetof(struct pt_regs, r2), + offsetof(struct pt_regs, r3), + [4] = -1, [5] = -1, [6] = -1, [7] = -1, + offsetof(struct pt_regs, r8), + offsetof(struct pt_regs, r9), + offsetof(struct pt_regs, r10), + offsetof(struct pt_regs, r11), + offsetof(struct pt_regs, r12), + offsetof(struct pt_regs, r13), + offsetof(struct pt_regs, r14), + offsetof(struct pt_regs, r15), + offsetof(struct pt_regs, r16), + offsetof(struct pt_regs, r17), + offsetof(struct pt_regs, r18), + offsetof(struct pt_regs, r19), + offsetof(struct pt_regs, r20), + offsetof(struct pt_regs, r21), + offsetof(struct pt_regs, r22), + offsetof(struct pt_regs, r23), + offsetof(struct pt_regs, r24), + offsetof(struct pt_regs, r25), + offsetof(struct pt_regs, r26), + offsetof(struct pt_regs, r27), + offsetof(struct pt_regs, r28), + offsetof(struct pt_regs, r29), + offsetof(struct pt_regs, r30), + offsetof(struct pt_regs, r31), }, .hash = { [0 ... UNW_HASH_SIZE - 1] = -1 }, #ifdef UNW_DEBUG @@ -209,7 +243,6 @@ #endif }; - /* Unwind accessors. */ /* @@ -218,19 +251,16 @@ static inline unsigned long pt_regs_off (unsigned long reg) { - unsigned long off =0; + short off = -1; - if (reg >= 1 && reg <= 3) - off = struct_offset(struct pt_regs, r1) + 8*(reg - 1); - else if (reg <= 11) - off = struct_offset(struct pt_regs, r8) + 8*(reg - 8); - else if (reg <= 15) - off = struct_offset(struct pt_regs, r12) + 8*(reg - 12); - else if (reg <= 31) - off = struct_offset(struct pt_regs, r16) + 8*(reg - 16); - else + if (reg < ARRAY_SIZE(unw.pt_regs_offsets)) + off = unw.pt_regs_offsets[reg]; + + if (off < 0) { UNW_DPRINT(0, "unwind.%s: bad scratch reg r%lu\n", __FUNCTION__, reg); - return off; + off = 0; + } + return (unsigned long) off; } static inline struct pt_regs * @@ -239,7 +269,10 @@ if (!info->pt) { /* This should not happen with valid unwind info. */ UNW_DPRINT(0, "unwind.%s: bad unwind info: resetting info->pt\n", __FUNCTION__); - info->pt = info->sp - 16; + if (info->flags & UNW_FLAG_INTERRUPT_FRAME) + info->pt = (unsigned long) ((struct pt_regs *) info->psp - 1); + else + info->pt = info->sp - 16; } UNW_DPRINT(3, "unwind.%s: sp 0x%lx pt 0x%lx\n", __FUNCTION__, info->sp, info->pt); return (struct pt_regs *) info->pt; @@ -371,12 +404,11 @@ unsigned long *addr; struct pt_regs *pt; - pt = get_scratch_regs(info); switch (regnum) { /* scratch: */ - case 0: addr = &pt->b0; break; - case 6: addr = &pt->b6; break; - case 7: addr = &pt->b7; break; + case 0: pt = get_scratch_regs(info); addr = &pt->b0; break; + case 6: pt = get_scratch_regs(info); addr = &pt->b6; break; + case 7: pt = get_scratch_regs(info); addr = &pt->b7; break; /* preserved: */ case 1: case 2: case 3: case 4: case 5: @@ -409,17 +441,17 @@ return -1; } - pt = get_scratch_regs(info); - if (regnum <= 5) { addr = *(&info->f2_loc + (regnum - 2)); if (!addr) addr = &info->sw->f2 + (regnum - 2); } else if (regnum <= 15) { - if (regnum <= 9) + if (regnum <= 11) { + pt = get_scratch_regs(info); addr = &pt->f6 + (regnum - 6); + } else - addr = &info->sw->f10 + (regnum - 10); + addr = &info->sw->f12 + (regnum - 12); } else if (regnum <= 31) { addr = info->fr_loc[regnum - 16]; if (!addr) @@ -447,7 +479,6 @@ unsigned long *addr; struct pt_regs *pt; - pt = get_scratch_regs(info); switch (regnum) { case UNW_AR_BSP: addr = info->bsp_loc; @@ -502,13 +533,25 @@ break; case UNW_AR_RSC: + pt = get_scratch_regs(info); addr = &pt->ar_rsc; break; case UNW_AR_CCV: + pt = get_scratch_regs(info); addr = &pt->ar_ccv; break; + case UNW_AR_CSD: + pt = get_scratch_regs(info); + addr = &pt->ar_csd; + break; + + case UNW_AR_SSD: + pt = get_scratch_regs(info); + addr = &pt->ar_ssd; + break; + default: UNW_DPRINT(0, "unwind.%s: trying to access non-existent ar%u\n", __FUNCTION__, regnum); @@ -782,7 +825,7 @@ static inline void desc_abi (unsigned char abi, unsigned char context, struct unw_state_record *sr) { - if (abi == 0 && context == 'i') { + if (abi == 3 && context == 'i') { sr->flags |= UNW_FLAG_INTERRUPT_FRAME; UNW_DPRINT(3, "unwind.%s: interrupt frame\n", __FUNCTION__); } @@ -1376,8 +1419,8 @@ val = unw.preg_index[UNW_REG_F16 + (rval - 16)]; else { opc = UNW_INSN_MOVE_SCRATCH; - if (rval <= 9) - val = struct_offset(struct pt_regs, f6) + 16*(rval - 6); + if (rval <= 11) + val = offsetof(struct pt_regs, f6) + 16*(rval - 6); else UNW_DPRINT(0, "unwind.%s: kernel may not touch f%lu\n", __FUNCTION__, rval); @@ -1390,11 +1433,11 @@ else { opc = UNW_INSN_MOVE_SCRATCH; if (rval == 0) - val = struct_offset(struct pt_regs, b0); + val = offsetof(struct pt_regs, b0); else if (rval == 6) - val = struct_offset(struct pt_regs, b6); + val = offsetof(struct pt_regs, b6); else - val = struct_offset(struct pt_regs, b7); + val = offsetof(struct pt_regs, b7); } break; @@ -1594,7 +1637,7 @@ && sr.curr.reg[UNW_REG_PSP].val != 0) { /* new psp is sp plus frame size */ insn.opc = UNW_INSN_ADD; - insn.dst = struct_offset(struct unw_frame_info, psp)/8; + insn.dst = offsetof(struct unw_frame_info, psp)/8; insn.val = sr.curr.reg[UNW_REG_PSP].val; /* frame size */ script_emit(script, insn); } @@ -1728,14 +1771,13 @@ lazy_init: off = unw.sw_off[val]; s[val] = (unsigned long) state->sw + off; - if (off >= struct_offset(struct switch_stack, r4) - && off <= struct_offset(struct switch_stack, r7)) + if (off >= offsetof(struct switch_stack, r4) && off <= offsetof(struct switch_stack, r7)) /* * We're initializing a general register: init NaT info, too. Note that * the offset is a multiple of 8 which gives us the 3 bits needed for * the type field. */ - s[val+1] = (struct_offset(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; + s[val+1] = (offsetof(struct switch_stack, ar_unat) - off) | UNW_NAT_MEMSTK; goto redo; } @@ -1799,11 +1841,7 @@ return -1; } ip = info->ip = *info->rp_loc; - if (ip < GATE_ADDR + PAGE_SIZE) { - /* - * We don't have unwind info for the gate page, so we consider that part - * of user-space for the purpose of unwinding. - */ + if (ip < GATE_ADDR) { UNW_DPRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; @@ -1825,7 +1863,7 @@ if ((pr & (1UL << pNonSys)) != 0) num_regs = *info->cfm_loc & 0x7f; /* size of frame */ info->pfs_loc = - (unsigned long *) (info->pt + struct_offset(struct pt_regs, ar_pfs)); + (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); UNW_DPRINT(3, "unwind.%s: interrupt_frame pt 0x%lx\n", __FUNCTION__, info->pt); } else num_regs = (*info->cfm_loc >> 7) & 0x7f; /* size of locals */ @@ -1876,11 +1914,7 @@ __FUNCTION__, ip); return -1; } - /* - * We don't have unwind info for the gate page, so we consider that part - * of user-space for the purpose of unwinding. - */ - if (ip < GATE_ADDR + PAGE_SIZE) + if (ip < GATE_ADDR) return 0; } unw_get_ip(info, &ip); @@ -2090,30 +2124,41 @@ kfree(table); } -void -unw_create_gate_table (void) +static void __init +create_gate_table (void) { - extern char __start_gate_section[], __stop_gate_section[]; - unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base; - const struct unw_table_entry *entry, *first, *unw_table_end; - extern int ia64_unw_end; + const struct unw_table_entry *entry, *start, *end; + unsigned long *lp, segbase = GATE_ADDR; size_t info_size, size; char *info; + Elf64_Phdr *punw = NULL, *phdr = (Elf64_Phdr *) (GATE_ADDR + GATE_EHDR->e_phoff); + int i; + + for (i = 0; i < GATE_EHDR->e_phnum; ++i, ++phdr) + if (phdr->p_type == PT_IA_64_UNWIND) { + punw = phdr; + break; + } + + if (!punw) { + printk("%s: failed to find gate DSO's unwind table!\n", __FUNCTION__); + return; + } - start = (unsigned long) __start_gate_section - segbase; - end = (unsigned long) __stop_gate_section - segbase; - unw_table_end = (struct unw_table_entry *) &ia64_unw_end; + start = (const struct unw_table_entry *) punw->p_vaddr; + end = (struct unw_table_entry *) ((char *) start + punw->p_memsz); size = 0; - first = lookup(&unw.kernel_table, start); - for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry) + unw_add_unwind_table("linux-gate.so", segbase, 0, start, end); + + for (entry = start; entry < end; ++entry) size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); size += 8; /* reserve space for "end of table" marker */ - unw.gate_table = alloc_bootmem(size); + unw.gate_table = kmalloc(size, GFP_KERNEL); if (!unw.gate_table) { unw.gate_table_size = 0; - printk(KERN_ERR "unwind: unable to create unwind data for gate page!\n"); + printk(KERN_ERR "%s: unable to create unwind data for gate page!\n", __FUNCTION__); return; } unw.gate_table_size = size; @@ -2121,19 +2166,21 @@ lp = unw.gate_table; info = (char *) unw.gate_table + size; - for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry, lp += 3) { + for (entry = start; entry < end; ++entry, lp += 3) { info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); info -= info_size; memcpy(info, (char *) segbase + entry->info_offset, info_size); - lp[0] = entry->start_offset - start + GATE_ADDR; /* start */ - lp[1] = entry->end_offset - start + GATE_ADDR; /* end */ - lp[2] = info - (char *) unw.gate_table; /* info */ + lp[0] = segbase + entry->start_offset; /* start */ + lp[1] = segbase + entry->end_offset; /* end */ + lp[2] = info - (char *) unw.gate_table; /* info */ } *lp = 0; /* end-of-table marker */ } -void +__initcall(create_gate_table); + +void __init unw_init (void) { extern int ia64_unw_start, ia64_unw_end, __gp; @@ -2174,6 +2221,14 @@ } /* + * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + * + * This system call has been deprecated. The new and improved way to get + * at the kernel's unwind info is via the gate DSO. The address of the + * ELF header for this DSO is passed to user-level via AT_SYSINFO_EHDR. + * + * DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + * * This system call copies the unwind data into the buffer pointed to by BUF and returns * the size of the unwind data. If BUF_SIZE is smaller than the size of the unwind data * or if BUF is NULL, nothing is copied, but the system call still returns the size of the diff -Nru a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile --- a/arch/ia64/lib/Makefile Sun Jun 8 01:09:45 2003 +++ b/arch/ia64/lib/Makefile Mon Jun 16 17:15:40 2003 @@ -13,6 +13,12 @@ lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o lib-$(CONFIG_PERFMON) += carta_random.o +ifeq ($(CONFIG_MD_RAID5),m) + lib-y += xor.o +else + lib-$(CONFIG_MD_RAID5) += xor.o +endif + IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -Nru a/arch/ia64/lib/idiv64.S b/arch/ia64/lib/idiv64.S --- a/arch/ia64/lib/idiv64.S Mon Feb 4 23:55:06 2002 +++ b/arch/ia64/lib/idiv64.S Wed May 21 19:48:56 2003 @@ -37,57 +37,44 @@ #define NAME PASTE(PASTE(__,SGN),PASTE(OP,di3)) GLOBAL_ENTRY(NAME) - .prologue .regstk 2,0,0,0 // Transfer inputs to FP registers. setf.sig f8 = in0 setf.sig f9 = in1 ;; - .fframe 16 - .save.f 0x20 - stf.spill [sp] = f17,-16 - // Convert the inputs to FP, to avoid FP software-assist faults. INT_TO_FP(f8, f8) - ;; - - .save.f 0x10 - stf.spill [sp] = f16 - .body INT_TO_FP(f9, f9) ;; - frcpa.s1 f17, p6 = f8, f9 // y0 = frcpa(b) + frcpa.s1 f11, p6 = f8, f9 // y0 = frcpa(b) ;; -(p6) fmpy.s1 f7 = f8, f17 // q0 = a*y0 -(p6) fnma.s1 f6 = f9, f17, f1 // e0 = -b*y0 + 1 +(p6) fmpy.s1 f7 = f8, f11 // q0 = a*y0 +(p6) fnma.s1 f6 = f9, f11, f1 // e0 = -b*y0 + 1 ;; -(p6) fma.s1 f16 = f7, f6, f7 // q1 = q0*e0 + q0 +(p6) fma.s1 f10 = f7, f6, f7 // q1 = q0*e0 + q0 (p6) fmpy.s1 f7 = f6, f6 // e1 = e0*e0 ;; #ifdef MODULO sub in1 = r0, in1 // in1 = -b #endif -(p6) fma.s1 f16 = f16, f7, f16 // q2 = q1*e1 + q1 -(p6) fma.s1 f6 = f17, f6, f17 // y1 = y0*e0 + y0 +(p6) fma.s1 f10 = f10, f7, f10 // q2 = q1*e1 + q1 +(p6) fma.s1 f6 = f11, f6, f11 // y1 = y0*e0 + y0 ;; (p6) fma.s1 f6 = f6, f7, f6 // y2 = y1*e1 + y1 -(p6) fnma.s1 f7 = f9, f16, f8 // r = -b*q2 + a +(p6) fnma.s1 f7 = f9, f10, f8 // r = -b*q2 + a ;; #ifdef MODULO setf.sig f8 = in0 // f8 = a setf.sig f9 = in1 // f9 = -b #endif -(p6) fma.s1 f17 = f7, f6, f16 // q3 = r*y2 + q2 +(p6) fma.s1 f11 = f7, f6, f10 // q3 = r*y2 + q2 ;; - .restore sp - ldf.fill f16 = [sp], 16 - FP_TO_INT(f17, f17) // q = trunc(q3) + FP_TO_INT(f11, f11) // q = trunc(q3) ;; #ifdef MODULO - xma.l f17 = f17, f9, f8 // r = q*(-b) + a + xma.l f11 = f11, f9, f8 // r = q*(-b) + a ;; #endif - getf.sig r8 = f17 // transfer result to result register - ldf.fill f17 = [sp] + getf.sig r8 = f11 // transfer result to result register br.ret.sptk.many rp END(NAME) diff -Nru a/arch/ia64/lib/memcpy_mck.S b/arch/ia64/lib/memcpy_mck.S --- a/arch/ia64/lib/memcpy_mck.S Fri Jan 17 19:18:54 2003 +++ b/arch/ia64/lib/memcpy_mck.S Wed May 14 18:32:48 2003 @@ -15,11 +15,7 @@ #include #include -#if __GNUC__ >= 3 -# define EK(y...) EX(y) -#else -# define EK(y,x...) x -#endif +#define EK(y...) EX(y) GLOBAL_ENTRY(bcopy) .regstk 3,0,0,0 diff -Nru a/arch/ia64/lib/xor.S b/arch/ia64/lib/xor.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/lib/xor.S Tue Apr 29 05:29:57 2003 @@ -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 -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c --- a/arch/ia64/mm/discontig.c Tue Feb 25 01:38:27 2003 +++ b/arch/ia64/mm/discontig.c Fri May 30 08:56:30 2003 @@ -285,9 +285,11 @@ kaddr = (unsigned long)__va(bdp->node_boot_start); ekaddr = (unsigned long)__va(bdp->node_low_pfn << PAGE_SHIFT); while (kaddr < ekaddr) { - bid = BANK_MEM_MAP_INDEX(kaddr); - node_data[mynode]->node_id_map[bid] = node; - node_data[mynode]->bank_mem_map_base[bid] = page; + if (paddr_to_nid(__pa(kaddr)) == node) { + bid = BANK_MEM_MAP_INDEX(kaddr); + node_data[mynode]->node_id_map[bid] = node; + node_data[mynode]->bank_mem_map_base[bid] = page; + } kaddr += BANKSIZE; page += BANKSIZE/PAGE_SIZE; } diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c --- a/arch/ia64/mm/fault.c Sat May 10 03:13:39 2003 +++ b/arch/ia64/mm/fault.c Wed May 14 17:50:39 2003 @@ -43,6 +43,33 @@ return 0; } +/* + * Return TRUE if ADDRESS points at a page in the kernel's mapped segment + * (inside region 5, on ia64) and that page is present. + */ +static int +mapped_kernel_page_is_present (unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset_k(address); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + return 0; + + pmd = pmd_offset(pgd,address); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + return 0; + + ptep = pte_offset_kernel(pmd, address); + if (!ptep) + return 0; + + pte = *ptep; + return pte_present(pte); +} + void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { @@ -187,6 +214,16 @@ } if (done_with_exception(regs)) + return; + + /* + * Since we have no vma's for region 5, we might get here even if the address is + * valid, due to the VHPT walker inserting a non present translation that becomes + * stale. If that happens, the non present fault handler already purged the stale + * translation, which fixed the problem. So, we check to see if the translation is + * valid, and return if it is. + */ + if (REGION_NUMBER(address) == 5 && mapped_kernel_page_is_present(address)) return; /* diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c --- a/arch/ia64/mm/hugetlbpage.c Wed May 14 23:43:48 2003 +++ b/arch/ia64/mm/hugetlbpage.c Mon Jun 16 17:03:24 2003 @@ -116,7 +116,7 @@ /* 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) +int check_valid_hugepage_range(unsigned long addr, unsigned long len) { if (REGION_NUMBER(addr) == REGION_HPAGE) return -EINVAL; diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Sun Jun 1 14:12:56 2003 +++ b/arch/ia64/mm/init.c Tue Jun 17 23:50:17 2003 @@ -1,7 +1,7 @@ /* * Initialize MMU support. * - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang */ #include @@ -9,13 +9,14 @@ #include #include +#include +#include #include +#include #include #include #include #include -#include -#include #include #include @@ -23,13 +24,15 @@ #include #include #include +#include #include #include #include -#include #include +#include +#include -struct mmu_gather mmu_gathers[NR_CPUS]; +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); /* References to section boundaries: */ extern char _stext, _etext, _edata, __init_begin, __init_end, _end; @@ -47,6 +50,8 @@ static int pgt_cache_water[2] = { 25, 50 }; +struct page *zero_page_memmap_ptr; /* map entry for zero page */ + void check_pgt_cache (void) { @@ -65,6 +70,36 @@ } } +void +update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) +{ + unsigned long addr; + struct page *page; + + if (!pte_exec(pte)) + return; /* not an executable page... */ + + page = pte_page(pte); + /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ + addr = (unsigned long) page_address(page); + + if (test_bit(PG_arch_1, &page->flags)) + return; /* i-cache is already coherent with d-cache */ + + flush_icache_range(addr, addr + PAGE_SIZE); + set_bit(PG_arch_1, &page->flags); /* mark page as clean */ +} + +inline void +ia64_set_rbs_bot (void) +{ + unsigned long stack_size = current->rlim[RLIMIT_STACK].rlim_max & -16; + + if (stack_size > MAX_USER_STACK_SIZE) + stack_size = MAX_USER_STACK_SIZE; + current->thread.rbs_bot = STACK_TOP - stack_size; +} + /* * This performs some platform-dependent address space initialization. * On IA-64, we want to setup the VM area for the register backing @@ -76,6 +111,8 @@ { struct vm_area_struct *vma; + ia64_set_rbs_bot(); + /* * If we're out of memory and kmem_cache_alloc() returns NULL, we simply ignore * the problem. When the process attempts to write to the register backing store @@ -84,7 +121,7 @@ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma) { vma->vm_mm = current->mm; - vma->vm_start = IA64_RBS_BOT; + vma->vm_start = current->thread.rbs_bot; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; @@ -112,14 +149,16 @@ void free_initmem (void) { - unsigned long addr; + unsigned long addr, eaddr; - addr = (unsigned long) &__init_begin; - for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) { + addr = (unsigned long) ia64_imva(&__init_begin); + eaddr = (unsigned long) ia64_imva(&__init_end); + while (addr < eaddr) { ClearPageReserved(virt_to_page(addr)); set_page_count(virt_to_page(addr), 1); free_page(addr); ++totalram_pages; + addr += PAGE_SIZE; } printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n", (&__init_end - &__init_begin) >> 10); @@ -230,18 +269,17 @@ } /* - * This is like put_dirty_page() but installs a clean page with PAGE_GATE protection - * (execute-only, typically). + * This is like put_dirty_page() but installs a clean page in the kernel's page table. */ struct page * -put_gate_page (struct page *page, unsigned long address) +put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) { pgd_t *pgd; pmd_t *pmd; pte_t *pte; if (!PageReserved(page)) - printk(KERN_ERR "put_gate_page: gate page at 0x%p not in reserved memory\n", + printk(KERN_ERR "put_kernel_page: page at 0x%p not in reserved memory\n", page_address(page)); pgd = pgd_offset_k(address); /* note: this is NOT pgd_offset()! */ @@ -258,7 +296,7 @@ pte_unmap(pte); goto out; } - set_pte(pte, mk_pte(page, PAGE_GATE)); + set_pte(pte, mk_pte(page, pgprot)); pte_unmap(pte); } out: spin_unlock(&init_mm.page_table_lock); @@ -266,10 +304,31 @@ return page; } +static void +setup_gate (void) +{ + struct page *page; + extern char __start_gate_section[]; + + /* + * Map the gate page twice: once read-only to export the ELF headers etc. and once + * execute-only page to enable privilege-promotion via "epc": + */ + page = virt_to_page(ia64_imva(__start_gate_section)); + put_kernel_page(page, GATE_ADDR, PAGE_READONLY); +#ifdef HAVE_BUGGY_SEGREL + page = virt_to_page(ia64_imva(__start_gate_section + PAGE_SIZE)); + put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE); +#else + put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE); +#endif + ia64_patch_gate(); +} + void __init ia64_mmu_init (void *my_cpu_data) { - unsigned long psr, rid, pta, impl_va_bits; + unsigned long psr, pta, impl_va_bits; extern void __init tlb_init (void); #ifdef CONFIG_DISABLE_VHPT # define VHPT_ENABLE_BIT 0 @@ -277,21 +336,8 @@ # define VHPT_ENABLE_BIT 1 #endif - /* - * Set up the kernel identity mapping for regions 6 and 5. The mapping for region - * 7 is setup up in _start(). - */ + /* Pin mapping for percpu area into TLB */ psr = ia64_clear_ic(); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (IA64_GRANULE_SHIFT << 2)); - - rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); - ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); - - /* ensure rr6 is up-to-date before inserting the PERCPU_ADDR translation: */ - ia64_srlz_d(); - ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)), PERCPU_PAGE_SHIFT); @@ -489,6 +535,7 @@ discontig_paging_init(); efi_memmap_walk(count_pages, &num_physpages); + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } #else /* !CONFIG_DISCONTIGMEM */ void @@ -560,6 +607,7 @@ } free_area_init(zones_size); # endif /* !CONFIG_VIRTUAL_MEM_MAP */ + zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page)); } #endif /* !CONFIG_DISCONTIGMEM */ @@ -576,13 +624,32 @@ return 0; } +/* + * Boot command-line option "nolwsys" can be used to disable the use of any light-weight + * system call handler. When this option is in effect, all fsyscalls will end up bubbling + * down into the kernel and calling the normal (heavy-weight) syscall handler. This is + * useful for performance testing, but conceivably could also come in handy for debugging + * purposes. + */ + +static int nolwsys; + +static int __init +nolwsys_setup (char *s) +{ + nolwsys = 1; + return 1; +} + +__setup("nolwsys", nolwsys_setup); + void mem_init (void) { - extern char __start_gate_section[]; long reserved_pages, codesize, datasize, initsize; unsigned long num_pgt_pages; pg_data_t *pgdat; + int i; static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; #ifdef CONFIG_PCI @@ -634,8 +701,19 @@ if (num_pgt_pages > (u64) pgt_cache_water[1]) pgt_cache_water[1] = num_pgt_pages; - /* install the gate page in the global page table: */ - put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); + /* + * For fsyscall entrpoints with no light-weight handler, use the ordinary + * (heavy-weight) handler, but mark it by setting bit 0, so the fsyscall entry + * code can tell them apart. + */ + for (i = 0; i < NR_syscalls; ++i) { + extern unsigned long fsyscall_table[NR_syscalls]; + extern unsigned long sys_call_table[NR_syscalls]; + + if (!fsyscall_table[i] || nolwsys) + fsyscall_table[i] = sys_call_table[i] | 1; + } + setup_gate(); /* setup gate pages before we free up boot memory... */ #ifdef CONFIG_IA32_SUPPORT ia32_gdt_init(); diff -Nru a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c --- a/arch/ia64/mm/tlb.c Thu Jan 30 06:14:13 2003 +++ b/arch/ia64/mm/tlb.c Tue May 13 10:44:14 2003 @@ -1,7 +1,7 @@ /* * TLB support routines. * - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * David Mosberger-Tang * * 08/02/00 A. Mallick @@ -22,17 +22,10 @@ #include #include -#define SUPPORTED_PGBITS ( \ - 1 << _PAGE_SIZE_256M | \ - 1 << _PAGE_SIZE_64M | \ - 1 << _PAGE_SIZE_16M | \ - 1 << _PAGE_SIZE_4M | \ - 1 << _PAGE_SIZE_1M | \ - 1 << _PAGE_SIZE_256K | \ - 1 << _PAGE_SIZE_64K | \ - 1 << _PAGE_SIZE_16K | \ - 1 << _PAGE_SIZE_8K | \ - 1 << _PAGE_SIZE_4K ) +static struct { + unsigned long mask; /* mask of supported purge page-sizes */ + unsigned long max_bits; /* log2() of largest supported purge page-size */ +} purge; struct ia64_ctx ia64_ctx = { .lock = SPIN_LOCK_UNLOCKED, @@ -154,22 +147,10 @@ } nbits = ia64_fls(size + 0xfff); - if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) { - if (nbits > _PAGE_SIZE_256M) - nbits = _PAGE_SIZE_256M; - else - /* - * Some page sizes are not implemented in the - * IA-64 arch, so if we get asked to clear an - * unsupported page size, round up to the - * nearest page size. Note that we depend on - * the fact that if page size N is not - * implemented, 2*N _is_ implemented. - */ - ++nbits; - if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) - panic("flush_tlb_range: BUG: nbits=%lu\n", nbits); - } + while (unlikely (((1UL << nbits) & purge.mask) == 0) && (nbits < purge.max_bits)) + ++nbits; + if (nbits > purge.max_bits) + nbits = purge.max_bits; start &= ~((1UL << nbits) - 1); # ifdef CONFIG_SMP @@ -190,6 +171,15 @@ ia64_tlb_init (void) { ia64_ptce_info_t ptce_info; + unsigned long tr_pgbits; + long status; + + if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { + printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld;" + "defaulting to architected purge page-sizes.\n", status); + purge.mask = 0x115557000; + } + purge.max_bits = ia64_fls(purge.mask); ia64_get_ptce(&ptce_info); local_cpu_data->ptce_base = ptce_info.base; diff -Nru a/arch/ia64/scripts/check-gas b/arch/ia64/scripts/check-gas --- a/arch/ia64/scripts/check-gas Sat Mar 22 07:38:27 2003 +++ b/arch/ia64/scripts/check-gas Sat Jun 14 00:38:59 2003 @@ -2,8 +2,11 @@ dir=$(dirname $0) CC=$1 OBJDUMP=$2 -$CC -c $dir/check-gas-asm.S -res=$($OBJDUMP -r --section .data check-gas-asm.o | fgrep 00004 | tr -s ' ' |cut -f3 -d' ') +tmp=${TMPDIR:-/tmp} +out=$tmp/out$$.o +$CC -c $dir/check-gas-asm.S -o $out +res=$($OBJDUMP -r --section .data $out | fgrep 00004 | tr -s ' ' |cut -f3 -d' ') +rm -f $out if [ $res != ".text" ]; then echo buggy else diff -Nru a/arch/ia64/scripts/check-segrel.S b/arch/ia64/scripts/check-segrel.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/scripts/check-segrel.S Sat Jun 14 00:38:59 2003 @@ -0,0 +1,4 @@ + .rodata + data4 @segrel(start) + .data +start: diff -Nru a/arch/ia64/scripts/check-segrel.lds b/arch/ia64/scripts/check-segrel.lds --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/scripts/check-segrel.lds Sat Jun 14 00:38:59 2003 @@ -0,0 +1,11 @@ +SECTIONS { + . = SIZEOF_HEADERS; + .rodata : { *(.rodata) } :ro + . = 0xa0000; + .data : { *(.data) } :dat + /DISCARD/ : { *(*) } +} +PHDRS { + ro PT_LOAD FILEHDR PHDRS; + dat PT_LOAD; +} diff -Nru a/arch/ia64/scripts/toolchain-flags b/arch/ia64/scripts/toolchain-flags --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/scripts/toolchain-flags Sat Jun 14 00:39:00 2003 @@ -0,0 +1,22 @@ +#!/bin/sh +# +# Check whether linker can handle cross-segment @segrel(): +# +CC=$1 +LD=$2 +OBJDUMP=$3 +dir=$(dirname $0) +tmp=${TMPDIR:-/tmp} +out=$tmp/out$$ +$CC -c $dir/check-segrel.S -o $out.o +$LD -static -T$dir/check-segrel.lds $out.o -o $out +res=$($OBJDUMP --full --section .rodata $out | fgrep 000 | cut -f3 -d' ') +rm -f $out $out.o +if [ $res != 00000a00 ]; then + echo " -DHAVE_BUGGY_SEGREL" + cat >&2 <, where dn is the digit number. The amount of memory is 8MB*2**. (If = 0, the memory size is 0). - SN1 doesnt support dimms this small but small memory systems + SN1 doesn't support dimms this small but small memory systems boot faster on Medusa. diff -Nru a/arch/ia64/sn/fakeprom/fpmem.c b/arch/ia64/sn/fakeprom/fpmem.c --- a/arch/ia64/sn/fakeprom/fpmem.c Tue Mar 18 07:58:23 2003 +++ b/arch/ia64/sn/fakeprom/fpmem.c Fri May 16 04:18:17 2003 @@ -13,7 +13,7 @@ * FPROM EFI memory descriptor build routines * * - Routines to build the EFI memory descriptor map - * - Should also be usable by the SGI SN1 prom to convert + * - Should also be usable by the SGI prom to convert * klconfig to efi_memmap */ @@ -53,10 +53,7 @@ #define KERNEL_SIZE (4*MB) #define PROMRESERVED_SIZE (1*MB) -#ifdef CONFIG_IA64_SGI_SN1 -#define PHYS_ADDRESS(_n, _x) (((long)_n<<33) | (long)_x) -#define MD_BANK_SHFT 30 -#else +#ifdef SGI_SN2 #define PHYS_ADDRESS(_n, _x) (((long)_n<<38) | (long)_x | 0x3000000000UL) #define MD_BANK_SHFT 34 #endif @@ -77,7 +74,7 @@ return sn_config->cpus; } -/* For SN1, get the index th nasid */ +/* For SN, get the index th nasid */ int GetNasid(int index) @@ -104,40 +101,7 @@ * actually disabled etc. */ -#ifdef CONFIG_IA64_SGI_SN1 -int -IsBankPresent(int index, node_memmap_t nmemmap) -{ - switch (index) { - case 0:return nmemmap.b0; - case 1:return nmemmap.b1; - case 2:return nmemmap.b2; - case 3:return nmemmap.b3; - case 4:return nmemmap.b4; - case 5:return nmemmap.b5; - case 6:return nmemmap.b6; - case 7:return nmemmap.b7; - default:return -1 ; - } -} - -int -GetBankSize(int index, node_memmap_t nmemmap) -{ - switch (index) { - case 0: - case 1:return nmemmap.b01size; - case 2: - case 3:return nmemmap.b23size; - case 4: - case 5:return nmemmap.b45size; - case 6: - case 7:return nmemmap.b67size; - default:return -1 ; - } -} - -#else +#ifdef SGI_SN2 int IsBankPresent(int index, node_memmap_t nmemmap) { @@ -192,12 +156,12 @@ for (cnode=0;cnode /* - * Structure of the mem config of the node as a SN1 MI reg + * Structure of the mem config of the node as a SN MI reg * Medusa supports this reg config. * * BankSize nibble to bank size mapping @@ -24,32 +24,7 @@ #define MBSHIFT 20 -#ifdef CONFIG_IA64_SGI_SN1 -typedef struct node_memmap_s -{ - unsigned int b0 :1, /* 0 bank 0 present */ - b1 :1, /* 1 bank 1 present */ - r01 :2, /* 2-3 reserved */ - b01size :4, /* 4-7 Size of bank 0 and 1 */ - b2 :1, /* 8 bank 2 present */ - b3 :1, /* 9 bank 3 present */ - r23 :2, /* 10-11 reserved */ - b23size :4, /* 12-15 Size of bank 2 and 3 */ - b4 :1, /* 16 bank 4 present */ - b5 :1, /* 17 bank 5 present */ - r45 :2, /* 18-19 reserved */ - b45size :4, /* 20-23 Size of bank 4 and 5 */ - b6 :1, /* 24 bank 6 present */ - b7 :1, /* 25 bank 7 present */ - r67 :2, /* 26-27 reserved */ - b67size :4; /* 28-31 Size of bank 6 and 7 */ -} node_memmap_t ; - -/* Support the medusa hack for 8M/16M/32M nodes */ -#define SN1_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ -#define BankSizeBytes(bsize) ((bsize<6) ? (1<<((bsize-1)+SN1_BANK_SIZE_SHIFT)) :\ - (1<<((bsize-9)+MBSHIFT))) -#else +#ifdef SGI_SN2 typedef struct node_memmap_s { unsigned int b0size :3, /* 0-2 bank 0 size */ @@ -73,6 +48,8 @@ #define SN2_BANK_SIZE_SHIFT (MBSHIFT+6) /* 64 MB */ #define BankPresent(bsize) (bsize<6) #define BankSizeBytes(bsize) (BankPresent(bsize) ? 1UL<<((bsize)+SN2_BANK_SIZE_SHIFT) : 0) +#define MD_BANKS_PER_NODE 4 +#define MD_BANKSIZE (1UL << 34) #endif typedef struct sn_memmap_s diff -Nru a/arch/ia64/sn/fakeprom/fpromasm.S b/arch/ia64/sn/fakeprom/fpromasm.S --- a/arch/ia64/sn/fakeprom/fpromasm.S Tue Dec 3 10:07:22 2002 +++ b/arch/ia64/sn/fakeprom/fpromasm.S Fri May 16 04:18:17 2003 @@ -8,7 +8,7 @@ * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -57,9 +57,7 @@ * be 0x00000ffffc000000, but on snia we use the (inverse swizzled) * IOSPEC_BASE value */ -#ifdef CONFIG_IA64_SGI_SN1 -#define IOPB_PA 0xc0000FFFFC000000 -#else +#ifdef SGI_SN2 #define IOPB_PA 0xc000000fcc000000 #endif @@ -84,10 +82,7 @@ // Isolate node number we are running on. mov r6 = ip;; -#ifdef CONFIG_IA64_SGI_SN1 - shr r5 = r6,33;; // r5 = node number - shl r6 = r5,33 // r6 = base memory address of node -#else +#ifdef SGI_SN2 shr r5 = r6,38 // r5 = node number dep r6 = 0,r6,0,36 // r6 = base memory address of node @@ -99,7 +94,7 @@ or r1 = r1,r6 // Relocate to boot node // Lets figure out who we are & put it in the LID register. -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 // On SN2, we (currently) pass the cpu number in r10 at boot and r25=3,r10;; movl r16=0x8000008110000400 // Allow IPIs @@ -324,10 +319,7 @@ 1: cmp.eq p6,p7=8,r28 /* PAL_VM_SUMMARY */ (p7) br.cond.sptk.few 1f movl r8=0 -#ifdef CONFIG_IA64_SGI_SN1 - movl r9=0x0203083001151059 - movl r10=0x1232 -#else +#ifdef SGI_SN2 movl r9=0x0203083001151065 movl r10=0x183f #endif diff -Nru a/arch/ia64/sn/fakeprom/fw-emu.c b/arch/ia64/sn/fakeprom/fw-emu.c --- a/arch/ia64/sn/fakeprom/fw-emu.c Tue Feb 25 02:41:38 2003 +++ b/arch/ia64/sn/fakeprom/fw-emu.c Fri May 16 04:18:18 2003 @@ -5,7 +5,7 @@ * Copyright (C) 1998-2000 David Mosberger-Tang * * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -36,14 +36,13 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ #include -#include #include #include #include #include #include #include -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 #include #include #endif @@ -69,10 +68,7 @@ #define ACPI_SLIT_REVISION 1 #define OEMID "SGI" -#ifdef CONFIG_IA64_SGI_SN1 -#define PRODUCT "SN1" -#define PROXIMITY_DOMAIN(nasid) (nasid) -#else +#ifdef SGI_SN2 #define PRODUCT "SN2" #define PROXIMITY_DOMAIN(nasid) (((nasid)>>1) & 255) #endif @@ -100,12 +96,7 @@ typedef union ia64_nasid_va { struct { -#if defined(CONFIG_IA64_SGI_SN1) - unsigned long off : 33; /* intra-region offset */ - unsigned long nasid : 7; /* NASID */ - unsigned long off2 : 21; /* fill */ - unsigned long reg : 3; /* region number */ -#elif defined(CONFIG_IA64_SGI_SN2) +#if defined(SGI_SN2) unsigned long off : 36; /* intra-region offset */ unsigned long attr : 2; unsigned long nasid : 11; /* NASID */ @@ -125,9 +116,7 @@ #define IS_VIRTUAL_MODE() ({struct ia64_psr psr; asm("mov %0=psr" : "=r"(psr)); psr.dt;}) #define ADDR_OF(p) (IS_VIRTUAL_MODE() ? ((void*)((long)(p)+PAGE_OFFSET)) : ((void*) (p))) -#if defined(CONFIG_IA64_SGI_SN1) -#define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.l;}) -#elif defined(CONFIG_IA64_SGI_SN2) +#if defined(SGI_SN2) #define __fwtab_pa(n,x) ({ia64_nasid_va _v; _v.l = (long) (x); _v.f.nasid = (x) ? (n) : 0; _v.f.reg = 0; _v.f.attr = 3; _v.l;}) #endif @@ -208,7 +197,7 @@ return EFI_UNSUPPORTED; } -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 #undef cpu_physical_id #define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) @@ -301,7 +290,7 @@ ; } else if (index == SAL_UPDATE_PAL) { ; -#ifdef CONFIG_IA64_SGI_SN2 +#ifdef SGI_SN2 } else if (index == SN_SAL_LOG_CE) { #ifdef ajmtestcpei fprom_send_cpei(); @@ -501,9 +490,7 @@ /* * Pass the parameter base address to the build_efi_xxx routines. */ -#if defined(CONFIG_IA64_SGI_SN1) - build_init(8LL*GB*base_nasid); -#else +#if defined(SGI_SN2) build_init(0x3000000000UL | ((long)base_nasid<<38)); #endif @@ -559,7 +546,7 @@ * You can also edit this line to pass other arguments to the kernel. * Note: disable kernel text replication. */ - strcpy(cmd_line, "init=/bin/bash ktreplicate=0"); + strcpy(cmd_line, "init=/bin/bash console=ttyS0"); memset(efi_systab, 0, sizeof(efi_systab)); efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; @@ -625,10 +612,7 @@ lsapic20->header.length = sizeof(struct acpi_table_lsapic); lsapic20->acpi_id = cnode*4+cpu; lsapic20->flags.enabled = 1; -#if defined(CONFIG_IA64_SGI_SN1) - lsapic20->eid = cpu; - lsapic20->id = nasid; -#else +#if defined(SGI_SN2) lsapic20->eid = nasid&0xffff; lsapic20->id = (cpu<<4) | (nasid>>16); #endif @@ -649,12 +633,9 @@ srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); srat_memory_affinity->base_addr_lo = 0; srat_memory_affinity->length_lo = 0; -#if defined(CONFIG_IA64_SGI_SN1) - srat_memory_affinity->base_addr_hi = nasid<<1; - srat_memory_affinity->length_hi = SN1_NODE_SIZE>>32; -#else +#if defined(SGI_SN2) srat_memory_affinity->base_addr_hi = (nasid<<6) | (3<<4); - srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32; + srat_memory_affinity->length_hi = (MD_BANKSIZE*MD_BANKS_PER_NODE)>>32; #endif srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY; srat_memory_affinity->flags.enabled = 1; @@ -671,10 +652,7 @@ srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity); srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid); srat_cpu_affinity->flags.enabled = 1; -#if defined(CONFIG_IA64_SGI_SN1) - srat_cpu_affinity->apic_id = nasid; - srat_cpu_affinity->lsapic_eid = cpu; -#else +#if defined(SGI_SN2) srat_cpu_affinity->lsapic_eid = nasid&0xffff; srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16); #endif @@ -708,7 +686,7 @@ sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */ strcpy(sal_systab->oem_id, "SGI"); - strcpy(sal_systab->product_id, "SN1"); + strcpy(sal_systab->product_id, "SN2"); /* fill in an entry point: */ sal_ed->type = SAL_DESC_ENTRY_POINT; @@ -757,7 +735,7 @@ sal_systab->checksum = -checksum; /* If the checksum is correct, the kernel tries to use the - * table. We don't build enough table & the kernel aborts. + * table. We dont build enough table & the kernel aborts. * Note that the PROM hasd thhhe same problem!! */ @@ -786,9 +764,7 @@ for(cpu=0; cpu 0) diff -Nru a/arch/ia64/sn/fakeprom/klgraph_init.c b/arch/ia64/sn/fakeprom/klgraph_init.c --- a/arch/ia64/sn/fakeprom/klgraph_init.c Tue Dec 3 10:07:22 2002 +++ b/arch/ia64/sn/fakeprom/klgraph_init.c Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ @@ -49,41 +49,13 @@ klgraph_init(void) { -#ifdef CONFIG_IA64_SGI_SN1 u64 *temp; -#endif /* * Initialize some hub/xbow registers that allows access to * Xbridge etc. These are normally done in PROM. */ /* Write IOERR clear to clear the CRAZY bit in the status */ -#ifdef CONFIG_IA64_SGI_SN1 - *(volatile uint64_t *)0xc0000a0001c001f8 = (uint64_t)0xffffffff; - - /* set widget control register...setting bedrock widget id to b */ - *(volatile uint64_t *)0xc0000a0001c00020 = (uint64_t)0x801b; - - /* set io outbound widget access...allow all */ - *(volatile uint64_t *)0xc0000a0001c00110 = (uint64_t)0xff01; - - /* set io inbound widget access...allow all */ - *(volatile uint64_t *)0xc0000a0001c00118 = (uint64_t)0xff01; - - /* set io crb timeout to max */ - *(volatile uint64_t *)0xc0000a0001c003c0 = (uint64_t)0xffffff; - *(volatile uint64_t *)0xc0000a0001c003c0 = (uint64_t)0xffffff; - - /* set local block io permission...allow all */ - *(volatile uint64_t *)0xc0000a0001e04010 = (uint64_t)0xfffffffffffffff; - - /* clear any errors */ - /* clear_ii_error(); medusa should have cleared these */ - - /* set default read response buffers in bridge */ - *(volatile u32 *)0xc0000a000f000280L = 0xba98; - *(volatile u32 *)0xc0000a000f000288L = 0xba98; -#elif CONFIG_IA64_SGI_SN2 *(volatile uint64_t *)0xc000000801c001f8 = (uint64_t)0xffffffff; /* set widget control register...setting bedrock widget id to a */ @@ -108,184 +80,126 @@ /* set default read response buffers in bridge */ // [PI] *(volatile u32 *)0xc00000080f000280L = 0xba98; // [PI] *(volatile u32 *)0xc00000080f000288L = 0xba98; -#endif /* CONFIG_IA64_SGI_SN1 */ - -#ifdef CONFIG_IA64_SGI_SN1 - - /* - * kldir entries initialization - mankato - */ - convert(0x8000000000002000, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002010, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002020, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002030, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002040, 0x434d5f53505f5357, 0x0000000000030000); - convert(0x8000000000002050, 0x0000000000000000, 0x0000000000010000); - convert(0x8000000000002060, 0x0000000000000001, 0x0000000000000000); - convert(0x8000000000002070, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002080, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002090, 0x0000000000000000, 0x0000000000000000); - convert(0x80000000000020a0, 0x0000000000000000, 0x0000000000000000); - convert(0x80000000000020b0, 0x0000000000000000, 0x0000000000000000); - convert(0x80000000000020c0, 0x434d5f53505f5357, 0x0000000000000000); - convert(0x80000000000020d0, 0x0000000000002400, 0x0000000000000400); - convert(0x80000000000020e0, 0x0000000000000001, 0x0000000000000000); - convert(0x80000000000020f0, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002100, 0x434d5f53505f5357, 0x0000000000040000); - convert(0x8000000000002110, 0x0000000000000000, 0xffffffffffffffff); - convert(0x8000000000002120, 0x0000000000000001, 0x0000000000000000); - convert(0x8000000000002130, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002140, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002150, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002160, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002170, 0x0000000000000000, 0x0000000000000000); - convert(0x8000000000002180, 0x434d5f53505f5357, 0x0000000000020000); - convert(0x8000000000002190, 0x0000000000000000, 0x0000000000010000); - convert(0x80000000000021a0, 0x0000000000000001, 0x0000000000000000); - /* - * klconfig entries initialization - mankato - */ - convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000); - convert(0x0000000000030010, 0x0003007000000018, 0x800002000f820178); - convert(0x0000000000030020, 0x80000a000f024000, 0x800002000f800000); - convert(0x0000000000030030, 0x0300fafa00012580, 0x00000000040f0000); - convert(0x0000000000030040, 0x0000000000000000, 0x0003097000030070); - convert(0x0000000000030050, 0x00030970000303b0, 0x0003181000033f70); - convert(0x0000000000030060, 0x0003d51000037570, 0x0000000000038330); - convert(0x0000000000030070, 0x0203110100030140, 0x0001000000000101); - convert(0x0000000000030080, 0x0900000000000000, 0x000000004e465e67); - convert(0x0000000000030090, 0x0003097000000000, 0x00030b1000030a40); - convert(0x00000000000300a0, 0x00030cb000030be0, 0x000315a0000314d0); - convert(0x00000000000300b0, 0x0003174000031670, 0x0000000000000000); - convert(0x0000000000030100, 0x000000000000001a, 0x3350490000000000); - convert(0x0000000000030110, 0x0000000000000037, 0x0000000000000000); - convert(0x0000000000030140, 0x0002420100030210, 0x0001000000000101); - convert(0x0000000000030150, 0x0100000000000000, 0xffffffffffffffff); - convert(0x0000000000030160, 0x00030d8000000000, 0x0000000000030e50); - convert(0x00000000000301c0, 0x0000000000000000, 0x0000000000030070); - convert(0x00000000000301d0, 0x0000000000000025, 0x424f490000000000); - convert(0x00000000000301e0, 0x000000004b434952, 0x0000000000000000); - convert(0x0000000000030210, 0x00027101000302e0, 0x00010000000e4101); - convert(0x0000000000030220, 0x0200000000000000, 0xffffffffffffffff); - convert(0x0000000000030230, 0x00030f2000000000, 0x0000000000030ff0); - convert(0x0000000000030290, 0x0000000000000000, 0x0000000000030140); - convert(0x00000000000302a0, 0x0000000000000026, 0x7262490000000000); - convert(0x00000000000302b0, 0x00000000006b6369, 0x0000000000000000); - convert(0x00000000000302e0, 0x0002710100000000, 0x00010000000f3101); - convert(0x00000000000302f0, 0x0500000000000000, 0xffffffffffffffff); - convert(0x0000000000030300, 0x000310c000000000, 0x0003126000031190); - convert(0x0000000000030310, 0x0003140000031330, 0x0000000000000000); - convert(0x0000000000030360, 0x0000000000000000, 0x0000000000030140); - convert(0x0000000000030370, 0x0000000000000029, 0x7262490000000000); - convert(0x0000000000030380, 0x00000000006b6369, 0x0000000000000000); - convert(0x0000000000030970, 0x0000000002010102, 0x0000000000000000); - convert(0x0000000000030980, 0x000000004e465e67, 0xffffffff00000000); - /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ - convert(0x00000000000309a0, 0x0000000000037570, 0xffffffff00000000); - convert(0x00000000000309b0, 0x0000000000030070, 0x0000000000000000); - convert(0x00000000000309c0, 0x000000000003f420, 0x0000000000000000); - convert(0x0000000000030a40, 0x0000000002010125, 0x0000000000000000); - convert(0x0000000000030a50, 0xffffffffffffffff, 0xffffffff00000000); - convert(0x0000000000030a70, 0x0000000000037b78, 0x0000000000000000); - convert(0x0000000000030b10, 0x0000000002010125, 0x0000000000000000); - convert(0x0000000000030b20, 0xffffffffffffffff, 0xffffffff00000000); - convert(0x0000000000030b40, 0x0000000000037d30, 0x0000000000000001); - convert(0x0000000000030be0, 0x00000000ff010203, 0x0000000000000000); - convert(0x0000000000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); - convert(0x0000000000030c10, 0x0000000000037ee8, 0x0100010000000200); - convert(0x0000000000030cb0, 0x00000000ff310111, 0x0000000000000000); - convert(0x0000000000030cc0, 0xffffffffffffffff, 0x0000000000000000); - convert(0x0000000000030d80, 0x0000000002010104, 0x0000000000000000); - convert(0x0000000000030d90, 0xffffffffffffffff, 0x00000000000000ff); - convert(0x0000000000030db0, 0x0000000000037f18, 0x0000000000000000); - convert(0x0000000000030dc0, 0x0000000000000000, 0x0003007000060000); - convert(0x0000000000030de0, 0x0000000000000000, 0x0003021000050000); - convert(0x0000000000030df0, 0x000302e000050000, 0x0000000000000000); - convert(0x0000000000030e30, 0x0000000000000000, 0x000000000000000a); - convert(0x0000000000030e50, 0x00000000ff00011a, 0x0000000000000000); - convert(0x0000000000030e60, 0xffffffffffffffff, 0x0000000000000000); - convert(0x0000000000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); - convert(0x0000000000030e90, 0x000000000000bc6e, 0x0000000000000000); - convert(0x0000000000030f20, 0x0000000002010205, 0x00000000d0020000); - convert(0x0000000000030f30, 0xffffffffffffffff, 0x0000000e0000000e); - convert(0x0000000000030f40, 0x000000000000000e, 0x0000000000000000); - convert(0x0000000000030f50, 0x0000000000038010, 0x00000000000007ff); - convert(0x0000000000030f70, 0x0000000000000000, 0x0000000022001077); - convert(0x0000000000030fa0, 0x0000000000000000, 0x000000000003f4a8); - convert(0x0000000000030ff0, 0x0000000000310120, 0x0000000000000000); - convert(0x0000000000031000, 0xffffffffffffffff, 0xffffffff00000002); - convert(0x0000000000031010, 0x000000000000000e, 0x0000000000000000); - convert(0x0000000000031020, 0x0000000000038088, 0x0000000000000000); - convert(0x00000000000310c0, 0x0000000002010205, 0x00000000d0020000); - convert(0x00000000000310d0, 0xffffffffffffffff, 0x0000000f0000000f); - convert(0x00000000000310e0, 0x000000000000000f, 0x0000000000000000); - convert(0x00000000000310f0, 0x00000000000380b8, 0x00000000000007ff); - convert(0x0000000000031120, 0x0000000022001077, 0x00000000000310a9); - convert(0x0000000000031130, 0x00000000580211c1, 0x000000008009104c); - convert(0x0000000000031140, 0x0000000000000000, 0x000000000003f4c0); - convert(0x0000000000031190, 0x0000000000310120, 0x0000000000000000); - convert(0x00000000000311a0, 0xffffffffffffffff, 0xffffffff00000003); - convert(0x00000000000311b0, 0x000000000000000f, 0x0000000000000000); - convert(0x00000000000311c0, 0x0000000000038130, 0x0000000000000000); - convert(0x0000000000031260, 0x0000000000110106, 0x0000000000000000); - convert(0x0000000000031270, 0xffffffffffffffff, 0xffffffff00000004); - convert(0x0000000000031280, 0x000000000000000f, 0x0000000000000000); - convert(0x00000000000312a0, 0x00000000ff110013, 0x0000000000000000); - convert(0x00000000000312b0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0x00000000000312c0, 0x000000000000000f, 0x0000000000000000); - convert(0x00000000000312e0, 0x0000000000110012, 0x0000000000000000); - convert(0x00000000000312f0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0x0000000000031300, 0x000000000000000f, 0x0000000000000000); - convert(0x0000000000031310, 0x0000000000038160, 0x0000000000000000); - convert(0x0000000000031330, 0x00000000ff310122, 0x0000000000000000); - convert(0x0000000000031340, 0xffffffffffffffff, 0xffffffff00000005); - convert(0x0000000000031350, 0x000000000000000f, 0x0000000000000000); - convert(0x0000000000031360, 0x0000000000038190, 0x0000000000000000); - convert(0x0000000000031400, 0x0000000000310121, 0x0000000000000000); - convert(0x0000000000031400, 0x0000000000310121, 0x0000000000000000); - convert(0x0000000000031410, 0xffffffffffffffff, 0xffffffff00000006); - convert(0x0000000000031420, 0x000000000000000f, 0x0000000000000000); - convert(0x0000000000031430, 0x00000000000381c0, 0x0000000000000000); - convert(0x00000000000314d0, 0x00000000ff010201, 0x0000000000000000); - convert(0x00000000000314e0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0x0000000000031500, 0x00000000000381f0, 0x000030430000ffff); - convert(0x0000000000031510, 0x000000000000ffff, 0x0000000000000000); - convert(0x00000000000315a0, 0x00000020ff000201, 0x0000000000000000); - convert(0x00000000000315b0, 0xffffffffffffffff, 0xffffffff00000001); - convert(0x00000000000315d0, 0x0000000000038240, 0x00003f3f0000ffff); - convert(0x00000000000315e0, 0x000000000000ffff, 0x0000000000000000); - convert(0x0000000000031670, 0x00000000ff010201, 0x0000000000000000); - convert(0x0000000000031680, 0xffffffffffffffff, 0x0000000100000002); - convert(0x00000000000316a0, 0x0000000000038290, 0x000030430000ffff); - convert(0x00000000000316b0, 0x000000000000ffff, 0x0000000000000000); - convert(0x0000000000031740, 0x00000020ff000201, 0x0000000000000000); - convert(0x0000000000031750, 0xffffffffffffffff, 0x0000000500000003); - convert(0x0000000000031770, 0x00000000000382e0, 0x00003f3f0000ffff); - convert(0x0000000000031780, 0x000000000000ffff, 0x0000000000000000); - - /* - * GDA initialization - mankato - */ - convert(0x8000000000002400, 0x0000000258464552, 0x000000000ead0000); - convert(0x8000000000002480, 0xffffffff00010000, 0xffffffffffffffff); - convert(0x8000000000002490, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024a0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024b0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024c0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024d0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024e0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x80000000000024f0, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002500, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002510, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002520, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002530, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002540, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002550, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002560, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002570, 0xffffffffffffffff, 0xffffffffffffffff); - convert(0x8000000000002580, 0x000000000000ffff, 0x0000000000000000); -#endif - + /* + * klconfig entries initialization - mankato + */ + convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000); + convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178); + convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000); + convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000); + convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070); + convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70); + convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330); + convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101); + convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67); + convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40); + convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0); + convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000); + convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000); + convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000); + convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101); + convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff); + convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50); + convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070); + convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000); + convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000); + convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101); + convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff); + convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0); + convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140); + convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000); + convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000); + convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101); + convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff); + convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190); + convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000); + convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140); + convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000); + convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000); + convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000); + convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000); + /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ + convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000); + convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000); + convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000); + convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000); + convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000); + convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000); + convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001); + convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000); + convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); + convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200); + convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000); + convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000); + convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000); + convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff); + convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000); + convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000); + convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000); + convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000); + convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a); + convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000); + convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000); + convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); + convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000); + convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000); + convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e); + convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000); + convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff); + convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077); + convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8); + convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000); + convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002); + convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000); + convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000); + convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000); + convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f); + convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff); + convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9); + convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c); + convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0); + convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000); + convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003); + convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000); + convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000); + convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); + convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); + convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000); + convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000); + convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000); + convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000); + convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000); + convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005); + convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000); + convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); + convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); + convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006); + convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000); + convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000); + convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000); + convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000); + convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff); + convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000); + convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000); + convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001); + convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff); + convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000); + convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000); + convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002); + convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff); + convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000); + convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000); + convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003); + convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff); + convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000); } - diff -Nru a/arch/ia64/sn/fakeprom/main.c b/arch/ia64/sn/fakeprom/main.c --- a/arch/ia64/sn/fakeprom/main.c Tue Dec 3 10:07:22 2002 +++ b/arch/ia64/sn/fakeprom/main.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -33,25 +33,9 @@ * First lets figure out who we are. This is done from the * LID passed to us. */ - -#ifdef CONFIG_IA64_SGI_SN1 - nasid = (lid>>24); - syn = (lid>>17)&1; - cpu = (lid>>16)&1; - - /* - * Now pick a synergy master to initialize synergy registers. - */ - if (test_and_set_bit(syn, &nasidmaster[nasid]) == 0) { - synergy_init(nasid, syn); - test_and_set_bit(syn+2, &nasidmaster[nasid]); - } else - while (get_bit(syn+2, &nasidmaster[nasid]) == 0); -#else nasid = (lid>>16)&0xfff; cpu = (lid>>28)&3; syn = 0; -#endif /* * Now pick a nasid master to initialize Bedrock registers. diff -Nru a/arch/ia64/sn/fakeprom/make_textsym b/arch/ia64/sn/fakeprom/make_textsym --- a/arch/ia64/sn/fakeprom/make_textsym Tue Mar 18 07:58:23 2003 +++ b/arch/ia64/sn/fakeprom/make_textsym Fri May 16 04:18:17 2003 @@ -7,7 +7,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. +# Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. # help() { @@ -37,6 +37,7 @@ done shift `expr $OPTIND - 1` +#OBJDUMP=/usr/bin/ia64-linux-objdump LINUX=${1:-vmlinux} TEXTSYM=${2:-${LINUX}.sym} TMPSYM=${2:-${LINUX}.sym.tmp} @@ -130,6 +131,8 @@ awk ' +/ _start$/ {start=1} +/ start_ap$/ {start=1} /__start_gate_section/ {start=1} /^'${dataprefix}\|${textprefix}'/ { if ($4 == ".kdb") @@ -142,7 +145,7 @@ n = 0 s = $(NF-1) while (length(s) > 0) { - n = n*16 + substr(s,1,1) + n = n*16 + (index("0123456789abcdef", substr(s,1,1)) - 1) s = substr(s,2) } printf "GLOBAL | %s | DATA | %s | %d\n", $1, $NF, n diff -Nru a/arch/ia64/sn/io/Makefile b/arch/ia64/sn/io/Makefile --- a/arch/ia64/sn/io/Makefile Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/io/Makefile Fri May 23 03:37:14 2003 @@ -11,16 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -ifdef CONFIG_IA64_SGI_SN2 -EXTRA_CFLAGS += -DSHUB_SWAP_WAR -endif - -obj-$(CONFIG_IA64_SGI_SN) += stubs.o sgi_if.o xswitch.o klgraph_hack.o \ - hcl.o labelcl.o invent.o sgi_io_sim.o \ - klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \ - alenlist.o pci.o pci_dma.o ate_utils.o \ - ifconfig_net.o io.o ioconfig_bus.o - -obj-$(CONFIG_IA64_SGI_SN2) += sn2/ - -obj-$(CONFIG_PCIBA) += pciba.o +obj-y += sgi_if.o xswitch.o sgi_io_sim.o cdl.o ate_utils.o \ + io.o machvec/ drivers/ platform_init/ sn2/ hwgfs/ diff -Nru a/arch/ia64/sn/io/alenlist.c b/arch/ia64/sn/io/alenlist.c --- a/arch/ia64/sn/io/alenlist.c Tue Dec 3 10:07:22 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,899 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* Implementation of Address/Length Lists. */ - - -#include -#include -#include -#include -#include - -/* - * Logically, an Address/Length List is a list of Pairs, where each pair - * holds an Address and a Length, all in some Address Space. In this - * context, "Address Space" is a particular Crosstalk Widget address - * space, a PCI device address space, a VME bus address space, a - * physical memory address space, etc. - * - * The main use for these Lists is to provide a single mechanism that - * describes where in an address space a DMA occurs. This allows the - * various I/O Bus support layers to provide a single interface for - * DMA mapping and DMA translation without regard to how the DMA target - * was specified by upper layers. The upper layers commonly specify a - * DMA target via a buf structure page list, a kernel virtual address, - * a user virtual address, a vector of addresses (a la uio and iov), - * or possibly a pfn list. - * - * Address/Length Lists also enable drivers to take advantage of their - * inate scatter/gather capabilities in systems where some address - * translation may be required between bus adapters. The driver forms - * a List that represents physical memory targets. This list is passed - * to the various adapters, which apply various translations. The final - * list that's returned to the driver is in terms of its local address - * address space -- addresses which can be passed off to a scatter/gather - * capable DMA controller. - * - * The current implementation is intended to be useful both in kernels - * that support interrupt threads (INTR_KTHREAD) and in systems that do - * not support interrupt threads. Of course, in the latter case, some - * interfaces can be called only within a suspendable context. - * - * Basic operations on Address/Length Lists include: - * alenlist_create Create a list - * alenlist_clear Clear a list - * alenlist_destroy Destroy a list - * alenlist_append Append a Pair to the end of a list - * alenlist_replace Replace a Pair in the middle of a list - * alenlist_get Get an Address/Length Pair from a list - * alenlist_size Return the number of Pairs in a list - * alenlist_concat Append one list to the end of another - * alenlist_clone Create a new copy of a list - * - * Operations that convert from upper-level specifications to Address/ - * Length Lists currently include: - * kvaddr_to_alenlist Convert from a kernel virtual address - * uvaddr_to_alenlist Convert from a user virtual address - * buf_to_alenlist Convert from a buf structure - * alenlist_done Tell system that we're done with an alenlist - * obtained from a conversion. - * Additional convenience operations: - * alenpair_init Create a list and initialize it with a Pair - * alenpair_get Peek at the first pair on a List - * - * A supporting type for Address/Length Lists is an alenlist_cursor_t. A - * cursor marks a position in a List, and determines which Pair is fetched - * by alenlist_get. - * alenlist_cursor_create Allocate and initialize a cursor - * alenlist_cursor_destroy Free space consumed by a cursor - * alenlist_cursor_init (Re-)Initialize a cursor to point - * to the start of a list - * alenlist_cursor_clone Clone a cursor (at the current offset) - * alenlist_cursor_offset Return the number of bytes into - * a list that this cursor marks - * Multiple cursors can point at various points into a List. Also, each - * list maintains one "internal cursor" which may be updated by alenlist_clear - * and alenlist_get. If calling code simply wishes to scan sequentially - * through a list starting at the beginning, and if it is the only user of - * a list, it can rely on this internal cursor rather than managing a - * separate explicit cursor. - * - * The current implementation allows callers to allocate both cursors and - * the lists as local stack (structure) variables. This allows for some - * extra efficiency at the expense of forward binary compatibility. It - * is recommended that customer drivers refrain from local allocation. - * In fact, we likely will choose to move the structures out of the public - * header file into a private place in order to discourage this usage. - * - * Currently, no locking is provided by the alenlist implementation. - * - * Implementation notes: - * For efficiency, Pairs are grouped into "chunks" of, say, 32 Pairs - * and a List consists of some number of these chunks. Chunks are completely - * invisible to calling code. Chunks should be large enough to hold most - * standard-sized DMA's, but not so large that they consume excessive space. - * - * It is generally expected that Lists will be constructed at one time and - * scanned at a later time. It is NOT expected that drivers will scan - * a List while the List is simultaneously extended, although this is - * theoretically possible with sufficient upper-level locking. - * - * In order to support demands of Real-Time drivers and in order to support - * swapping under low-memory conditions, we support the concept of a - * "pre-allocated fixed-sized List". After creating a List with - * alenlist_create, a driver may explicitly grow the list (via "alenlist_grow") - * to a specific number of Address/Length pairs. It is guaranteed that future - * operations involving this list will never automatically grow the list - * (i.e. if growth is ever required, the operation will fail). Additionally, - * operations that use alenlist's (e.g. DMA operations) accept a flag which - * causes processing to take place "in-situ"; that is, the input alenlist - * entries are replaced with output alenlist entries. The combination of - * pre-allocated Lists and in-situ processing allows us to avoid the - * potential deadlock scenario where we sleep (waiting for memory) in the - * swap out path. - * - * For debugging, we track the number of allocated Lists in alenlist_count - * the number of allocated chunks in alenlist_chunk_count, and the number - * of allocate cursors in alenlist_cursor_count. We also provide a debug - * routine, alenlist_show, which dumps the contents of an Address/Length List. - * - * Currently, Lists are formed by drivers on-demand. Eventually, we may - * associate an alenlist with a buf structure and keep it up to date as - * we go along. In that case, buf_to_alenlist simply returns a pointer - * to the existing List, and increments the Lists's reference count. - * alenlist_done would decrement the reference count and destroys the List - * if it was the last reference. - * - * Eventually alenlist's may allow better support for user-level scatter/ - * gather operations (e.g. via readv/writev): With proper support, we - * could potentially handle a vector of reads with a single scatter/gather - * DMA operation. This could be especially useful on NUMA systems where - * there's more of a reason for users to use vector I/O operations. - * - * Eventually, alenlist's may replace kaio lists, vhand page lists, - * buffer cache pfdat lists, DMA page lists, etc. - */ - -/* Opaque data types */ - -/* An Address/Length pair. */ -typedef struct alen_s { - alenaddr_t al_addr; - size_t al_length; -} alen_t; - -/* - * Number of elements in one chunk of an Address/Length List. - * - * This size should be sufficient to hold at least an "average" size - * DMA request. Must be at least 1, and should be a power of 2, - * for efficiency. - */ -#define ALEN_CHUNK_SZ ((512*1024)/NBPP) - -/* - * A fixed-size set of Address/Length Pairs. Chunks of Pairs are strung together - * to form a complete Address/Length List. Chunking is entirely hidden within the - * alenlist implementation, and it simply makes allocation and growth of lists more - * efficient. - */ -typedef struct alenlist_chunk_s { - alen_t alc_pair[ALEN_CHUNK_SZ];/* list of addr/len pairs */ - struct alenlist_chunk_s *alc_next; /* point to next chunk of pairs */ -} *alenlist_chunk_t; - -/* - * An Address/Length List. An Address/Length List is allocated with alenlist_create. - * Alternatively, a list can be allocated on the stack (local variable of type - * alenlist_t) and initialized with alenpair_init or with a combination of - * alenlist_clear and alenlist_append, etc. Code which statically allocates these - * structures loses forward binary compatibility! - * - * A statically allocated List is sufficiently large to hold ALEN_CHUNK_SZ pairs. - */ -struct alenlist_s { - unsigned short al_flags; - unsigned short al_logical_size; /* logical size of list, in pairs */ - unsigned short al_actual_size; /* actual size of list, in pairs */ - struct alenlist_chunk_s *al_last_chunk; /* pointer to last logical chunk */ - struct alenlist_cursor_s al_cursor; /* internal cursor */ - struct alenlist_chunk_s al_chunk; /* initial set of pairs */ - alenaddr_t al_compaction_address; /* used to compact pairs */ -}; - -/* al_flags field */ -#define AL_FIXED_SIZE 0x1 /* List is pre-allocated, and of fixed size */ - - -struct zone *alenlist_zone = NULL; -struct zone *alenlist_chunk_zone = NULL; -struct zone *alenlist_cursor_zone = NULL; - -#if DEBUG -int alenlist_count=0; /* Currently allocated Lists */ -int alenlist_chunk_count = 0; /* Currently allocated chunks */ -int alenlist_cursor_count = 0; /* Currently allocate cursors */ -#define INCR_COUNT(ptr) atomic_inc((ptr)); -#define DECR_COUNT(ptr) atomic_dec((ptr)); -#else -#define INCR_COUNT(ptr) -#define DECR_COUNT(ptr) -#endif /* DEBUG */ - -#if DEBUG -static void alenlist_show(alenlist_t); -#endif /* DEBUG */ - -/* - * Initialize Address/Length List management. One time initialization. - */ -void -alenlist_init(void) -{ - alenlist_zone = snia_kmem_zone_init(sizeof(struct alenlist_s), "alenlist"); - alenlist_chunk_zone = snia_kmem_zone_init(sizeof(struct alenlist_chunk_s), "alchunk"); - alenlist_cursor_zone = snia_kmem_zone_init(sizeof(struct alenlist_cursor_s), "alcursor"); -#if DEBUG - idbg_addfunc("alenshow", alenlist_show); -#endif /* DEBUG */ -} - - -/* - * Initialize an Address/Length List cursor. - */ -static void -do_cursor_init(alenlist_t alenlist, alenlist_cursor_t cursorp) -{ - cursorp->al_alenlist = alenlist; - cursorp->al_offset = 0; - cursorp->al_chunk = &alenlist->al_chunk; - cursorp->al_index = 0; - cursorp->al_bcount = 0; -} - - -/* - * Create an Address/Length List, and clear it. - * Set the cursor to the beginning. - */ -alenlist_t -alenlist_create(unsigned flags) -{ - alenlist_t alenlist; - - alenlist = snia_kmem_zone_alloc(alenlist_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - if (alenlist) { - INCR_COUNT(&alenlist_count); - - alenlist->al_flags = 0; - alenlist->al_logical_size = 0; - alenlist->al_actual_size = ALEN_CHUNK_SZ; - alenlist->al_last_chunk = &alenlist->al_chunk; - alenlist->al_chunk.alc_next = NULL; - do_cursor_init(alenlist, &alenlist->al_cursor); - } - - return(alenlist); -} - - -/* - * Grow an Address/Length List so that all resources needed to contain - * the specified number of Pairs are pre-allocated. An Address/Length - * List that has been explicitly "grown" will never *automatically* - * grow, shrink, or be destroyed. - * - * Pre-allocation is useful for Real-Time drivers and for drivers that - * may be used along the swap-out path and therefore cannot afford to - * sleep until memory is freed. - * - * The cursor is set to the beginning of the list. - */ -int -alenlist_grow(alenlist_t alenlist, size_t npairs) -{ - /* - * This interface should be used relatively rarely, so - * the implementation is kept simple: We clear the List, - * then append npairs bogus entries. Finally, we mark - * the list as FIXED_SIZE and re-initialize the internal - * cursor. - */ - - /* - * Temporarily mark as non-fixed size, since we're about - * to shrink and expand it. - */ - alenlist->al_flags &= ~AL_FIXED_SIZE; - - /* Free whatever was in the alenlist. */ - alenlist_clear(alenlist); - - /* Allocate everything that we need via automatic expansion. */ - while (npairs--) - if (alenlist_append(alenlist, 0, 0, AL_NOCOMPACT) == ALENLIST_FAILURE) - return(ALENLIST_FAILURE); - - /* Now, mark as FIXED_SIZE */ - alenlist->al_flags |= AL_FIXED_SIZE; - - /* Clear out bogus entries */ - alenlist_clear(alenlist); - - /* Initialize internal cursor to the beginning */ - do_cursor_init(alenlist, &alenlist->al_cursor); - - return(ALENLIST_SUCCESS); -} - - -/* - * Clear an Address/Length List so that it holds no pairs. - */ -void -alenlist_clear(alenlist_t alenlist) -{ - alenlist_chunk_t chunk, freechunk; - - /* - * If this List is not FIXED_SIZE, free all the - * extra chunks. - */ - if (!(alenlist->al_flags & AL_FIXED_SIZE)) { - /* First, free any extension alenlist chunks */ - chunk = alenlist->al_chunk.alc_next; - while (chunk) { - freechunk = chunk; - chunk = chunk->alc_next; - snia_kmem_zone_free(alenlist_chunk_zone, freechunk); - DECR_COUNT(&alenlist_chunk_count); - } - alenlist->al_actual_size = ALEN_CHUNK_SZ; - alenlist->al_chunk.alc_next = NULL; - } - - alenlist->al_logical_size = 0; - alenlist->al_last_chunk = &alenlist->al_chunk; - do_cursor_init(alenlist, &alenlist->al_cursor); -} - - -/* - * Create and initialize an Address/Length Pair. - * This is intended for degenerate lists, consisting of a single - * address/length pair. - */ -alenlist_t -alenpair_init( alenaddr_t address, - size_t length) -{ - alenlist_t alenlist; - - alenlist = alenlist_create(0); - - alenlist->al_logical_size = 1; - ASSERT(alenlist->al_last_chunk == &alenlist->al_chunk); - alenlist->al_chunk.alc_pair[0].al_length = length; - alenlist->al_chunk.alc_pair[0].al_addr = address; - - return(alenlist); -} - -/* - * Return address/length from a degenerate (1-pair) List, or - * first pair from a larger list. Does NOT update the internal cursor, - * so this is an easy way to peek at a start address. - */ -int -alenpair_get( alenlist_t alenlist, - alenaddr_t *address, - size_t *length) -{ - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - - *length = alenlist->al_chunk.alc_pair[0].al_length; - *address = alenlist->al_chunk.alc_pair[0].al_addr; - return(ALENLIST_SUCCESS); -} - - -/* - * Destroy an Address/Length List. - */ -void -alenlist_destroy(alenlist_t alenlist) -{ - if (alenlist == NULL) - return; - - /* - * Turn off FIXED_SIZE so this List can be - * automatically shrunk. - */ - alenlist->al_flags &= ~AL_FIXED_SIZE; - - /* Free extension chunks first */ - if (alenlist->al_chunk.alc_next) - alenlist_clear(alenlist); - - /* Now, free the alenlist itself */ - snia_kmem_zone_free(alenlist_zone, alenlist); - DECR_COUNT(&alenlist_count); -} - -/* - * Release an Address/Length List. - * This is in preparation for a day when alenlist's may be longer-lived, and - * perhaps associated with a buf structure. We'd add a reference count, and - * this routine would decrement the count. For now, we create alenlist's on - * on demand and free them when done. If the driver is not explicitly managing - * a List for its own use, it should call alenlist_done rather than alenlist_destroy. - */ -void -alenlist_done(alenlist_t alenlist) -{ - alenlist_destroy(alenlist); -} - - -/* - * Append another address/length to the end of an Address/Length List, - * growing the list if permitted and necessary. - * - * Returns: SUCCESS/FAILURE - */ -int -alenlist_append( alenlist_t alenlist, /* append to this list */ - alenaddr_t address, /* address to append */ - size_t length, /* length to append */ - unsigned flags) -{ - alen_t *alenp; - int index, last_index; - - index = alenlist->al_logical_size % ALEN_CHUNK_SZ; - - if ((alenlist->al_logical_size > 0)) { - /* - * See if we can compact this new pair in with the previous entry. - * al_compaction_address holds that value that we'd need to see - * in order to compact. - */ - if (!(flags & AL_NOCOMPACT) && - (alenlist->al_compaction_address == address)) { - last_index = (alenlist->al_logical_size-1) % ALEN_CHUNK_SZ; - alenp = &(alenlist->al_last_chunk->alc_pair[last_index]); - alenp->al_length += length; - alenlist->al_compaction_address += length; - return(ALENLIST_SUCCESS); - } - - /* - * If we're out of room in this chunk, move to a new chunk. - */ - if (index == 0) { - if (alenlist->al_flags & AL_FIXED_SIZE) { - alenlist->al_last_chunk = alenlist->al_last_chunk->alc_next; - - /* If we're out of space in a FIXED_SIZE List, quit. */ - if (alenlist->al_last_chunk == NULL) { - ASSERT(alenlist->al_logical_size == alenlist->al_actual_size); - return(ALENLIST_FAILURE); - } - } else { - alenlist_chunk_t new_chunk; - - new_chunk = snia_kmem_zone_alloc(alenlist_chunk_zone, - flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - - if (new_chunk == NULL) - return(ALENLIST_FAILURE); - - alenlist->al_last_chunk->alc_next = new_chunk; - new_chunk->alc_next = NULL; - alenlist->al_last_chunk = new_chunk; - alenlist->al_actual_size += ALEN_CHUNK_SZ; - INCR_COUNT(&alenlist_chunk_count); - } - } - } - - alenp = &(alenlist->al_last_chunk->alc_pair[index]); - alenp->al_addr = address; - alenp->al_length = length; - - alenlist->al_logical_size++; - alenlist->al_compaction_address = address + length; - - return(ALENLIST_SUCCESS); -} - - -/* - * Replace an item in an Address/Length List. Cursor is updated so - * that alenlist_get will get the next item in the list. This interface - * is not very useful for drivers; but it is useful to bus providers - * that need to translate between address spaced in situ. The old Address - * and Length are returned. - */ -/* ARGSUSED */ -int -alenlist_replace( alenlist_t alenlist, /* in: replace in this list */ - alenlist_cursor_t cursorp, /* inout: which item to replace */ - alenaddr_t *addrp, /* inout: address */ - size_t *lengthp, /* inout: length */ - unsigned flags) -{ - alen_t *alenp; - alenlist_chunk_t chunk; - unsigned int index; - size_t length; - alenaddr_t addr; - - if ((addrp == NULL) || (lengthp == NULL)) - return(ALENLIST_FAILURE); - - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - - addr = *addrp; - length = *lengthp; - - /* - * If no cursor explicitly specified, use the Address/Length List's - * internal cursor. - */ - if (cursorp == NULL) - cursorp = &alenlist->al_cursor; - - chunk = cursorp->al_chunk; - index = cursorp->al_index; - - ASSERT(cursorp->al_alenlist == alenlist); - if (cursorp->al_alenlist != alenlist) - return(ALENLIST_FAILURE); - - alenp = &chunk->alc_pair[index]; - - /* Return old values */ - *addrp = alenp->al_length; - *lengthp = alenp->al_addr; - - /* Set up new values */ - alenp->al_length = length; - alenp->al_addr = addr; - - /* Update cursor to point to next item */ - cursorp->al_bcount = length; - - return(ALENLIST_SUCCESS); -} - - -/* - * Initialize a cursor in order to walk an alenlist. - * An alenlist_cursor always points to the last thing that was obtained - * from the list. If al_chunk is NULL, then nothing has yet been obtained. - * - * Note: There is an "internal cursor" associated with every Address/Length List. - * For users that scan sequentially through a List, it is more efficient to - * simply use the internal cursor. The caller must insure that no other users - * will simultaneously scan the List. The caller can reposition the internal - * cursor by calling alenlist_cursor_init with a NULL cursorp. - */ -int -alenlist_cursor_init(alenlist_t alenlist, size_t offset, alenlist_cursor_t cursorp) -{ - size_t byte_count; - - if (cursorp == NULL) - cursorp = &alenlist->al_cursor; - - /* Get internal cursor's byte count for use as a hint. - * - * If the internal cursor points passed the point that we're interested in, - * we need to seek forward from the beginning. Otherwise, we can seek forward - * from the internal cursor. - */ - if ((offset > 0) && - ((byte_count = alenlist_cursor_offset(alenlist, (alenlist_cursor_t)NULL)) <= offset)) { - offset -= byte_count; - alenlist_cursor_clone(alenlist, NULL, cursorp); - } else - do_cursor_init(alenlist, cursorp); - - /* We could easily speed this up, but it shouldn't be used very often. */ - while (offset != 0) { - alenaddr_t addr; - size_t length; - - if (alenlist_get(alenlist, cursorp, offset, &addr, &length, 0) != ALENLIST_SUCCESS) - return(ALENLIST_FAILURE); - offset -= length; - } - return(ALENLIST_SUCCESS); -} - - -/* - * Copy a cursor. The source cursor is either an internal alenlist cursor - * or an explicit cursor. - */ -int -alenlist_cursor_clone( alenlist_t alenlist, - alenlist_cursor_t cursorp_in, - alenlist_cursor_t cursorp_out) -{ - ASSERT(cursorp_out); - - if (alenlist && cursorp_in) - if (alenlist != cursorp_in->al_alenlist) - return(ALENLIST_FAILURE); - - if (alenlist) - *cursorp_out = alenlist->al_cursor; /* small structure copy */ - else if (cursorp_in) - *cursorp_out = *cursorp_in; /* small structure copy */ - else - return(ALENLIST_FAILURE); /* no source */ - - return(ALENLIST_SUCCESS); -} - -/* - * Return the number of bytes passed so far according to the specified cursor. - * If cursorp is NULL, use the alenlist's internal cursor. - */ -size_t -alenlist_cursor_offset(alenlist_t alenlist, alenlist_cursor_t cursorp) -{ - ASSERT(!alenlist || !cursorp || (alenlist == cursorp->al_alenlist)); - - if (cursorp == NULL) { - ASSERT(alenlist); - cursorp = &alenlist->al_cursor; - } - - return(cursorp->al_offset); -} - -/* - * Allocate and initialize an Address/Length List cursor. - */ -alenlist_cursor_t -alenlist_cursor_create(alenlist_t alenlist, unsigned flags) -{ - alenlist_cursor_t cursorp; - - ASSERT(alenlist != NULL); - cursorp = snia_kmem_zone_alloc(alenlist_cursor_zone, flags & AL_NOSLEEP ? VM_NOSLEEP : 0); - if (cursorp) { - INCR_COUNT(&alenlist_cursor_count); - alenlist_cursor_init(alenlist, 0, cursorp); - } - return(cursorp); -} - -/* - * Free an Address/Length List cursor. - */ -void -alenlist_cursor_destroy(alenlist_cursor_t cursorp) -{ - DECR_COUNT(&alenlist_cursor_count); - snia_kmem_zone_free(alenlist_cursor_zone, cursorp); -} - - -/* - * Fetch an address/length pair from an Address/Length List. Update - * the "cursor" so that next time this routine is called, we'll get - * the next address range. Never return a length that exceeds maxlength - * (if non-zero). If maxlength is a power of 2, never return a length - * that crosses a maxlength boundary. [This may seem strange at first, - * but it's what many drivers want.] - * - * Returns: SUCCESS/FAILURE - */ -int -alenlist_get( alenlist_t alenlist, /* in: get from this list */ - alenlist_cursor_t cursorp, /* inout: which item to get */ - size_t maxlength, /* in: at most this length */ - alenaddr_t *addrp, /* out: address */ - size_t *lengthp, /* out: length */ - unsigned flags) -{ - alen_t *alenp; - alenlist_chunk_t chunk; - unsigned int index; - size_t bcount; - size_t length; - - /* - * If no cursor explicitly specified, use the Address/Length List's - * internal cursor. - */ - if (cursorp == NULL) { - if (alenlist->al_logical_size == 0) - return(ALENLIST_FAILURE); - cursorp = &alenlist->al_cursor; - } - - chunk = cursorp->al_chunk; - index = cursorp->al_index; - bcount = cursorp->al_bcount; - - ASSERT(cursorp->al_alenlist == alenlist); - if (cursorp->al_alenlist != alenlist) - return(ALENLIST_FAILURE); - - alenp = &chunk->alc_pair[index]; - length = alenp->al_length - bcount; - - /* Bump up to next pair, if we're done with this pair. */ - if (length == 0) { - cursorp->al_bcount = bcount = 0; - cursorp->al_index = index = (index + 1) % ALEN_CHUNK_SZ; - - /* Bump up to next chunk, if we're done with this chunk. */ - if (index == 0) { - if (cursorp->al_chunk == alenlist->al_last_chunk) - return(ALENLIST_FAILURE); - chunk = chunk->alc_next; - ASSERT(chunk != NULL); - } else { - /* If in last chunk, don't go beyond end. */ - if (cursorp->al_chunk == alenlist->al_last_chunk) { - int last_size = alenlist->al_logical_size % ALEN_CHUNK_SZ; - if (last_size && (index >= last_size)) - return(ALENLIST_FAILURE); - } - } - - alenp = &chunk->alc_pair[index]; - length = alenp->al_length; - } - - /* Constrain what we return according to maxlength */ - if (maxlength) { - size_t maxlen1 = maxlength - 1; - - if ((maxlength & maxlen1) == 0) /* power of 2 */ - maxlength -= - ((alenp->al_addr + cursorp->al_bcount) & maxlen1); - - length = min(maxlength, length); - } - - /* Update the cursor, if desired. */ - if (!(flags & AL_LEAVE_CURSOR)) { - cursorp->al_bcount += length; - cursorp->al_chunk = chunk; - } - - *lengthp = length; - *addrp = alenp->al_addr + bcount; - - return(ALENLIST_SUCCESS); -} - - -/* - * Return the number of pairs in the specified Address/Length List. - * (For FIXED_SIZE Lists, this returns the logical size of the List, - * not the actual capacity of the List.) - */ -int -alenlist_size(alenlist_t alenlist) -{ - return(alenlist->al_logical_size); -} - - -/* - * Concatenate two Address/Length Lists. - */ -void -alenlist_concat(alenlist_t from, - alenlist_t to) -{ - struct alenlist_cursor_s cursor; - alenaddr_t addr; - size_t length; - - alenlist_cursor_init(from, 0, &cursor); - - while(alenlist_get(from, &cursor, (size_t)0, &addr, &length, 0) == ALENLIST_SUCCESS) - alenlist_append(to, addr, length, 0); -} - -/* - * Create a copy of a list. - * (Not all attributes of the old list are cloned. For instance, if - * a FIXED_SIZE list is cloned, the resulting list is NOT FIXED_SIZE.) - */ -alenlist_t -alenlist_clone(alenlist_t old_list, unsigned flags) -{ - alenlist_t new_list; - - new_list = alenlist_create(flags); - if (new_list != NULL) - alenlist_concat(old_list, new_list); - - return(new_list); -} - - -/* - * Convert a kernel virtual address to a Physical Address/Length List. - */ -alenlist_t -kvaddr_to_alenlist(alenlist_t alenlist, caddr_t kvaddr, size_t length, unsigned flags) -{ - alenaddr_t paddr; - long offset; - size_t piece_length; - int created_alenlist; - - if (length <=0) - return(NULL); - - /* If caller supplied a List, use it. Otherwise, allocate one. */ - if (alenlist == NULL) { - alenlist = alenlist_create(0); - created_alenlist = 1; - } else { - alenlist_clear(alenlist); - created_alenlist = 0; - } - - paddr = kvtophys(kvaddr); - offset = poff(kvaddr); - - /* Handle first page */ - piece_length = min((size_t)(NBPP - offset), length); - if (alenlist_append(alenlist, paddr, piece_length, flags) == ALENLIST_FAILURE) - goto failure; - length -= piece_length; - kvaddr += piece_length; - - /* Handle middle pages */ - while (length >= NBPP) { - paddr = kvtophys(kvaddr); - if (alenlist_append(alenlist, paddr, NBPP, flags) == ALENLIST_FAILURE) - goto failure; - length -= NBPP; - kvaddr += NBPP; - } - - /* Handle last page */ - if (length) { - ASSERT(length < NBPP); - paddr = kvtophys(kvaddr); - if (alenlist_append(alenlist, paddr, length, flags) == ALENLIST_FAILURE) - goto failure; - } - - alenlist_cursor_init(alenlist, 0, NULL); - return(alenlist); - -failure: - if (created_alenlist) - alenlist_destroy(alenlist); - return(NULL); -} - - -#if DEBUG -static void -alenlist_show(alenlist_t alenlist) -{ - struct alenlist_cursor_s cursor; - alenaddr_t addr; - size_t length; - int i = 0; - - alenlist_cursor_init(alenlist, 0, &cursor); - - qprintf("Address/Length List@0x%x:\n", alenlist); - qprintf("logical size=0x%x actual size=0x%x last_chunk at 0x%x\n", - alenlist->al_logical_size, alenlist->al_actual_size, - alenlist->al_last_chunk); - qprintf("cursor: chunk=0x%x index=%d offset=0x%x\n", - alenlist->al_cursor.al_chunk, - alenlist->al_cursor.al_index, - alenlist->al_cursor.al_bcount); - while(alenlist_get(alenlist, &cursor, (size_t)0, &addr, &length, 0) == ALENLIST_SUCCESS) - qprintf("%d:\t0x%lx 0x%lx\n", ++i, addr, length); -} -#endif /* DEBUG */ diff -Nru a/arch/ia64/sn/io/ate_utils.c b/arch/ia64/sn/io/ate_utils.c --- a/arch/ia64/sn/io/ate_utils.c Tue Dec 3 10:07:22 2002 +++ b/arch/ia64/sn/io/ate_utils.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/ia64/sn/io/cdl.c b/arch/ia64/sn/io/cdl.c --- a/arch/ia64/sn/io/cdl.c Tue Dec 3 10:07:22 2002 +++ b/arch/ia64/sn/io/cdl.c Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -18,9 +18,9 @@ #include /* these get called directly in cdl_add_connpt in fops bypass hack */ -extern int pcibr_attach(devfs_handle_t); -extern int xbow_attach(devfs_handle_t); -extern int pic_attach(devfs_handle_t); +extern int pcibr_attach(vertex_hdl_t); +extern int xbow_attach(vertex_hdl_t); +extern int pic_attach(vertex_hdl_t); /* @@ -32,75 +32,20 @@ * IO Infrastructure Drivers e.g. pcibr. */ -struct cdl { - int part_num; - int mfg_num; - int (*attach) (devfs_handle_t); -} dummy_reg; - -#ifdef CONFIG_IA64_SGI_SN1 -#define MAX_SGI_IO_INFRA_DRVR 4 -#else #define MAX_SGI_IO_INFRA_DRVR 7 -#endif + static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = { { XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, { BRIDGE_WIDGET_PART_NUM, BRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops */}, -#ifndef CONFIG_IA64_SGI_SN1 { PIC_WIDGET_PART_NUM_BUS0, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, { PIC_WIDGET_PART_NUM_BUS1, PIC_WIDGET_MFGR_NUM, pic_attach /* &pic_fops */}, -#endif { XXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, { XBOW_WIDGET_PART_NUM, XBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, -#ifndef CONFIG_IA64_SGI_SN1 { PXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, -#endif }; /* - * cdl_new: Called by pciio and xtalk. - */ -cdl_p -cdl_new(char *name, char *k1str, char *k2str) -{ - /* - * Just return a dummy pointer. - */ - return((cdl_p)&dummy_reg); -} - -/* - * cdl_del: Do nothing. - */ -void -cdl_del(cdl_p reg) -{ - return; -} - -/* - * cdl_add_driver: The driver part number and manufacturers number - * are statically initialized above. - * - Do nothing. - */ -int -cdl_add_driver(cdl_p reg, int key1, int key2, char *prefix, int flags, cdl_drv_f *func) -{ - return 0; -} - -/* - * cdl_del_driver: Not supported. - */ -void -cdl_del_driver(cdl_p reg, char *prefix, cdl_drv_f *func) -{ - return; -} - -/* * cdl_add_connpt: We found a device and it's connect point. Call the * attach routine of that driver. * @@ -112,8 +57,8 @@ * vertices. */ int -cdl_add_connpt(cdl_p reg, int part_num, int mfg_num, - devfs_handle_t connpt, int drv_flags) +cdl_add_connpt(int part_num, int mfg_num, + vertex_hdl_t connpt, int drv_flags) { int i; @@ -121,7 +66,6 @@ * Find the driver entry point and call the attach routine. */ for (i = 0; i < MAX_SGI_IO_INFRA_DRVR; i++) { - if ( (part_num == sgi_infrastructure_drivers[i].part_num) && ( mfg_num == sgi_infrastructure_drivers[i].mfg_num) ) { /* @@ -139,73 +83,3 @@ return (0); } - -/* - * cdl_del_connpt: Not implemented. - */ -int -cdl_del_connpt(cdl_p reg, int key1, int key2, devfs_handle_t connpt, int drv_flags) -{ - - return(0); -} - -/* - * cdl_iterate: Not Implemented. - */ -void -cdl_iterate(cdl_p reg, - char *prefix, - cdl_iter_f * func) -{ - return; -} - -async_attach_t -async_attach_new(void) -{ - - return(0); -} - -void -async_attach_free(async_attach_t aa) -{ - return; -} - -async_attach_t -async_attach_get_info(devfs_handle_t vhdl) -{ - - return(0); -} - -void -async_attach_add_info(devfs_handle_t vhdl, async_attach_t aa) -{ - return; - -} - -void -async_attach_del_info(devfs_handle_t vhdl) -{ - return; -} - -void async_attach_signal_start(async_attach_t aa) -{ - return; -} - -void async_attach_signal_done(async_attach_t aa) -{ - return; -} - -void async_attach_waitall(async_attach_t aa) -{ - return; -} - diff -Nru a/arch/ia64/sn/io/drivers/Makefile b/arch/ia64/sn/io/drivers/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/drivers/Makefile Fri May 23 03:37:31 2003 @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += ioconfig_bus.o ifconfig_net.o diff -Nru a/arch/ia64/sn/io/drivers/ifconfig_net.c b/arch/ia64/sn/io/drivers/ifconfig_net.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/drivers/ifconfig_net.c Mon May 19 05:42:35 2003 @@ -0,0 +1,298 @@ +/* $Id: ifconfig_net.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ifconfig_net - SGI's Persistent Network Device names. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGI_IFCONFIG_NET "SGI-PERSISTENT NETWORK DEVICE NAME DRIVER" +#define SGI_IFCONFIG_NET_VERSION "1.0" + +/* + * Some Global definitions. + */ +static devfs_handle_t ifconfig_net_handle; +static unsigned long ifconfig_net_debug; + +/* + * ifconfig_net_open - Opens the special device node "/devhw/.ifconfig_net". + */ +static int ifconfig_net_open(struct inode * inode, struct file * filp) +{ + if (ifconfig_net_debug) { + printk("ifconfig_net_open called.\n"); + } + + return(0); + +} + +/* + * ifconfig_net_close - Closes the special device node "/devhw/.ifconfig_net". + */ +static int ifconfig_net_close(struct inode * inode, struct file * filp) +{ + + if (ifconfig_net_debug) { + printk("ifconfig_net_close called.\n"); + } + + return(0); +} + +/* + * assign_ifname - Assign the next available interface name from the persistent list. + */ +void +assign_ifname(struct net_device *dev, + struct ifname_num *ifname_num) + +{ + + /* + * Handle eth devices. + */ + if ( (memcmp(dev->name, "eth", 3) == 0) ) { + if (ifname_num->next_eth != -1) { + /* + * Assign it the next available eth interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "eth%d", (int)ifname_num->next_eth); + ifname_num->next_eth++; + } + + return; + } + + /* + * Handle fddi devices. + */ + if ( (memcmp(dev->name, "fddi", 4) == 0) ) { + if (ifname_num->next_fddi != -1) { + /* + * Assign it the next available fddi interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "fddi%d", (int)ifname_num->next_fddi); + ifname_num->next_fddi++; + } + + return; + } + + /* + * Handle hip devices. + */ + if ( (memcmp(dev->name, "hip", 3) == 0) ) { + if (ifname_num->next_hip != -1) { + /* + * Assign it the next available hip interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "hip%d", (int)ifname_num->next_hip); + ifname_num->next_hip++; + } + + return; + } + + /* + * Handle tr devices. + */ + if ( (memcmp(dev->name, "tr", 2) == 0) ) { + if (ifname_num->next_tr != -1) { + /* + * Assign it the next available tr interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "tr%d", (int)ifname_num->next_tr); + ifname_num->next_tr++; + } + + return; + } + + /* + * Handle fc devices. + */ + if ( (memcmp(dev->name, "fc", 2) == 0) ) { + if (ifname_num->next_fc != -1) { + /* + * Assign it the next available fc interface number. + */ + memset(dev->name, 0, strlen(dev->name)); + sprintf(dev->name, "fc%d", (int)ifname_num->next_fc); + ifname_num->next_fc++; + } + + return; + } +} + +/* + * find_persistent_ifname: Returns the entry that was seen in previous boot. + */ +struct ifname_MAC * +find_persistent_ifname(struct net_device *dev, + struct ifname_MAC *ifname_MAC) + +{ + + while (ifname_MAC->addr_len) { + if (memcmp(dev->dev_addr, ifname_MAC->dev_addr, dev->addr_len) == 0) + return(ifname_MAC); + + ifname_MAC++; + } + + return(NULL); +} + +/* + * ifconfig_net_ioctl: ifconfig_net driver ioctl interface. + */ +static int ifconfig_net_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + extern struct net_device *__dev_get_by_name(const char *); +#ifdef CONFIG_NET + struct net_device *dev; + struct ifname_MAC *found; + char temp[64]; +#endif + struct ifname_MAC *ifname_MAC; + struct ifname_MAC *new_devices, *temp_new_devices; + struct ifname_num *ifname_num; + unsigned long size; + + + if (ifconfig_net_debug) { + printk("HCL: hcl_ioctl called.\n"); + } + + /* + * Read in the header and see how big of a buffer we really need to + * allocate. + */ + ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), + GFP_KERNEL); + copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num)); + size = ifname_num->size; + kfree(ifname_num); + ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL); + ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) ); + + copy_from_user( ifname_num, (char *) arg, size); + new_devices = kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL); + temp_new_devices = new_devices; + + memset(new_devices, 0, size - sizeof(struct ifname_num)); + +#ifdef CONFIG_NET + /* + * Go through the net device entries and make them persistent! + */ + for (dev = dev_base; dev != NULL; dev = dev->next) { + /* + * Skip NULL entries or "lo" + */ + if ( (dev->addr_len == 0) || ( !strncmp(dev->name, "lo", strlen(dev->name))) ){ + continue; + } + + /* + * See if we have a persistent interface name for this device. + */ + found = NULL; + found = find_persistent_ifname(dev, ifname_MAC); + if (found) { + strcpy(dev->name, found->name); + } else { + /* Never seen this before .. */ + assign_ifname(dev, ifname_num); + + /* + * Save the information for the next boot. + */ + sprintf(temp,"%s %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + strcpy(temp_new_devices->name, dev->name); + temp_new_devices->addr_len = dev->addr_len; + memcpy(temp_new_devices->dev_addr, dev->dev_addr, dev->addr_len); + temp_new_devices++; + } + + } +#endif + + /* + * Copy back to the User Buffer area any new devices encountered. + */ + copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, + size - sizeof(struct ifname_num)); + + return(0); + +} + +struct file_operations ifconfig_net_fops = { + ioctl:ifconfig_net_ioctl, /* ioctl */ + open:ifconfig_net_open, /* open */ + release:ifconfig_net_close /* release */ +}; + + +/* + * init_ifconfig_net() - Boot time initialization. Ensure that it is called + * after devfs has been initialized. + * + */ +#ifdef MODULE +int init_module (void) +#else +int __init init_ifconfig_net(void) +#endif +{ + ifconfig_net_handle = NULL; + ifconfig_net_handle = hwgraph_register(hwgraph_root, ".ifconfig_net", + 0, 0, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &ifconfig_net_fops, NULL); + + if (ifconfig_net_handle == NULL) { + panic("Unable to create SGI PERSISTENT NETWORK DEVICE Name Driver.\n"); + } + + return(0); + +} diff -Nru a/arch/ia64/sn/io/drivers/ioconfig_bus.c b/arch/ia64/sn/io/drivers/ioconfig_bus.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/drivers/ioconfig_bus.c Mon May 19 05:42:35 2003 @@ -0,0 +1,401 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ioconfig_bus - SGI's Persistent PCI Bus Numbering. + * + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING" +#define SGI_IOCONFIG_BUS_VERSION "1.0" + +/* + * Some Global definitions. + */ +static vertex_hdl_t ioconfig_bus_handle; +static unsigned long ioconfig_bus_debug; + +#ifdef IOCONFIG_BUS_DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +static u64 ioconfig_file; +static u64 ioconfig_file_size; +static u64 ioconfig_activated; +static char ioconfig_kernopts[128]; + +/* + * For debugging purpose .. hardcode a table .. + */ +struct ascii_moduleid *ioconfig_bus_table; +u64 ioconfig_bus_table_size; + + +static int free_entry; +static int new_entry; + +int next_basebus_number; + +void +ioconfig_get_busnum(char *io_moduleid, int *bus_num) +{ + struct ascii_moduleid *temp; + int index; + + DBG("ioconfig_get_busnum io_moduleid %s\n", io_moduleid); + + *bus_num = -1; + temp = ioconfig_bus_table; + for (index = 0; index < free_entry; temp++, index++) { + if ( (io_moduleid[0] == temp->io_moduleid[0]) && + (io_moduleid[1] == temp->io_moduleid[1]) && + (io_moduleid[2] == temp->io_moduleid[2]) && + (io_moduleid[4] == temp->io_moduleid[4]) && + (io_moduleid[5] == temp->io_moduleid[5]) ) { + *bus_num = index * 0x10; + return; + } + } + + /* + * New IO Brick encountered. + */ + if (((int)io_moduleid[0]) == 0) { + DBG("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid); + return; + } + + io_moduleid[3] = '#'; + strcpy((char *)&(ioconfig_bus_table[free_entry].io_moduleid), io_moduleid); + *bus_num = free_entry * 0x10; + free_entry++; +} + +static void +dump_ioconfig_table(void) +{ + + int index = 0; + struct ascii_moduleid *temp; + + temp = ioconfig_bus_table; + while (index < free_entry) { + DBG("ASSCI Module ID %s\n", temp->io_moduleid); + temp++; + index++; + } +} + +/* + * nextline + * This routine returns the nextline in the buffer. + */ +int nextline(char *buffer, char **next, char *line) +{ + + char *temp; + + if (buffer[0] == 0x0) { + return(0); + } + + temp = buffer; + while (*temp != 0) { + *line = *temp; + if (*temp != '\n'){ + *line = *temp; + temp++; line++; + } else + break; + } + + if (*temp == 0) + *next = temp; + else + *next = ++temp; + + return(1); +} + +/* + * build_pcibus_name + * This routine parses the ioconfig contents read into + * memory by ioconfig command in EFI and builds the + * persistent pci bus naming table. + */ +void +build_moduleid_table(char *file_contents, struct ascii_moduleid *table) +{ + /* + * Read the whole file into memory. + */ + int rc; + char *name; + char *temp; + char *next; + char *current; + char *line; + struct ascii_moduleid *moduleid; + + line = kmalloc(256, GFP_KERNEL); + memset(line, 0,256); + name = kmalloc(125, GFP_KERNEL); + memset(name, 0, 125); + moduleid = table; + current = file_contents; + while (nextline(current, &next, line)){ + + DBG("current 0x%lx next 0x%lx\n", current, next); + + temp = line; + /* + * Skip all leading Blank lines .. + */ + while (isspace(*temp)) + if (*temp != '\n') + temp++; + else + break; + + if (*temp == '\n') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Skip comment lines + */ + if (*temp == '#') { + current = next; + memset(line, 0, 256); + continue; + } + + /* + * Get the next free entry in the table. + */ + rc = sscanf(temp, "%s", name); + strcpy(&moduleid->io_moduleid[0], name); + DBG("Found %s\n", name); + moduleid++; + free_entry++; + current = next; + memset(line, 0, 256); + } + + new_entry = free_entry; + kfree(line); + kfree(name); + + return; +} + +void +ioconfig_bus_init(void) +{ + + struct ia64_sal_retval ret_stuff; + u64 *temp; + int cnode; + + DBG("ioconfig_bus_init called.\n"); + + for (cnode = 0; cnode < numnodes; cnode++) { + nasid_t nasid; + /* + * Make SAL call to get the address of the bus configuration table. + */ + ret_stuff.status = (uint64_t)0; + ret_stuff.v0 = (uint64_t)0; + ret_stuff.v1 = (uint64_t)0; + ret_stuff.v2 = (uint64_t)0; + nasid = COMPACT_TO_NASID_NODEID(cnode); + SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, nasid, 0, 0, 0, 0, 0); + temp = (u64 *)TO_NODE_CAC(nasid, ret_stuff.v0); + ioconfig_file = *temp; + DBG("ioconfig_bus_init: Nasid %d ret_stuff.v0 0x%lx\n", nasid, + ret_stuff.v0); + if (ioconfig_file) { + ioconfig_file_size = ret_stuff.v1; + ioconfig_file = (ioconfig_file | CACHEABLE_MEM_SPACE); + ioconfig_activated = 1; + break; + } + } + + DBG("ioconfig_bus_init: ret_stuff.v0 %p ioconfig_file %p %d\n", + ret_stuff.v0, (void *)ioconfig_file, (int)ioconfig_file_size); + + ioconfig_bus_table = kmalloc( 512, GFP_KERNEL ); + memset(ioconfig_bus_table, 0, 512); + + /* + * If ioconfig options are given on the bootline .. take it. + */ + if (*ioconfig_kernopts != '\0') { + /* + * ioconfig="..." kernel options given. + */ + DBG("ioconfig_bus_init: Kernel Options given.\n"); + (void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table); + (void) dump_ioconfig_table(); + return; + } + + if (ioconfig_activated) { + DBG("ioconfig_bus_init: ioconfig file given.\n"); + (void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table); + (void) dump_ioconfig_table(); + } else { + DBG("ioconfig_bus_init: ioconfig command not executed in prom\n"); + } + +} + +void +ioconfig_bus_new_entries(void) +{ + + + int index = 0; + struct ascii_moduleid *temp; + + if ((ioconfig_activated) && (free_entry > new_entry)) { + printk("### Please add the following new IO Bricks Module ID \n"); + printk("### to your Persistent Bus Numbering Config File\n"); + } else + return; + + index = new_entry; + temp = &ioconfig_bus_table[index]; + while (index < free_entry) { + printk("%s\n", (char *)temp); + temp++; + index++; + } + printk("### End\n"); + +} +static int ioconfig_bus_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + struct ioconfig_parm parm; + + /* + * Copy in the parameters. + */ + copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm)); + parm.number = free_entry - new_entry; + parm.ioconfig_activated = ioconfig_activated; + copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm)); + copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry)); + + return 0; +} + +/* + * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_open(struct inode * inode, struct file * filp) +{ + if (ioconfig_bus_debug) { + DBG("ioconfig_bus_open called.\n"); + } + + return(0); + +} + +/* + * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus". + */ +static int ioconfig_bus_close(struct inode * inode, struct file * filp) +{ + + if (ioconfig_bus_debug) { + DBG("ioconfig_bus_close called.\n"); + } + + return(0); +} + +struct file_operations ioconfig_bus_fops = { + ioctl:ioconfig_bus_ioctl, + open:ioconfig_bus_open, /* open */ + release:ioconfig_bus_close /* release */ +}; + + +/* + * init_ifconfig_bus() - Boot time initialization. Ensure that it is called + * after devfs has been initialized. + * + */ +int init_ioconfig_bus(void) +{ + ioconfig_bus_handle = NULL; + ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", + 0, 0, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &ioconfig_bus_fops, NULL); + + if (ioconfig_bus_handle == NULL) { + panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n"); + } + + return(0); + +} + +static int __init ioconfig_bus_setup (char *str) +{ + + char *temp; + + DBG("ioconfig_bus_setup: Kernel Options %s\n", str); + + temp = (char *)ioconfig_kernopts; + memset(temp, 0, 128); + while ( (*str != '\0') && !isspace (*str) ) { + if (*str == ',') { + *temp = '\n'; + temp++; + str++; + continue; + } + *temp = *str; + temp++; + str++; + } + + return(0); + +} +__setup("ioconfig=", ioconfig_bus_setup); diff -Nru a/arch/ia64/sn/io/eeprom.c b/arch/ia64/sn/io/eeprom.c --- a/arch/ia64/sn/io/eeprom.c Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1454 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * WARNING: There is more than one copy of this file in different isms. - * All copies must be kept exactly in sync. - * Do not modify this file without also updating the following: - * - * irix/kern/io/eeprom.c - * stand/arcs/lib/libsk/ml/eeprom.c - * stand/arcs/lib/libkl/io/eeprom.c - * - * (from time to time they might not be in sync but that's due to bringup - * activity - this comment is to remind us that they eventually have to - * get back together) - * - * eeprom.c - * - * access to board-mounted EEPROMs via the L1 system controllers - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(EEPROM_DEBUG) -#define db_printf(x) printk x -#else -#define db_printf(x) printk x -#endif - -#define BCOPY(x,y,z) memcpy(y,x,z) - -#define UNDERSCORE 0 /* don't convert underscores to hyphens */ -#define HYPHEN 1 /* convert underscores to hyphens */ - -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ); -uint64_t generate_unique_id( char *sn, int sn_len ); -uchar_t char_to_base36( char c ); -int nicify( char *dst, eeprom_brd_record_t *src ); -static void int64_to_hex_string( char *out, uint64_t val ); - -// extern int router_lock( net_vec_t, int, int ); -// extern int router_unlock( net_vec_t ); -#define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000) -#define ROUTER_UNLOCK(p) // router_unlock(p) - -#define IP27LOG_OVNIC "OverrideNIC" - - -/* the following function converts an EEPROM record to a close facsimile - * of the string returned by reading a Dallas Semiconductor NIC (see - * one of the many incarnations of nic.c for details on that driver) - */ -int nicify( char *dst, eeprom_brd_record_t *src ) -{ - int field_len; - uint64_t unique_id; - char *cur_dst = dst; - eeprom_board_ia_t *board; - - board = src->board_ia; - ASSERT( board ); /* there should always be a board info area */ - - /* copy part number */ - strcpy( cur_dst, "Part:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->part_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN ); - cur_dst += field_len; - - /* copy product name */ - strcpy( cur_dst, ";Name:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII ); - field_len = board->product_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE ); - cur_dst += field_len; - - /* copy serial number */ - strcpy( cur_dst, ";Serial:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->serial_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->serial_num, field_len, - HYPHEN); - - cur_dst += field_len; - - /* copy revision */ - strcpy( cur_dst, ";Revision:"); - cur_dst += strlen( cur_dst ); - ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->board_rev_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN ); - cur_dst += field_len; - - /* EEPROMs don't have equivalents for the Group, Capability and - * Variety fields, so we pad these with 0's - */ - strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" ); - cur_dst += strlen( cur_dst ); - - /* use the board serial number to "fake" a laser id */ - strcpy( cur_dst, ";Laser:" ); - cur_dst += strlen( cur_dst ); - unique_id = generate_unique_id( board->serial_num, - board->serial_num_tl & FIELD_LENGTH_MASK ); - int64_to_hex_string( cur_dst, unique_id ); - strcat( dst, ";" ); - - return 1; -} - - -/* These functions borrow heavily from chars2* in nic.c - */ -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ) -{ - int i; - for( i = 0; i < length; i++ ) { - - /* change underscores to hyphens if requested */ - if( from[i] == '_' && change_underscore == HYPHEN ) - to[i] = '-'; - - /* ; and ; are separators, so mustn't appear within - * a field */ - else if( from[i] == ':' || from[i] == ';' ) - to[i] = '?'; - - /* I'm not sure why or if ASCII character 0xff would - * show up in an EEPROM field, but the NIC parsing - * routines wouldn't like it if it did... so we - * get rid of it, just in case. */ - else if( (unsigned char)from[i] == (unsigned char)0xff ) - to[i] = ' '; - - /* unprintable characters are replaced with . */ - else if( from[i] < ' ' || from[i] >= 0x7f ) - to[i] = '.'; - - /* otherwise, just copy the character */ - else - to[i] = from[i]; - } - - if( i == 0 ) { - to[i] = ' '; /* return at least a space... */ - i++; - } - to[i] = 0; /* terminating null */ -} - -/* Note that int64_to_hex_string currently only has a big-endian - * implementation. - */ -#ifdef _MIPSEB -static void int64_to_hex_string( char *out, uint64_t val ) -{ - int i; - uchar_t table[] = "0123456789abcdef"; - uchar_t *byte_ptr = (uchar_t *)&val; - for( i = 0; i < sizeof(uint64_t); i++ ) { - out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ]; - out[i*2+1] = table[ (*byte_ptr) & 0x0f ]; - byte_ptr++; - } - out[i*2] = '\0'; -} - -#else /* little endian */ - -static void int64_to_hex_string( char *out, uint64_t val ) -{ - - - printk("int64_to_hex_string needs a little-endian implementation.\n"); -} -#endif /* _MIPSEB */ - -/* Convert a standard ASCII serial number to a unique integer - * id number by treating the serial number string as though - * it were a base 36 number - */ -uint64_t generate_unique_id( char *sn, int sn_len ) -{ - int uid = 0; - int i; - - #define VALID_BASE36(c) ((c >= '0' && c <='9') \ - || (c >= 'A' && c <='Z') \ - || (c >= 'a' && c <='z')) - - for( i = 0; i < sn_len; i++ ) { - if( !VALID_BASE36(sn[i]) ) - continue; - uid *= 36; - uid += char_to_base36( sn[i] ); - } - - if( uid == 0 ) - return rtc_time(); - - return uid; -} - -uchar_t char_to_base36( char c ) -{ - uchar_t val; - - if( c >= '0' && c <= '9' ) - val = (c - '0'); - - else if( c >= 'A' && c <= 'Z' ) - val = (c - 'A' + 10); - - else if( c >= 'a' && c <= 'z' ) - val = (c - 'a' + 10); - - else val = 0; - - return val; -} - - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ) -{ - int rval = 0; - rval += *src; src++; - rval += ((int)(*src) << 8); src ++; - rval += ((int)(*src) << 16); - return rval; -} - - -int eeprom_str( char *nic_str, nasid_t nasid, int component ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - if( (component & C_DIMM) == C_DIMM ) { - /* this function isn't applicable to DIMMs */ - return EEP_PARAM; - } - else { - eep.board_ia = &board; - eep.spd = NULL; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - } - - switch( component & BRICK_MASK ) { - case C_BRICK: - r = cbrick_eeprom_read( &eep, nasid, component ); - break; - case IO_BRICK: - r = iobrick_eeprom_read( &eep, nasid, component ); - break; - default: - return EEP_PARAM; /* must be an invalid component */ - } - if( r ) - return r; - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - - if( !(component & VECTOR) ) - return EEP_PARAM; - - if( (r = vector_eeprom_read( &eep, nasid, path, component )) ) - return r; - - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - - -int is_iobrick( int nasid, int widget_num ) -{ - uint32_t wid_reg; - int part_num, mfg_num; - - /* Read the widget's WIDGET_ID register to get - * its part number and mfg number - */ - wid_reg = *(volatile int32_t *) - (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID); - - part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT; - - /* Is this the "xbow part" of an XBridge? If so, this - * widget is definitely part of an I/O brick. - */ - if( part_num == XXBOW_WIDGET_PART_NUM && - mfg_num == XXBOW_WIDGET_MFGR_NUM ) - - return 1; - - /* Is this a "bridge part" of an XBridge? If so, once - * again, we know this widget is part of an I/O brick. - */ - if( part_num == XBRIDGE_WIDGET_PART_NUM && - mfg_num == XBRIDGE_WIDGET_MFGR_NUM ) - - return 1; - - return 0; -} - - -int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 ) - { - /* We successfully read IP27LOG_OVNIC, so return it as the UID. */ - db_printf(( "cbrick_uid_get:" - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - *uid = strtoull( uid_str, NULL, 0 ); - return EEP_OK; - } -#endif - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one. - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = ≻ - sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); - } - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( scp, subch, msg, msg, &len ) ) { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* free up subchannel */ - sc_close(scp, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - return( EEP_L1 ); - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - -#define FAIL \ - { \ - *uid = rtc_time(); \ - printk( "rbrick_uid_get failed; using current time as uid\n" ); \ - return EEP_OK; \ - } - - ROUTER_LOCK(path); - sc_init( &sc, nasid, path ); - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) { - ROUTER_UNLOCK(path); - FAIL; - } - - if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* send the request to the L1 */ - if( sc_command( &sc, subch, msg, msg, &len ) ) { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* free up subchannel */ - ROUTER_UNLOCK(path); - sc_close(&sc, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - FAIL; - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - -int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( r != EEP_OK ) { - *uid = rtc_time(); - return r; - } - - *uid = generate_unique_id( board.serial_num, - board.serial_num_tl & FIELD_LENGTH_MASK ); - - return EEP_OK; -} - - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - char *tmp; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) { - db_printf(( "ibrick_mac_addr_get: " - "Couldn't read MAC address from EEPROM\n" )); - return EEP_L1; - } - else { - /* successfully read info area */ - int ix; - tmp = board.mac_addr; - for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ ) - { - *eaddr++ = *tmp++; - } - *eaddr = '\0'; - } - - return EEP_OK; -} - - -/* - * eeprom_vertex_info_set - * - * Given a vertex handle, a component designation, a starting nasid - * and (in the case of a router) a vector path to the component, this - * function will read the EEPROM and attach the resulting information - * to the vertex in the same string format as that provided by the - * Dallas Semiconductor NIC drivers. If the vertex already has the - * string, this function just returns the string. - */ - -extern char *nic_vertex_info_get( devfs_handle_t ); -extern void nic_vmc_check( devfs_handle_t, char * ); -/* the following were lifted from nic.c - change later? */ -#define MAX_INFO 2048 -#define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) -#define DEL(ptr) (kern_free((ptr))) - -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ) -{ - char *info_tmp; - int info_len; - char *info; - - /* see if this vertex is already marked */ - info_tmp = nic_vertex_info_get(v); - if (info_tmp) return info_tmp; - - /* get a temporary place for the data */ - NEWSZ(info_tmp, MAX_INFO); - if (!info_tmp) return NULL; - - /* read the EEPROM */ - if( component & R_BRICK ) { - if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK ) - return NULL; - } - else { - if( eeprom_str( info_tmp, nasid, component ) != EEP_OK ) - return NULL; - } - - /* allocate a smaller final place */ - info_len = strlen(info_tmp)+1; - NEWSZ(info, info_len); - if (info) { - strcpy(info, info_tmp); - DEL(info_tmp); - } else { - info = info_tmp; - } - - /* add info to the vertex */ - hwgraph_info_add_LBL(v, INFO_LBL_NIC, - (arbitrary_info_t) info); - - /* see if someone else got there first */ - info_tmp = nic_vertex_info_get(v); - if (info != info_tmp) { - DEL(info); - return info_tmp; - } - - /* export the data */ - hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len); - - /* trigger all matching callbacks */ - nic_vmc_check(v, info); - - return info; -} - - -/********************************************************************* - * - * stubs for use until the Bedrock/L1 link is available - * - */ - -#include - -/* #define EEPROM_TEST */ - -/* fake eeprom reading functions (replace when the BR/L1 communication - * channel is in working order) - */ - - -/* generate a charater in [0-9A-Z]; if an "extra" character is - * specified (such as '_'), include it as one of the possibilities. - */ -char random_eeprom_ch( char extra ) -{ - char ch; - int modval = 36; - if( extra ) - modval++; - - ch = rtc_time() % modval; - - if( ch < 10 ) - ch += '0'; - else if( ch >= 10 && ch < 36 ) - ch += ('A' - 10); - else - ch = extra; - - return ch; -} - -/* create a part number of the form xxx-xxxx-xxx. - * It may be important later to generate different - * part numbers depending on the component we're - * supposed to be "reading" from, so the component - * paramter is provided. - */ -void fake_a_part_number( char *buf, int component ) -{ - int i; - switch( component ) { - - /* insert component-specific routines here */ - - case C_BRICK: - strcpy( buf, "030-1266-001" ); - break; - default: - for( i = 0; i < 12; i++ ) { - if( i == 3 || i == 8 ) - buf[i] = '-'; - else - buf[i] = random_eeprom_ch(0); - } - } -} - - -/* create a six-character serial number */ -void fake_a_serial_number( char *buf, uint64_t ser ) -{ - int i; - static const char hexchars[] = "0123456789ABCDEF"; - - if (ser) { - for( i = 5; i >=0; i-- ) { - buf[i] = hexchars[ser & 0xf]; - ser >>= 4; - } - } - else { - for( i = 0; i < 6; i++ ) - buf[i] = random_eeprom_ch(0); - } -} - - -void fake_a_product_name( uchar_t *format, char* buf, int component ) -{ - switch( component & BRICK_MASK ) { - - case C_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "C_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "IP35" ); - *format = 0xC4; - } - break; - - case R_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "R_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "R_BRICK" ); - *format = 0xC7; - } - break; - - case IO_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "IO_BRICK_SUB" ); - *format = 0xCC; - } - else { - strcpy( buf, "IO_BRICK" ); - *format = 0xC8; - } - break; - - default: - strcpy( buf, "UNK_DEVICE" ); - *format = 0xCA; - } -} - - - -int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, - uint64_t ser ) -{ - eeprom_board_ia_t *board; - eeprom_chassis_ia_t *chassis; - int i, cs; - - board = buf->board_ia; - chassis = buf->chassis_ia; - - if( !(component & SUBORD_MASK) ) { - if( !chassis ) - return EEP_PARAM; - chassis->format = 0; - chassis->length = 5; - chassis->type = 0x17; - - chassis->part_num_tl = 0xCC; - fake_a_part_number( chassis->part_num, component ); - chassis->serial_num_tl = 0xC6; - fake_a_serial_number( chassis->serial_num, ser ); - - cs = chassis->format + chassis->length + chassis->type - + chassis->part_num_tl + chassis->serial_num_tl; - for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->part_num[i]; - for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->serial_num[i]; - chassis->checksum = 256 - (cs % 256); - } - - if( !board ) - return EEP_PARAM; - board->format = 0; - board->length = 10; - board->language = 0; - board->mfg_date = 1789200; /* noon, 5/26/99 */ - board->manuf_tl = 0xC3; - strcpy( board->manuf, "SGI" ); - - fake_a_product_name( &(board->product_tl), board->product, component ); - - board->serial_num_tl = 0xC6; - fake_a_serial_number( board->serial_num, ser ); - - board->part_num_tl = 0xCC; - fake_a_part_number( board->part_num, component ); - - board->board_rev_tl = 0xC2; - board->board_rev[0] = '0'; - board->board_rev[1] = '1'; - - board->eeprom_size_tl = 0x01; - board->eeprom_size = 1; - - board->temp_waiver_tl = 0xC2; - board->temp_waiver[0] = '0'; - board->temp_waiver[1] = '1'; - - cs = board->format + board->length + board->language - + (board->mfg_date & 0xFF) - + (board->mfg_date & 0xFF00) - + (board->mfg_date & 0xFF0000) - + board->manuf_tl + board->product_tl + board->serial_num_tl - + board->part_num_tl + board->board_rev_tl - + board->board_rev[0] + board->board_rev[1] - + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl - + board->temp_waiver[0] + board->temp_waiver[1]; - for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->manuf[i]; - for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->product[i]; - for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->serial_num[i]; - for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->part_num[i]; - - board->checksum = 256 - (cs % 256); - - return EEP_OK; -} - -#define EEPROM_CHUNKSIZE 64 - -#if defined(EEPROM_DEBUG) -#define RETURN_ERROR \ -{ \ - printk( "read_ia error return, component 0x%x, line %d" \ - ", address 0x%x, ia code 0x%x\n", \ - l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \ - return EEP_L1; \ -} - -#else -#define RETURN_ERROR return(EEP_L1) -#endif - -int read_ia( l1sc_t *sc, int subch, int l1_compt, - int ia_code, char *eep_record ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ - int offset = 0; /* current offset into info area */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( ia_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, ia_code, - L1_ARG_INT, offset, - L1_ARG_INT, ia_len )) < 0 ) - { - RETURN_ERROR; - } - - /* send the request to the L1 */ - - if( sc_command( sc, subch, msg, msg, &len ) ) { - RETURN_ERROR; - } - - /* check response */ - if( sc_interpret_resp( msg, 5, - L1_ARG_INT, &ia_len, - L1_ARG_UNKNOWN, &len, eep_record ) < 0 ) - { - RETURN_ERROR; - } - - if( ia_len > EEPROM_CHUNKSIZE ) - ia_len = EEPROM_CHUNKSIZE; - - eep_record += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_spd( l1sc_t *sc, int subch, int l1_compt, - eeprom_spd_u *spd ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int resp; /* l1 response code */ - int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ - int offset = 0; /* current offset into spd record */ - char *spd_p = spd->bytes; /* "thumb" for writing to spd */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( spd_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, L1_EEP_SPD, - L1_ARG_INT, offset, - L1_ARG_INT, spd_len )) < 0 ) - { - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - return( EEP_L1 ); - } - - /* check response */ - if( (resp = sc_interpret_resp( msg, 5, - L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) - { - /* - * translate l1 response code to eeprom.c error codes: - * The L1 response will be L1_RESP_NAVAIL if the spd - * can't be read (i.e. the spd isn't physically there). It will - * return L1_RESP_INVAL if the spd exists, but fails the checksum - * test because the eeprom wasn't programmed, programmed incorrectly, - * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, - * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is - * invalid. - */ - if(resp == L1_RESP_INVAL) { - resp = EEP_BAD_CHECKSUM; - } else { - resp = EEP_L1; - } - return( resp ); - } - - if( spd_len > EEPROM_CHUNKSIZE ) - spd_len = EEPROM_CHUNKSIZE; - - spd_p += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_chassis_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* use to verify eeprom record checksum */ - int i; - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record ) - != EEP_OK ) - { - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->type = *eep_rec_p++; - - ia->part_num_tl = *eep_rec_p++; - - (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->serial_num, - (ia->serial_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->checksum = eep_record[(8 * ia->length) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_chassis_ia: bad checksum\n" )); - db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int read_board_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_board_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* running checksum total */ - int i; - - BZERO( ia, sizeof( eeprom_board_ia_t ) ); - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record ) - != EEP_OK ) - { - db_printf(( "read_board_ia: error reading info area from L1\n" )); - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_board_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->language = *eep_rec_p++; - - ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p ); - eep_rec_p += 3; - - ia->manuf_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK); - - ia->product_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK)); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->part_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - eep_rec_p++; /* we do not use the FRU file id */ - - ia->board_rev_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK); - - ia->eeprom_size_tl = *eep_rec_p++; - ia->eeprom_size = *eep_rec_p++; - - ia->temp_waiver_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->temp_waiver, - (ia->temp_waiver_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK); - - /* if there's more, we must be reading a main board; get - * additional fields - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->ekey_G_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_G, - ia->ekey_G_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK); - - ia->ekey_P_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_P, - ia->ekey_P_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK); - - ia->ekey_Y_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_Y, - ia->ekey_Y_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK); - - /* - * need to get a couple more fields if this is an I brick - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->mac_addr_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->mac_addr, - ia->mac_addr_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK); - - ia->ieee1394_cfg_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->ieee1394_cfg, - ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK ); - - } - } - - ia->checksum = eep_record[(ia->length * 8) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_board_ia: bad checksum\n" )); - db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; -#ifdef LOG_GETENV - char uid_str[32]; -#endif - int l1_compt, subch; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting a cbrick */ - if( !(component & C_BRICK) ) - return EEP_PARAM; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 ) - { - db_printf(( "_cbrick_eeprom_read: " - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - uid = strtoull( uid_str, NULL, 0 ); - } -#endif - - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if((component & C_DIMM) == C_DIMM) { - l1_compt = L1_EEP_DIMM(component & COMPT_MASK); - r = read_spd(scp,subch,l1_compt, buf->spd); - sc_close(scp,subch); - return(r); - } - - switch( component ) - { - case C_BRICK: - /* c-brick motherboard */ - l1_compt = L1_EEP_NODE; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( scp, subch ); - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - if( uid ) { - /* If IP27LOG_OVNIC is set, we want to put that value - * in as our UID. */ - fake_a_serial_number( buf->chassis_ia->serial_num, uid ); - buf->chassis_ia->serial_num_tl = 6; - } - break; - - case C_PIMM: - /* one of the PIMM boards */ - l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) - { - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - return _cbrick_eeprom_read( buf, scp, component ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - int l1_compt, subch; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're talking to an applicable brick */ - if( !(component & IO_BRICK) ) { - return EEP_PARAM; - } - - /* If we're talking to this c-brick's attached io brick, use - * the local l1sc_t; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) - return EEP_L1; - - - switch( component ) - { - case IO_BRICK: - /* IO brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - - if( r != EEP_OK ) { - sc_close( scp, subch ); - /* - * Whenever we no longer need to test on hardware - * that does not have EEPROMS, then this can be removed. - */ - r = fake_an_eeprom_record( buf, component, rtc_time() ); - return r; - } - break; - - case IO_POWER: - /* IO brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) { - return r; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; - int l1_compt, subch; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting an applicable brick */ - if( !(component & VECTOR) ) - return EEP_PARAM; - - switch( component & BRICK_MASK ) - { - case R_BRICK: - ROUTER_LOCK( path ); - sc_init( &sc, nasid, path ); - - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) - { - db_printf(( "vector_eeprom_read: couldn't open subch\n" )); - ROUTER_UNLOCK(path); - return EEP_L1; - } - switch( component ) - { - case R_BRICK: - /* r-brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - printk( "vector_eeprom_read: couldn't get rbrick eeprom info;" - " using current time as uid\n" ); - uid = rtc_time(); - db_printf(("vector_eeprom_read: using a fake eeprom record\n")); - return fake_an_eeprom_record( buf, component, uid ); - } - break; - - case R_POWER: - /* r-brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - return EEP_PARAM; - } - r = read_board_ia( &sc, subch, l1_compt, buf->board_ia ); - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - if( r != EEP_OK ) { - db_printf(( "vector_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; - - case C_BRICK: - sc_init( &sc, nasid, path ); - return _cbrick_eeprom_read( buf, &sc, component ); - - default: - /* unsupported brick type */ - return EEP_PARAM; - } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} diff -Nru a/arch/ia64/sn/io/efi-rtc.c b/arch/ia64/sn/io/efi-rtc.c --- a/arch/ia64/sn/io/efi-rtc.c Wed Aug 14 04:48:55 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,185 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. - * Copyright (C) 2001 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * No locking necessary when this is called from efirtc which protects us - * from racing by efi_rtc_lock. - */ -#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3)) -#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr)) -#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data)) - -#define TOD_SGS_M48T35 1 -#define TOD_DALLAS_DS1386 2 - -static unsigned long nvram_base = 0; -static int tod_chip_type; - -static int -get_tod_chip_type(void) -{ - unsigned char testval; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_DAY_ADDR, 0xff); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - - testval = read_io_port(RTC_DAL_DAY_ADDR); - if (testval == 0xff) - return TOD_SGS_M48T35; - - return TOD_DALLAS_DS1386; -} - -efi_status_t -ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - memset(time, 0, sizeof(*time)); - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT); - - time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF; - time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR)); - time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR)); - time->nanosecond = 0; - - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - - time->nanosecond = 0; - time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR)); - time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR)); - time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR)); - time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR)); - time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR)); - time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF; - - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - if (caps) { - caps->resolution = 50000000; /* 50PPM */ - caps->accuracy = 1000; /* 1ms */ - caps->sets_to_zero = 0; - } - - return EFI_SUCCESS; -} - -static efi_status_t ioc3_set_time (efi_time_t *t) -{ - if (!nvram_base) { - printk(KERN_CRIT "nvram_base is zero\n"); - return EFI_UNSUPPORTED; - } - - switch (tod_chip_type) { - case TOD_SGS_M48T35: - write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE); - write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_SGS_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_SGS_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_SGS_CONTROL_ADDR, 0); - break; - - case TOD_DALLAS_DS1386: - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE); - write_io_port(RTC_DAL_SEC_ADDR, INT_TO_BCD(t->second)); - write_io_port(RTC_DAL_MIN_ADDR, INT_TO_BCD(t->minute)); - write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour)); - write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day)); - write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month)); - write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF))); - write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE); - break; - - default: - break; - } - - return EFI_SUCCESS; -} - -/* The following two are not supported atm. */ -static efi_status_t -ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -static efi_status_t -ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm) -{ - return EFI_UNSUPPORTED; -} - -/* - * It looks like the master IOC3 is usually on bus 0, device 4. Hope - * that's right - */ -static __init int efi_ioc3_time_init(void) -{ - struct pci_dev *dev; - static struct ioc3 *ioc3; - - dev = pci_find_slot(0, PCI_DEVFN(4, 0)); - if (!dev) { - printk(KERN_CRIT "Couldn't find master IOC3\n"); - - return -ENODEV; - } - - ioc3 = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - nvram_base = (unsigned long) ioc3 + IOC3_BYTEBUS_DEV0; - - tod_chip_type = get_tod_chip_type(); - if (tod_chip_type == 1) - printk(KERN_NOTICE "TOD type is SGS M48T35\n"); - else if (tod_chip_type == 2) - printk(KERN_NOTICE "TOD type is Dallas DS1386\n"); - else - printk(KERN_CRIT "No or unknown TOD\n"); - - efi.get_time = ioc3_get_time; - efi.set_time = ioc3_set_time; - efi.get_wakeup_time = ioc3_get_wakeup_time; - efi.set_wakeup_time = ioc3_set_wakeup_time; - - return 0; -} - -module_init(efi_ioc3_time_init); diff -Nru a/arch/ia64/sn/io/hcl.c b/arch/ia64/sn/io/hcl.c --- a/arch/ia64/sn/io/hcl.c Tue Feb 25 10:47:06 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1515 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * hcl - SGI's Hardware Graph compatibility layer. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER" -#define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE" -#define HCL_TEMP_NAME_LEN 44 -#define HCL_VERSION "1.0" -devfs_handle_t hwgraph_root = NULL; -devfs_handle_t linux_busnum = NULL; - -/* - * Debug flag definition. - */ -#define OPTION_NONE 0x00 -#define HCL_DEBUG_NONE 0x00000 -#define HCL_DEBUG_ALL 0x0ffff -#if defined(CONFIG_HCL_DEBUG) -static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; -#endif -static unsigned int hcl_debug = HCL_DEBUG_NONE; -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) -static unsigned int boot_options = OPTION_NONE; -#endif - -/* - * Some Global definitions. - */ -devfs_handle_t hcl_handle = NULL; - -invplace_t invplace_none = { - GRAPH_VERTEX_NONE, - GRAPH_VERTEX_PLACE_NONE, - NULL -}; - -/* - * HCL device driver. - * The purpose of this device driver is to provide a facility - * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path - * to manipulate label entries without having to implement - * system call interfaces. This methodology will enable us to - * make this feature module loadable. - */ -static int hcl_open(struct inode * inode, struct file * filp) -{ - if (hcl_debug) { - printk("HCL: hcl_open called.\n"); - } - - return(0); - -} - -static int hcl_close(struct inode * inode, struct file * filp) -{ - - if (hcl_debug) { - printk("HCL: hcl_close called.\n"); - } - - return(0); - -} - -static int hcl_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - - if (hcl_debug) { - printk("HCL: hcl_ioctl called.\n"); - } - - switch (cmd) { - default: - if (hcl_debug) { - printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd); - } - } - - return(0); - -} - -struct file_operations hcl_fops = { - (struct module *)0, - NULL, /* lseek - default */ - NULL, /* read - general block-dev read */ - NULL, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* poll */ - hcl_ioctl, /* ioctl */ - NULL, /* mmap */ - hcl_open, /* open */ - NULL, /* flush */ - hcl_close, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* lock */ - NULL, /* readv */ - NULL, /* writev */ -}; - - -/* - * init_hcl() - Boot time initialization. Ensure that it is called - * after devfs has been initialized. - * - * For now this routine is being called out of devfs/base.c. Actually - * Not a bad place to be .. - * - */ -#ifdef MODULE -int init_module (void) -#else -int __init init_hcl(void) -#endif -{ - extern void string_table_init(struct string_table *); - extern struct string_table label_string_table; - extern int init_ifconfig_net(void); - int rv = 0; - -#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) - printk ("\n%s: v%s Colin Ngam (cngam@sgi.com)\n", - HCL_NAME, HCL_VERSION); - - hcl_debug = hcl_debug_init; - printk ("%s: hcl_debug: 0x%0x\n", HCL_NAME, hcl_debug); - printk ("\n%s: boot_options: 0x%0x\n", HCL_NAME, boot_options); -#endif - - /* - * Create the hwgraph_root on devfs. - */ - rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); - if (rv) - printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); - - /* - * Create the hcl driver to support inventory entry manipulations. - * By default, it is expected that devfs is mounted on /dev. - * - */ - hcl_handle = hwgraph_register(hwgraph_root, ".hcl", - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &hcl_fops, NULL); - - if (hcl_handle == NULL) { - panic("HCL: Unable to create HCL Driver in init_hcl().\n"); - return(0); - } - - /* - * Initialize the HCL string table. - */ - string_table_init(&label_string_table); - - /* - * Create the directory that links Linux bus numbers to our Xwidget. - */ - rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); - if (linux_busnum == NULL) { - panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); - return(0); - } - - /* - * Initialize the ifconfgi_net driver that does network devices - * Persistent Naming. - */ - init_ifconfig_net(); - - return(0); - -} - - -/* - * hcl_setup() - Process boot time parameters if given. - * "hcl=" - * This routine gets called only if "hcl=" is given in the - * boot line and before init_hcl(). - * - * We currently do not have any boot options .. when we do, - * functionalities can be added here. - * - */ -static int __init hcl_setup(char *str) -{ - while ( (*str != '\0') && !isspace (*str) ) - { -#ifdef CONFIG_HCL_DEBUG - if (strncmp (str, "all", 3) == 0) { - hcl_debug_init |= HCL_DEBUG_ALL; - str += 3; - } else - return 0; -#endif - if (*str != ',') return 0; - ++str; - } - - return 1; - -} - -__setup("hcl=", hcl_setup); - - -/* - * Set device specific "fast information". - * - */ -void -hwgraph_fastinfo_set(devfs_handle_t de, arbitrary_info_t fastinfo) -{ - - if (hcl_debug) { - printk("HCL: hwgraph_fastinfo_set handle 0x%p fastinfo %ld\n", (void *)de, fastinfo); - } - - labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL); - -} - - -/* - * Get device specific "fast information". - * - */ -arbitrary_info_t -hwgraph_fastinfo_get(devfs_handle_t de) -{ - arbitrary_info_t fastinfo; - int rv; - - if (!de) { - printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n"); - return(-1); - } - - rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo); - if (rv == 0) - return(fastinfo); - - return(0); -} - - -/* - * hwgraph_connectpt_set - Sets the connect point handle in de to the - * given connect_de handle. By default, the connect point of the - * devfs node is the parent. This effectively changes this assumption. - */ -int -hwgraph_connectpt_set(devfs_handle_t de, devfs_handle_t connect_de) -{ - int rv; - - if (!de) - return(-1); - - rv = labelcl_info_connectpt_set(de, connect_de); - - return(rv); -} - - -/* - * hwgraph_connectpt_get: Returns the entry's connect point in the devfs - * tree. - */ -devfs_handle_t -hwgraph_connectpt_get(devfs_handle_t de) -{ - int rv; - arbitrary_info_t info; - devfs_handle_t connect; - - rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); - if (rv != 0) { - return(NULL); - } - - connect = (devfs_handle_t)info; - return(connect); - -} - - -/* - * hwgraph_mk_dir - Creates a directory entry with devfs. - * Note that a directory entry in devfs can have children - * but it cannot be a char|block special file. - */ -devfs_handle_t -hwgraph_mk_dir(devfs_handle_t de, const char *name, - unsigned int namelen, void *info) -{ - - int rv; - labelcl_info_t *labelcl_info = NULL; - devfs_handle_t new_devfs_handle = NULL; - devfs_handle_t parent = NULL; - - /* - * Create the device info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(NULL); - - /* - * Create a devfs entry. - */ - new_devfs_handle = devfs_mk_dir(de, name, (void *)labelcl_info); - if (!new_devfs_handle) { - labelcl_info_destroy(labelcl_info); - return(NULL); - } - - /* - * Get the parent handle. - */ - parent = devfs_get_parent (new_devfs_handle); - - /* - * To provide the same semantics as the hwgraph, set the connect point. - */ - rv = hwgraph_connectpt_set(new_devfs_handle, parent); - if (!rv) { - /* - * We need to clean up! - */ - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - return(new_devfs_handle); - -} - -/* - * hwgraph_vertex_create - Create a vertex by giving it a temp name. - */ - -/* - * hwgraph_path_add - Create a directory node with the given path starting - * from the given devfs_handle_t. - */ -extern char * dev_to_name(devfs_handle_t, char *, uint); -int -hwgraph_path_add(devfs_handle_t fromv, - char *path, - devfs_handle_t *new_de) -{ - - unsigned int namelen = strlen(path); - int rv; - - /* - * We need to handle the case when fromv is NULL .. - * in this case we need to create the path from the - * hwgraph root! - */ - if (fromv == NULL) - fromv = hwgraph_root; - - /* - * check the entry doesn't already exist, if it does - * then we simply want new_de to point to it (otherwise - * we'll overwrite the existing labelcl_info struct) - */ - rv = hwgraph_edge_get(fromv, path, new_de); - if (rv) { /* couldn't find entry so we create it */ - *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL); - if (new_de == NULL) - return(-1); - else - return(0); - } - else - return(0); - -} - -/* - * hwgraph_register - Creates a file entry with devfs. - * Note that a file entry cannot have children .. it is like a - * char|block special vertex in hwgraph. - */ -devfs_handle_t -hwgraph_register(devfs_handle_t de, const char *name, - unsigned int namelen, unsigned int flags, - unsigned int major, unsigned int minor, - umode_t mode, uid_t uid, gid_t gid, - struct file_operations *fops, - void *info) -{ - - int rv; - void *labelcl_info = NULL; - devfs_handle_t new_devfs_handle = NULL; - devfs_handle_t parent = NULL; - - /* - * Create the labelcl info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(NULL); - - /* - * Create a devfs entry. - */ - new_devfs_handle = devfs_register(de, name, flags, major, - minor, mode, fops, labelcl_info); - if (!new_devfs_handle) { - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - return(NULL); - } - - /* - * Get the parent handle. - */ - if (de == NULL) - parent = devfs_get_parent (new_devfs_handle); - else - parent = de; - - /* - * To provide the same semantics as the hwgraph, set the connect point. - */ - rv = hwgraph_connectpt_set(new_devfs_handle, parent); - if (rv) { - /* - * We need to clean up! - */ - printk(KERN_WARNING "HCL: Unable to set the connect point to its parent 0x%p\n", - (void *)new_devfs_handle); - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - return(new_devfs_handle); - -} - - -/* - * hwgraph_mk_symlink - Create a symbolic link. - */ -int -hwgraph_mk_symlink(devfs_handle_t de, const char *name, unsigned int namelen, - unsigned int flags, const char *link, unsigned int linklen, - devfs_handle_t *handle, void *info) -{ - - void *labelcl_info = NULL; - int status = 0; - devfs_handle_t new_devfs_handle = NULL; - - /* - * Create the labelcl info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(-1); - - /* - * Create a symbolic link devfs entry. - */ - status = devfs_mk_symlink(de, name, flags, link, - &new_devfs_handle, labelcl_info); - if ( (!new_devfs_handle) || (!status) ){ - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - return(-1); - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_devfs_handle, (arbitrary_info_t)info); - - *handle = new_devfs_handle; - return(0); - -} - -/* - * hwgraph_vertex_get_next - this routine returns the next sibbling for the - * device entry given in de. If there are no more sibbling, NULL - * is returned in next_sibbling. - * - * Currently we do not have any protection against de being deleted - * while it's handle is being held. - */ -int -hwgraph_vertex_get_next(devfs_handle_t *next_sibbling, devfs_handle_t *de) -{ - *next_sibbling = devfs_get_next_sibling (*de); - - if (*next_sibbling != NULL) - *de = *next_sibbling; - return (0); -} - - -/* - * hwgraph_vertex_destroy - Destroy the devfs entry - */ -int -hwgraph_vertex_destroy(devfs_handle_t de) -{ - - void *labelcl_info = NULL; - - labelcl_info = devfs_get_info(de); - devfs_unregister(de); - - if (labelcl_info) - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - - return(0); -} - -/* -** See if a vertex has an outgoing edge with a specified name. -** Vertices in the hwgraph *implicitly* contain these edges: -** "." refers to "current vertex" -** ".." refers to "connect point vertex" -** "char" refers to current vertex (character device access) -** "block" refers to current vertex (block device access) -*/ - -/* - * hwgraph_edge_add - This routines has changed from the original conext. - * All it does now is to create a symbolic link from "from" to "to". - */ -/* ARGSUSED */ -int -hwgraph_edge_add(devfs_handle_t from, devfs_handle_t to, char *name) -{ - - char *path; - char *s1; - char *index; - int name_start; - devfs_handle_t handle = NULL; - int rv; - int i, count; - - path = kmalloc(1024, GFP_KERNEL); - memset(path, 0x0, 1024); - name_start = devfs_generate_path (from, path, 1024); - s1 = &path[name_start]; - count = 0; - while (1) { - index = strstr (s1, "/"); - if (index) { - count++; - s1 = ++index; - } else { - count++; - break; - } - } - - memset(path, 0x0, 1024); - name_start = devfs_generate_path (to, path, 1024); - - for (i = 0; i < count; i++) { - strcat(path,"../"); - } - - strcat(path, &path[name_start]); - - /* - * Otherwise, just create a symlink to the vertex. - * In this case the vertex was previous created with a REAL pathname. - */ - rv = devfs_mk_symlink (from, (const char *)name, - DEVFS_FL_DEFAULT, path, - &handle, NULL); - - name_start = devfs_generate_path (handle, path, 1024); - return(rv); - - -} -/* ARGSUSED */ -int -hwgraph_edge_get(devfs_handle_t from, char *name, devfs_handle_t *toptr) -{ - - int namelen = 0; - devfs_handle_t target_handle = NULL; - - if (name == NULL) - return(-1); - - if (toptr == NULL) - return(-1); - - /* - * If the name is "." just return the current devfs entry handle. - */ - if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) { - if (toptr) { - *toptr = from; - } - } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) { - /* - * Hmmm .. should we return the connect point or parent .. - * see in hwgraph, the concept of parent is the connectpt! - * - * Maybe we should see whether the connectpt is set .. if - * not just return the parent! - */ - target_handle = hwgraph_connectpt_get(from); - if (target_handle) { - /* - * Just return the connect point. - */ - *toptr = target_handle; - return(0); - } - target_handle = devfs_get_parent(from); - *toptr = target_handle; - - } else { - /* - * Call devfs to get the devfs entry. - */ - namelen = (int) strlen(name); - target_handle = devfs_get_handle(from, name, 1); /* Yes traverse symbolic links */ - if (target_handle == NULL) - return(-1); - else - *toptr = target_handle; - } - - return(0); -} - - -/* - * hwgraph_edge_get_next - Retrieves the next sibbling given the current - * entry number "placeptr". - * - * Allow the caller to retrieve walk through the sibblings of "source" - * devfs_handle_t. The implicit edges "." and ".." is returned first - * followed by each of the real children. - * - * We may end up returning garbage if another thread perform any deletion - * in this directory before "placeptr". - * - */ -/* ARGSUSED */ -int -hwgraph_edge_get_next(devfs_handle_t source, char *name, devfs_handle_t *target, - uint *placeptr) - -{ - - uint which_place; - unsigned int namelen = 0; - const char *tempname = NULL; - - if (placeptr == NULL) - return(-1); - - which_place = *placeptr; - -again: - if (which_place <= HWGRAPH_RESERVED_PLACES) { - if (which_place == EDGE_PLACE_WANT_CURRENT) { - /* - * Looking for "." - * Return the current devfs handle. - */ - if (name != NULL) - strcpy(name, HWGRAPH_EDGELBL_DOT); - - if (target != NULL) { - *target = source; - /* XXX should incr "source" ref count here if we - * ever implement ref counts */ - } - - } else if (which_place == EDGE_PLACE_WANT_CONNECTPT) { - /* - * Looking for the connect point or parent. - * If the connect point is set .. it returns the connect point. - * Otherwise, it returns the parent .. will we support - * connect point? - */ - devfs_handle_t connect_point = hwgraph_connectpt_get(source); - - if (connect_point == NULL) { - /* - * No connectpoint set .. either the User - * explicitly NULL it or this node was not - * created via hcl. - */ - which_place++; - goto again; - } - - if (name != NULL) - strcpy(name, HWGRAPH_EDGELBL_DOTDOT); - - if (target != NULL) - *target = connect_point; - - } else if (which_place == EDGE_PLACE_WANT_REAL_EDGES) { - /* - * return first "real" entry in directory, and increment - * placeptr. Next time around we should have - * which_place > HWGRAPH_RESERVED_EDGES so we'll fall through - * this nested if block. - */ - *target = devfs_get_first_child(source); - if (*target && name) { - tempname = devfs_get_name(*target, &namelen); - if (tempname && namelen) - strcpy(name, tempname); - } - - *placeptr = which_place + 1; - return (0); - } - - *placeptr = which_place+1; - return(0); - } - - /* - * walk linked list, (which_place - HWGRAPH_RESERVED_PLACES) times - */ - { - devfs_handle_t curr; - int i = 0; - - for (curr=devfs_get_first_child(source), i= i+HWGRAPH_RESERVED_PLACES; - curr!=NULL && iinv_next) { - if ((int)class != -1 && old_pinv->inv_class != class) - continue; - if ((int)type != -1 && old_pinv->inv_type != type) - continue; - if ((int)state != -1 && old_pinv->inv_state != state) - continue; - if ((int)controller != -1 - && old_pinv->inv_controller != controller) - continue; - if ((int)unit != -1 && old_pinv->inv_unit != unit) - continue; - - /* exact duplicate of previously-added inventory item */ - rv = LABELCL_DUP; - goto failure; - } - - /* Not a duplicate, so we know that we need to add something. */ - if (pinv == NULL) { - /* Release lock while we wait for memory. */ - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - pinv = (inventory_t *)kmalloc(sizeof(inventory_t), GFP_KERNEL); - replace_in_inventory(pinv, class, type, controller, unit, state); - goto again; - } - - pinv->inv_next = NULL; - if (last_pinv) { - last_pinv->inv_next = pinv; - } else { - rv = labelcl_info_add_LBL(de, INFO_LBL_INVENT, - sizeof(inventory_t), (arbitrary_info_t)pinv); - - if (!rv) - goto failure; - } - - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - return(0); - -failure: - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - if (pinv) - kfree(pinv); - return(rv); -} - - -/* - * hwgraph_inventory_remove - Removes an inventory entry. - * - * Remove an inventory item associated with a vertex. It is the caller's - * responsibility to make sure that there are no races between removing - * inventory from a vertex and simultaneously removing that vertex. -*/ -int -hwgraph_inventory_remove( devfs_handle_t de, - int class, - int type, - major_t controller, - minor_t unit, - int state) -{ - inventory_t *pinv = NULL, *last_pinv = NULL, *next_pinv = NULL; - labelcl_error_t rv; - - /* - * We never remove stuff from ".invent" .. - */ - if (!de) - return (-1); - - /* - * Remove our inventory data to the list of inventory data - * associated with this vertex. - */ - /* GRAPH_LOCK_UPDATE(&invent_lock); */ - rv = labelcl_info_get_LBL(de, - INFO_LBL_INVENT, - NULL, (arbitrary_info_t *)&pinv); - if (rv != LABELCL_SUCCESS) - goto failure; - - /* - * Search through inventory items associated with this - * vertex, looking for a match. - */ - for (;pinv; pinv = next_pinv) { - next_pinv = pinv->inv_next; - - if(((int)class == -1 || pinv->inv_class == class) && - ((int)type == -1 || pinv->inv_type == type) && - ((int)state == -1 || pinv->inv_state == state) && - ((int)controller == -1 || pinv->inv_controller == controller) && - ((int)unit == -1 || pinv->inv_unit == unit)) { - - /* Found a matching inventory item. Remove it. */ - if (last_pinv) { - last_pinv->inv_next = pinv->inv_next; - } else { - rv = hwgraph_info_replace_LBL(de, INFO_LBL_INVENT, (arbitrary_info_t)pinv->inv_next, NULL); - if (rv != LABELCL_SUCCESS) - goto failure; - } - - pinv->inv_next = NULL; /* sanity */ - kfree(pinv); - } else - last_pinv = pinv; - } - - if (last_pinv == NULL) { - rv = hwgraph_info_remove_LBL(de, INFO_LBL_INVENT, NULL); - if (rv != LABELCL_SUCCESS) - goto failure; - } - - rv = LABELCL_SUCCESS; - -failure: - /* GRAPH_LOCK_DONE_UPDATE(&invent_lock); */ - return(rv); -} - -/* - * hwgraph_inventory_get_next - Get next inventory item associated with the - * specified vertex. - * - * No locking is really needed. We don't yet have the ability - * to remove inventory items, and new items are always added to - * the end of a vertex' inventory list. - * - * However, a devfs entry can be removed! -*/ -int -hwgraph_inventory_get_next(devfs_handle_t de, invplace_t *place, inventory_t **ppinv) -{ - inventory_t *pinv; - labelcl_error_t rv; - - if (de == NULL) - return(LABELCL_BAD_PARAM); - - if (place->invplace_vhdl == NULL) { - place->invplace_vhdl = de; - place->invplace_inv = NULL; - } - - if (de != place->invplace_vhdl) - return(LABELCL_BAD_PARAM); - - if (place->invplace_inv == NULL) { - /* Just starting on this vertex */ - rv = labelcl_info_get_LBL(de, INFO_LBL_INVENT, - NULL, (arbitrary_info_t *)&pinv); - if (rv != LABELCL_SUCCESS) - return(LABELCL_NOT_FOUND); - - } else { - /* Advance to next item on this vertex */ - pinv = place->invplace_inv->inv_next; - } - place->invplace_inv = pinv; - *ppinv = pinv; - - return(LABELCL_SUCCESS); -} - -/* - * hwgraph_controller_num_get - Returns the controller number in the inventory - * entry. - */ -int -hwgraph_controller_num_get(devfs_handle_t device) -{ - inventory_t *pinv; - invplace_t invplace = { NULL, NULL, NULL }; - int val = -1; - if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) { - val = (pinv->inv_class == INV_NETWORK)? pinv->inv_unit: pinv->inv_controller; - } -#ifdef DEBUG - /* - * It does not make any sense to call this on vertexes with multiple - * inventory structs chained together - */ - if ( device_inventory_get_next(device, &invplace) != NULL ) { - printk("Should panic here ... !\n"); -#endif - return (val); -} - -/* - * hwgraph_controller_num_set - Sets the controller number in the inventory - * entry. - */ -void -hwgraph_controller_num_set(devfs_handle_t device, int contr_num) -{ - inventory_t *pinv; - invplace_t invplace = { NULL, NULL, NULL }; - if ((pinv = device_inventory_get_next(device, &invplace)) != NULL) { - if (pinv->inv_class == INV_NETWORK) - pinv->inv_unit = contr_num; - else { - if (pinv->inv_class == INV_FCNODE) - pinv = device_inventory_get_next(device, &invplace); - if (pinv != NULL) - pinv->inv_controller = contr_num; - } - } -#ifdef DEBUG - /* - * It does not make any sense to call this on vertexes with multiple - * inventory structs chained together - */ - if(pinv != NULL) - ASSERT(device_inventory_get_next(device, &invplace) == NULL); -#endif -} - -/* - * Find the canonical name for a given vertex by walking back through - * connectpt's until we hit the hwgraph root vertex (or until we run - * out of buffer space or until something goes wrong). - * - * COMPATIBILITY FUNCTIONALITY - * Walks back through 'parents', not necessarily the same as connectpts. - * - * Need to resolve the fact that devfs does not return the path from - * "/" but rather it just stops right before /dev .. - */ -int -hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen) -{ - char *locbuf; - int pos; - - if (buflen < 1) - return(-1); /* XXX should be GRAPH_BAD_PARAM ? */ - - locbuf = kmalloc(buflen, GFP_KERNEL); - - pos = devfs_generate_path(vhdl, locbuf, buflen); - if (pos < 0) { - kfree(locbuf); - return pos; - } - - strcpy(buf, &locbuf[pos]); - kfree(locbuf); - return 0; -} - -/* -** vertex_to_name converts a vertex into a canonical name by walking -** back through connect points until we hit the hwgraph root (or until -** we run out of buffer space). -** -** Usually returns a pointer to the original buffer, filled in as -** appropriate. If the buffer is too small to hold the entire name, -** or if anything goes wrong while determining the name, vertex_to_name -** returns "UnknownDevice". -*/ - -#define DEVNAME_UNKNOWN "UnknownDevice" - -char * -vertex_to_name(devfs_handle_t vhdl, char *buf, uint buflen) -{ - if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS) - return(buf); - else - return(DEVNAME_UNKNOWN); -} - -#ifdef LATER -/* -** Return the compact node id of the node that ultimately "owns" the specified -** vertex. In order to do this, we walk back through masters and connect points -** until we reach a vertex that represents a node. -*/ -cnodeid_t -master_node_get(devfs_handle_t vhdl) -{ - cnodeid_t cnodeid; - devfs_handle_t master; - - for (;;) { - cnodeid = nodevertex_to_cnodeid(vhdl); - if (cnodeid != CNODEID_NONE) - return(cnodeid); - - master = device_master_get(vhdl); - - /* Check for exceptional cases */ - if (master == vhdl) { - /* Since we got a reference to the "master" thru - * device_master_get() we should decrement - * its reference count by 1 - */ - hwgraph_vertex_unref(master); - return(CNODEID_NONE); - } - - if (master == GRAPH_VERTEX_NONE) { - master = hwgraph_connectpt_get(vhdl); - if ((master == GRAPH_VERTEX_NONE) || - (master == vhdl)) { - if (master == vhdl) - /* Since we got a reference to the - * "master" thru - * hwgraph_connectpt_get() we should - * decrement its reference count by 1 - */ - hwgraph_vertex_unref(master); - return(CNODEID_NONE); - } - } - - vhdl = master; - /* Decrement the reference to "master" which was got - * either thru device_master_get() or hwgraph_connectpt_get() - * above. - */ - hwgraph_vertex_unref(master); - } -} - -/* - * Using the canonical path name to get hold of the desired vertex handle will - * not work on multi-hub sn0 nodes. Hence, we use the following (slightly - * convoluted) algorithm. - * - * - Start at the vertex corresponding to the driver (provided as input parameter) - * - Loop till you reach a vertex which has EDGE_LBL_MEMORY - * - If EDGE_LBL_CONN exists, follow that up. - * else if EDGE_LBL_MASTER exists, follow that up. - * else follow EDGE_LBL_DOTDOT up. - * - * * We should be at desired hub/heart vertex now * - * - Follow EDGE_LBL_CONN to the widget vertex. - * - * - return vertex handle of this widget. - */ -devfs_handle_t -mem_vhdl_get(devfs_handle_t drv_vhdl) -{ -devfs_handle_t cur_vhdl, cur_upper_vhdl; -devfs_handle_t tmp_mem_vhdl, mem_vhdl; -graph_error_t loop_rv; - - /* Initializations */ - cur_vhdl = drv_vhdl; - loop_rv = ~GRAPH_SUCCESS; - - /* Loop till current vertex has EDGE_LBL_MEMORY */ - while (loop_rv != GRAPH_SUCCESS) { - - if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &cur_upper_vhdl)) == GRAPH_SUCCESS) { - - } else if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_MASTER, &cur_upper_vhdl)) == GRAPH_SUCCESS) { - } else { /* Follow HWGRAPH_EDGELBL_DOTDOT up */ - (void) hwgraph_edge_get(cur_vhdl, HWGRAPH_EDGELBL_DOTDOT, &cur_upper_vhdl); - } - - cur_vhdl = cur_upper_vhdl; - -#if DEBUG && HWG_DEBUG - printf("Current vhdl %d \n", cur_vhdl); -#endif /* DEBUG */ - - loop_rv = hwgraph_edge_get(cur_vhdl, EDGE_LBL_MEMORY, &tmp_mem_vhdl); - } - - /* We should be at desired hub/heart vertex now */ - if ((hwgraph_edge_get(cur_vhdl, EDGE_LBL_CONN, &mem_vhdl)) != GRAPH_SUCCESS) - return (GRAPH_VERTEX_NONE); - - return (mem_vhdl); -} -#endif /* LATER */ - - -/* -** Add a char device -- if the driver supports it -- at a specified vertex. -*/ -graph_error_t -hwgraph_char_device_add( devfs_handle_t from, - char *path, - char *prefix, - devfs_handle_t *devhdl) -{ - devfs_handle_t xx = NULL; - - printk("WARNING: hwgraph_char_device_add() not supported .. use hwgraph_register.\n"); - *devhdl = xx; // Must set devhdl - return(GRAPH_SUCCESS); -} - -graph_error_t -hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr) -{ - printk("WARNING: hwgraph_edge_remove NOT supported.\n"); - return(GRAPH_ILLEGAL_REQUEST); -} - -graph_error_t -hwgraph_vertex_unref(devfs_handle_t vhdl) -{ - return(GRAPH_ILLEGAL_REQUEST); -} - - -EXPORT_SYMBOL(hwgraph_mk_dir); -EXPORT_SYMBOL(hwgraph_path_add); -EXPORT_SYMBOL(hwgraph_char_device_add); -EXPORT_SYMBOL(hwgraph_register); -EXPORT_SYMBOL(hwgraph_vertex_destroy); - -EXPORT_SYMBOL(hwgraph_fastinfo_get); -EXPORT_SYMBOL(hwgraph_edge_get); - -EXPORT_SYMBOL(hwgraph_fastinfo_set); -EXPORT_SYMBOL(hwgraph_connectpt_set); -EXPORT_SYMBOL(hwgraph_connectpt_get); -EXPORT_SYMBOL(hwgraph_edge_get_next); -EXPORT_SYMBOL(hwgraph_info_add_LBL); -EXPORT_SYMBOL(hwgraph_info_remove_LBL); -EXPORT_SYMBOL(hwgraph_info_replace_LBL); -EXPORT_SYMBOL(hwgraph_info_get_LBL); -EXPORT_SYMBOL(hwgraph_info_get_exported_LBL); -EXPORT_SYMBOL(hwgraph_info_get_next_LBL); -EXPORT_SYMBOL(hwgraph_info_export_LBL); -EXPORT_SYMBOL(hwgraph_info_unexport_LBL); -EXPORT_SYMBOL(hwgraph_path_lookup); -EXPORT_SYMBOL(hwgraph_traverse); -EXPORT_SYMBOL(hwgraph_path_to_vertex); -EXPORT_SYMBOL(hwgraph_path_to_dev); -EXPORT_SYMBOL(hwgraph_block_device_get); -EXPORT_SYMBOL(hwgraph_char_device_get); -EXPORT_SYMBOL(hwgraph_vertex_name_get); diff -Nru a/arch/ia64/sn/io/hcl_util.c b/arch/ia64/sn/io/hcl_util.c --- a/arch/ia64/sn/io/hcl_util.c Wed Dec 4 07:03:54 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,200 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static devfs_handle_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE; -extern devfs_handle_t hwgraph_root; - - -/* -** Return the "master" for a given vertex. A master vertex is a -** controller or adapter or other piece of hardware that the given -** vertex passes through on the way to the rest of the system. -*/ -devfs_handle_t -device_master_get(devfs_handle_t vhdl) -{ - graph_error_t rc; - devfs_handle_t master; - - rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master); - if (rc == GRAPH_SUCCESS) - return(master); - else - return(GRAPH_VERTEX_NONE); -} - -/* -** Set the master for a given vertex. -** Returns 0 on success, non-0 indicates failure -*/ -int -device_master_set(devfs_handle_t vhdl, devfs_handle_t master) -{ - graph_error_t rc; - - rc = hwgraph_edge_add(vhdl, master, EDGE_LBL_MASTER); - return(rc != GRAPH_SUCCESS); -} - - -/* -** Return the compact node id of the node that ultimately "owns" the specified -** vertex. In order to do this, we walk back through masters and connect points -** until we reach a vertex that represents a node. -*/ -cnodeid_t -master_node_get(devfs_handle_t vhdl) -{ - cnodeid_t cnodeid; - devfs_handle_t master; - - for (;;) { - cnodeid = nodevertex_to_cnodeid(vhdl); - if (cnodeid != CNODEID_NONE) - return(cnodeid); - - master = device_master_get(vhdl); - - /* Check for exceptional cases */ - if (master == vhdl) { - /* Since we got a reference to the "master" thru - * device_master_get() we should decrement - * its reference count by 1 - */ - return(CNODEID_NONE); - } - - if (master == GRAPH_VERTEX_NONE) { - master = hwgraph_connectpt_get(vhdl); - if ((master == GRAPH_VERTEX_NONE) || - (master == vhdl)) { - return(CNODEID_NONE); - } - } - - vhdl = master; - } -} - -static devfs_handle_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; -extern int maxcpus; - -void -mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid) -{ - if (cpuid == CPU_NONE) - return; - - (void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT, - (arbitrary_info_t)cpuid); - { - char cpuid_buffer[10]; - - if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) { - (void)hwgraph_path_add( hwgraph_root, - EDGE_LBL_CPUNUM, - &hwgraph_all_cpuids); - } - - sprintf(cpuid_buffer, "%ld", cpuid); - (void)hwgraph_edge_add( hwgraph_all_cpuids, - vhdl, - cpuid_buffer); - } -} - -/* -** If the specified device represents a node, return its -** compact node ID; otherwise, return CNODEID_NONE. -*/ -cnodeid_t -nodevertex_to_cnodeid(devfs_handle_t vhdl) -{ - int rv = 0; - arbitrary_info_t cnodeid = CNODEID_NONE; - - rv = labelcl_info_get_LBL(vhdl, INFO_LBL_CNODEID, NULL, &cnodeid); - - return((cnodeid_t)cnodeid); -} - -void -mark_nodevertex_as_node(devfs_handle_t vhdl, cnodeid_t cnodeid) -{ - if (cnodeid == CNODEID_NONE) - return; - - cnodeid_to_vertex(cnodeid) = vhdl; - labelcl_info_add_LBL(vhdl, INFO_LBL_CNODEID, INFO_DESC_EXPORT, - (arbitrary_info_t)cnodeid); - - { - char cnodeid_buffer[10]; - - if (hwgraph_all_cnodes == GRAPH_VERTEX_NONE) { - (void)hwgraph_path_add( hwgraph_root, - EDGE_LBL_NODENUM, - &hwgraph_all_cnodes); - } - - sprintf(cnodeid_buffer, "%d", cnodeid); - (void)hwgraph_edge_add( hwgraph_all_cnodes, - vhdl, - cnodeid_buffer); - } -} - -/* -** If the specified device represents a CPU, return its cpuid; -** otherwise, return CPU_NONE. -*/ -cpuid_t -cpuvertex_to_cpuid(devfs_handle_t vhdl) -{ - arbitrary_info_t cpuid = CPU_NONE; - - (void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid); - - return((cpuid_t)cpuid); -} - - -/* -** dev_to_name converts a devfs_handle_t into a canonical name. If the devfs_handle_t -** represents a vertex in the hardware graph, it is converted in the -** normal way for vertices. If the devfs_handle_t is an old devfs_handle_t (one which -** does not represent a hwgraph vertex), we synthesize a name based -** on major/minor number. -** -** Usually returns a pointer to the original buffer, filled in as -** appropriate. If the buffer is too small to hold the entire name, -** or if anything goes wrong while determining the name, dev_to_name -** returns "UnknownDevice". -*/ -char * -dev_to_name(devfs_handle_t dev, char *buf, uint buflen) -{ - return(vertex_to_name(dev, buf, buflen)); -} - - diff -Nru a/arch/ia64/sn/io/hubdev.c b/arch/ia64/sn/io/hubdev.c --- a/arch/ia64/sn/io/hubdev.c Wed Dec 4 07:04:10 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,132 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct hubdev_callout { - int (*attach_method)(devfs_handle_t); - struct hubdev_callout *fp; -}; - -typedef struct hubdev_callout hubdev_callout_t; - -mutex_t hubdev_callout_mutex; -hubdev_callout_t *hubdev_callout_list = NULL; - -void -hubdev_init(void) -{ - mutex_init(&hubdev_callout_mutex); - hubdev_callout_list = NULL; -} - -void -hubdev_register(int (*attach_method)(devfs_handle_t)) -{ - hubdev_callout_t *callout; - - ASSERT(attach_method); - - callout = (hubdev_callout_t *)snia_kmem_zalloc(sizeof(hubdev_callout_t), KM_SLEEP); - ASSERT(callout); - - mutex_lock(&hubdev_callout_mutex); - /* - * Insert at the end of the list - */ - callout->fp = hubdev_callout_list; - hubdev_callout_list = callout; - callout->attach_method = attach_method; - mutex_unlock(&hubdev_callout_mutex); -} - -int -hubdev_unregister(int (*attach_method)(devfs_handle_t)) -{ - hubdev_callout_t **p; - - ASSERT(attach_method); - - mutex_lock(&hubdev_callout_mutex); - /* - * Remove registry element containing attach_method - */ - for (p = &hubdev_callout_list; *p != NULL; p = &(*p)->fp) { - if ((*p)->attach_method == attach_method) { - hubdev_callout_t* victim = *p; - *p = (*p)->fp; - kfree(victim); - mutex_unlock(&hubdev_callout_mutex); - return (0); - } - } - mutex_unlock(&hubdev_callout_mutex); - return (ENOENT); -} - - -int -hubdev_docallouts(devfs_handle_t hub) -{ - hubdev_callout_t *p; - int errcode; - - mutex_lock(&hubdev_callout_mutex); - - for (p = hubdev_callout_list; p != NULL; p = p->fp) { - ASSERT(p->attach_method); - errcode = (*p->attach_method)(hub); - if (errcode != 0) { - mutex_unlock(&hubdev_callout_mutex); - return (errcode); - } - } - mutex_unlock(&hubdev_callout_mutex); - return (0); -} - -/* - * Given a hub vertex, return the base address of the Hspec space - * for that hub. - */ - -#if defined(CONFIG_IA64_SGI_SN1) - -caddr_t -hubdev_prombase_get(devfs_handle_t hub) -{ - hubinfo_t hinfo = NULL; - - hubinfo_get(hub, &hinfo); - ASSERT(hinfo); - - return ((caddr_t)NODE_RBOOT_BASE(hinfo->h_nasid)); -} - -cnodeid_t -hubdev_cnodeid_get(devfs_handle_t hub) -{ - hubinfo_t hinfo = NULL; - hubinfo_get(hub, &hinfo); - ASSERT(hinfo); - - return hinfo->h_cnodeid; -} - -#endif /* CONFIG_IA64_SGI_SN1 */ diff -Nru a/arch/ia64/sn/io/hubspc.c b/arch/ia64/sn/io/hubspc.c --- a/arch/ia64/sn/io/hubspc.c Tue Dec 3 10:07:23 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,251 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * hubspc.c - Hub Memory Space Management Driver - * This driver implements the managers for the following - * memory resources: - * 1) reference counters - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Uncomment the following line for tracing */ -/* #define HUBSPC_DEBUG 1 */ - -int hubspc_devflag = D_MP; - - -/***********************************************************************/ -/* CPU Prom Space */ -/***********************************************************************/ - -typedef struct cpuprom_info { - devfs_handle_t prom_dev; - devfs_handle_t nodevrtx; - struct cpuprom_info *next; -}cpuprom_info_t; - -static cpuprom_info_t *cpuprom_head; -static spinlock_t cpuprom_spinlock; -#define PROM_LOCK() mutex_spinlock(&cpuprom_spinlock) -#define PROM_UNLOCK(s) mutex_spinunlock(&cpuprom_spinlock, (s)) - -/* - * Add prominfo to the linked list maintained. - */ -void -prominfo_add(devfs_handle_t hub, devfs_handle_t prom) -{ - cpuprom_info_t *info; - unsigned long s; - - info = kmalloc(sizeof(cpuprom_info_t), GFP_KERNEL); - ASSERT(info); - info->prom_dev = prom; - info->nodevrtx = hub; - - - s = PROM_LOCK(); - info->next = cpuprom_head; - cpuprom_head = info; - PROM_UNLOCK(s); -} - -void -prominfo_del(devfs_handle_t prom) -{ - unsigned long s; - cpuprom_info_t *info; - cpuprom_info_t **prev; - - s = PROM_LOCK(); - prev = &cpuprom_head; - while ( (info = *prev) ) { - if (info->prom_dev == prom) { - *prev = info->next; - PROM_UNLOCK(s); - return; - } - - prev = &info->next; - } - PROM_UNLOCK(s); - ASSERT(0); -} - -devfs_handle_t -prominfo_nodeget(devfs_handle_t prom) -{ - unsigned long s; - cpuprom_info_t *info; - - s = PROM_LOCK(); - info = cpuprom_head; - while (info) { - if(info->prom_dev == prom) { - PROM_UNLOCK(s); - return info->nodevrtx; - } - info = info->next; - } - PROM_UNLOCK(s); - return 0; -} - -#if defined(CONFIG_IA64_SGI_SN1) -#define SN_PROMVERSION INV_IP35PROM - -/* Add "detailed" labelled inventory information to the - * prom vertex - */ -void -cpuprom_detailed_inventory_info_add(devfs_handle_t prom_dev,devfs_handle_t node) -{ - invent_miscinfo_t *cpuprom_inventory_info; - extern invent_generic_t *klhwg_invent_alloc(cnodeid_t cnode, - int class, int size); - cnodeid_t cnode = hubdev_cnodeid_get(node); - - /* Allocate memory for the extra inventory information - * for the prom - */ - cpuprom_inventory_info = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); - - ASSERT(cpuprom_inventory_info); - - /* Set the enabled flag so that the hinv interprets this - * information - */ - cpuprom_inventory_info->im_gen.ig_flag = INVENT_ENABLED; - cpuprom_inventory_info->im_type = SN_PROMVERSION; - /* Store prom revision into inventory information */ - cpuprom_inventory_info->im_rev = IP27CONFIG.pvers_rev; - cpuprom_inventory_info->im_version = IP27CONFIG.pvers_vers; - - /* Store this info as labelled information hanging off the - * prom device vertex - */ - hwgraph_info_add_LBL(prom_dev, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) cpuprom_inventory_info); - /* Export this information so that user programs can get to - * this by using attr_get() - */ - hwgraph_info_export_LBL(prom_dev, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/***********************************************************************/ -/* Base Hub Space Driver */ -/***********************************************************************/ - -/* - * hubspc_init - * Registration of the hubspc devices with the hub manager - */ -void -hubspc_init(void) -{ - /* - * Register with the hub manager - */ - - /* The reference counters */ -#if defined(CONFIG_IA64_SGI_SN1) - hubdev_register(mem_refcnt_attach); -#endif - -#ifdef CONFIG_IA64_SGI_SN1 - /* L1 system controller link */ - if ( !IS_RUNNING_ON_SIMULATOR() ) { - /* initialize the L1 link */ - extern void l1_init(void); - l1_init(); - } -#endif /* CONFIG_IA64_SGI_SN1 */ -#ifdef HUBSPC_DEBUG - printk("hubspc_init: Completed\n"); -#endif /* HUBSPC_DEBUG */ - /* Initialize spinlocks */ - mutex_spinlock_init(&cpuprom_spinlock); -} - -/* ARGSUSED */ -int -hubspc_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) -{ - return (0); -} - - -/* ARGSUSED */ -int -hubspc_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return (0); -} - -/* ARGSUSED */ -int -hubspc_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - /*REFERENCED*/ - int errcode = 0; - - /* check validity of request */ - if( len == 0 ) { - return -ENXIO; - } - - return errcode; -} - -/* ARGSUSED */ -int -hubspc_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return (0); - -} - -/* ARGSUSED */ -int -hubspc_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int mode, - cred_t *cred_p, - int *rvalp) -{ - return (0); - -} diff -Nru a/arch/ia64/sn/io/hwgfs/Makefile b/arch/ia64/sn/io/hwgfs/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/Makefile Fri May 16 11:50:50 2003 @@ -0,0 +1,13 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += hcl.o labelcl.o hcl_util.o invent_stub.o \ + ramfs.o interface.o diff -Nru a/arch/ia64/sn/io/hwgfs/hcl.c b/arch/ia64/sn/io/hwgfs/hcl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/hcl.c Mon May 19 05:42:35 2003 @@ -0,0 +1,938 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * hcl - SGI's Hardware Graph compatibility layer. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* needed for smp_lock.h :( */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HCL_NAME "SGI-HWGRAPH COMPATIBILITY DRIVER" +#define HCL_TEMP_NAME "HCL_TEMP_NAME_USED_FOR_HWGRAPH_VERTEX_CREATE" +#define HCL_TEMP_NAME_LEN 44 +#define HCL_VERSION "1.0" + +#define vertex_hdl_t hwgfs_handle_t +vertex_hdl_t hwgraph_root; +vertex_hdl_t linux_busnum; + +extern void pci_bus_cvlink_init(void); + +/* + * Debug flag definition. + */ +#define OPTION_NONE 0x00 +#define HCL_DEBUG_NONE 0x00000 +#define HCL_DEBUG_ALL 0x0ffff +#if defined(CONFIG_HCL_DEBUG) +static unsigned int hcl_debug_init __initdata = HCL_DEBUG_NONE; +#endif +static unsigned int hcl_debug = HCL_DEBUG_NONE; +#if defined(CONFIG_HCL_DEBUG) && !defined(MODULE) +static unsigned int boot_options = OPTION_NONE; +#endif + +/* + * Some Global definitions. + */ +vertex_hdl_t hcl_handle; + +invplace_t invplace_none = { + GRAPH_VERTEX_NONE, + GRAPH_VERTEX_PLACE_NONE, + NULL +}; + +/* + * HCL device driver. + * The purpose of this device driver is to provide a facility + * for User Level Apps e.g. hinv, ioconfig etc. an ioctl path + * to manipulate label entries without having to implement + * system call interfaces. This methodology will enable us to + * make this feature module loadable. + */ +static int hcl_open(struct inode * inode, struct file * filp) +{ + if (hcl_debug) { + printk("HCL: hcl_open called.\n"); + } + + return(0); + +} + +static int hcl_close(struct inode * inode, struct file * filp) +{ + + if (hcl_debug) { + printk("HCL: hcl_close called.\n"); + } + + return(0); + +} + +static int hcl_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + + if (hcl_debug) { + printk("HCL: hcl_ioctl called.\n"); + } + + switch (cmd) { + default: + if (hcl_debug) { + printk("HCL: hcl_ioctl cmd = 0x%x\n", cmd); + } + } + + return(0); + +} + +struct file_operations hcl_fops = { + (struct module *)0, + NULL, /* lseek - default */ + NULL, /* read - general block-dev read */ + NULL, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + hcl_ioctl, /* ioctl */ + NULL, /* mmap */ + hcl_open, /* open */ + NULL, /* flush */ + hcl_close, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* lock */ + NULL, /* readv */ + NULL, /* writev */ +}; + + +/* + * init_hcl() - Boot time initialization. + * + */ +int __init init_hcl(void) +{ + extern void string_table_init(struct string_table *); + extern struct string_table label_string_table; + extern int init_ifconfig_net(void); + extern int init_ioconfig_bus(void); + extern int init_hwgfs_fs(void); + int rv = 0; + + if (IS_RUNNING_ON_SIMULATOR()) { + extern u64 klgraph_addr[]; + klgraph_addr[0] = 0xe000003000030000; + } + + init_hwgfs_fs(); + + /* + * Create the hwgraph_root. + */ + rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); + if (rv) + printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv); + + /* + * Create the hcl driver to support inventory entry manipulations. + * + */ + hcl_handle = hwgraph_register(hwgraph_root, ".hcl", + 0, 0, + 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + &hcl_fops, NULL); + + if (hcl_handle == NULL) { + panic("HCL: Unable to create HCL Driver in init_hcl().\n"); + return(0); + } + + /* + * Initialize the HCL string table. + */ + + string_table_init(&label_string_table); + + /* + * Create the directory that links Linux bus numbers to our Xwidget. + */ + rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); + if (linux_busnum == NULL) { + panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); + return(0); + } + + pci_bus_cvlink_init(); + + /* + * Initialize the ifconfgi_net driver that does network devices + * Persistent Naming. + */ + init_ifconfig_net(); + init_ioconfig_bus(); + + return(0); + +} + + +/* + * hcl_setup() - Process boot time parameters if given. + * "hcl=" + * This routine gets called only if "hcl=" is given in the + * boot line and before init_hcl(). + * + * We currently do not have any boot options .. when we do, + * functionalities can be added here. + * + */ +static int __init hcl_setup(char *str) +{ + while ( (*str != '\0') && !isspace (*str) ) + { +#ifdef CONFIG_HCL_DEBUG + if (strncmp (str, "all", 3) == 0) { + hcl_debug_init |= HCL_DEBUG_ALL; + str += 3; + } else + return 0; +#endif + if (*str != ',') return 0; + ++str; + } + + return 1; + +} + +__setup("hcl=", hcl_setup); + + +/* + * Set device specific "fast information". + * + */ +void +hwgraph_fastinfo_set(vertex_hdl_t de, arbitrary_info_t fastinfo) +{ + labelcl_info_replace_IDX(de, HWGRAPH_FASTINFO, fastinfo, NULL); +} + + +/* + * Get device specific "fast information". + * + */ +arbitrary_info_t +hwgraph_fastinfo_get(vertex_hdl_t de) +{ + arbitrary_info_t fastinfo; + int rv; + + if (!de) { + printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n"); + return(-1); + } + + rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo); + if (rv == 0) + return(fastinfo); + + return(0); +} + + +/* + * hwgraph_connectpt_set - Sets the connect point handle in de to the + * given connect_de handle. By default, the connect point of the + * node is the parent. This effectively changes this assumption. + */ +int +hwgraph_connectpt_set(vertex_hdl_t de, vertex_hdl_t connect_de) +{ + int rv; + + if (!de) + return(-1); + + rv = labelcl_info_connectpt_set(de, connect_de); + + return(rv); +} + + +/* + * hwgraph_connectpt_get: Returns the entry's connect point. + * + */ +vertex_hdl_t +hwgraph_connectpt_get(vertex_hdl_t de) +{ + int rv; + arbitrary_info_t info; + vertex_hdl_t connect; + + rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); + if (rv != 0) { + return(NULL); + } + + connect = (vertex_hdl_t)info; + return(connect); + +} + + +/* + * hwgraph_mk_dir - Creates a directory entry. + */ +vertex_hdl_t +hwgraph_mk_dir(vertex_hdl_t de, const char *name, + unsigned int namelen, void *info) +{ + + int rv; + labelcl_info_t *labelcl_info = NULL; + vertex_hdl_t new_handle = NULL; + vertex_hdl_t parent = NULL; + + /* + * Create the device info structure for hwgraph compatiblity support. + */ + labelcl_info = labelcl_info_create(); + if (!labelcl_info) + return(NULL); + + /* + * Create an entry. + */ + new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info); + if (!new_handle) { + labelcl_info_destroy(labelcl_info); + return(NULL); + } + + /* + * Get the parent handle. + */ + parent = hwgfs_get_parent (new_handle); + + /* + * To provide the same semantics as the hwgraph, set the connect point. + */ + rv = hwgraph_connectpt_set(new_handle, parent); + if (!rv) { + /* + * We need to clean up! + */ + } + + /* + * If the caller provides a private data pointer, save it in the + * labelcl info structure(fastinfo). This can be retrieved via + * hwgraph_fastinfo_get() + */ + if (info) + hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); + + return(new_handle); + +} + +/* + * hwgraph_path_add - Create a directory node with the given path starting + * from the given fromv. + */ +int +hwgraph_path_add(vertex_hdl_t fromv, + char *path, + vertex_hdl_t *new_de) +{ + + unsigned int namelen = strlen(path); + int rv; + + /* + * We need to handle the case when fromv is NULL .. + * in this case we need to create the path from the + * hwgraph root! + */ + if (fromv == NULL) + fromv = hwgraph_root; + + /* + * check the entry doesn't already exist, if it does + * then we simply want new_de to point to it (otherwise + * we'll overwrite the existing labelcl_info struct) + */ + rv = hwgraph_edge_get(fromv, path, new_de); + if (rv) { /* couldn't find entry so we create it */ + *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL); + if (new_de == NULL) + return(-1); + else + return(0); + } + else + return(0); + +} + +/* + * hwgraph_register - Creates a special device file. + * + */ +vertex_hdl_t +hwgraph_register(vertex_hdl_t de, const char *name, + unsigned int namelen, unsigned int flags, + unsigned int major, unsigned int minor, + umode_t mode, uid_t uid, gid_t gid, + struct file_operations *fops, + void *info) +{ + + vertex_hdl_t new_handle = NULL; + + /* + * Create an entry. + */ + new_handle = hwgfs_register(de, name, flags, major, + minor, mode, fops, info); + + return(new_handle); + +} + + +/* + * hwgraph_mk_symlink - Create a symbolic link. + */ +int +hwgraph_mk_symlink(vertex_hdl_t de, const char *name, unsigned int namelen, + unsigned int flags, const char *link, unsigned int linklen, + vertex_hdl_t *handle, void *info) +{ + + void *labelcl_info = NULL; + int status = 0; + vertex_hdl_t new_handle = NULL; + + /* + * Create the labelcl info structure for hwgraph compatiblity support. + */ + labelcl_info = labelcl_info_create(); + if (!labelcl_info) + return(-1); + + /* + * Create a symbolic link. + */ + status = hwgfs_mk_symlink(de, name, flags, link, + &new_handle, labelcl_info); + if ( (!new_handle) || (!status) ){ + labelcl_info_destroy((labelcl_info_t *)labelcl_info); + return(-1); + } + + /* + * If the caller provides a private data pointer, save it in the + * labelcl info structure(fastinfo). This can be retrieved via + * hwgraph_fastinfo_get() + */ + if (info) + hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); + + *handle = new_handle; + return(0); + +} + +/* + * hwgraph_vertex_destroy - Destroy the entry + */ +int +hwgraph_vertex_destroy(vertex_hdl_t de) +{ + + void *labelcl_info = NULL; + + labelcl_info = hwgfs_get_info(de); + hwgfs_unregister(de); + + if (labelcl_info) + labelcl_info_destroy((labelcl_info_t *)labelcl_info); + + return(0); +} + +#if 0 +/* + * hwgraph_edge_add - This routines has changed from the original conext. + * All it does now is to create a symbolic link from "from" to "to". + */ +/* ARGSUSED */ +int +hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name) +{ + + char *path, *link; + vertex_hdl_t handle = NULL; + int rv, i; + + handle = hwgfs_find_handle(from, name, 0, 0, 0, 1); + if (handle) { + return(0); + } + + path = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + link = kmalloc(1024, GFP_KERNEL); + memset(path, 0x0, 1024); + i = hwgfs_generate_path (to, link, 1024); + rv = hwgfs_mk_symlink (from, (const char *)name, + DEVFS_FL_DEFAULT, link, + &handle, NULL); + return(0); + + +} +#endif + +int +hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name) +{ + + char *path, *link; + char *s1; + char *index; + vertex_hdl_t handle = NULL; + int rv; + int i, count; + + path = kmalloc(1024, GFP_KERNEL); + memset((char *)path, 0x0, 1024); + link = kmalloc(1024, GFP_KERNEL); + memset((char *)link, 0x0, 1024); + + i = hwgfs_generate_path (from, path, 1024); + s1 = (char *)path; + count = 0; + while (1) { + index = strstr (s1, "/"); + if (index) { + count++; + s1 = ++index; + } else { + count++; + break; + } + } + + for (i = 0; i < count; i++) { + strcat((char *)link,"../"); + } + + memset(path, 0x0, 1024); + i = hwgfs_generate_path (to, path, 1024); + strcat((char *)link, (char *)path); + + /* + * Otherwise, just create a symlink to the vertex. + * In this case the vertex was previous created with a REAL pathname. + */ + rv = hwgfs_mk_symlink (from, (const char *)name, + DEVFS_FL_DEFAULT, link, + &handle, NULL); + kfree(path); + kfree(link); + + return(rv); + + +} + +/* ARGSUSED */ +int +hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr) +{ + + vertex_hdl_t target_handle = NULL; + + if (name == NULL) + return(-1); + + if (toptr == NULL) + return(-1); + + /* + * If the name is "." just return the current entry handle. + */ + if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) { + if (toptr) { + *toptr = from; + } + } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) { + /* + * Hmmm .. should we return the connect point or parent .. + * see in hwgraph, the concept of parent is the connectpt! + * + * Maybe we should see whether the connectpt is set .. if + * not just return the parent! + */ + target_handle = hwgraph_connectpt_get(from); + if (target_handle) { + /* + * Just return the connect point. + */ + *toptr = target_handle; + return(0); + } + target_handle = hwgfs_get_parent(from); + *toptr = target_handle; + + } else { + target_handle = hwgfs_find_handle (from, name, 0, 0, + 0, 1); /* Yes traverse symbolic links */ + } + + if (target_handle == NULL) + return(-1); + else + *toptr = target_handle; + + return(0); +} + +/* + * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc + * of the label as INFO_DESC_PRIVATE and store the info in the label. + */ +/* ARGSUSED */ +int +hwgraph_info_add_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t info) +{ + return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info)); +} + +/* + * hwgraph_info_remove_LBL - Remove the label entry for the device. + */ +/* ARGSUSED */ +int +hwgraph_info_remove_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t *old_info) +{ + return(labelcl_info_remove_LBL(de, name, NULL, old_info)); +} + +/* + * hwgraph_info_replace_LBL - replaces an existing label with + * a new label info value. + */ +/* ARGSUSED */ +int +hwgraph_info_replace_LBL( vertex_hdl_t de, + char *name, + arbitrary_info_t info, + arbitrary_info_t *old_info) +{ + return(labelcl_info_replace_LBL(de, name, + INFO_DESC_PRIVATE, info, + NULL, old_info)); +} +/* + * hwgraph_info_get_LBL - Get and return the info value in the label of the + * device. + */ +/* ARGSUSED */ +int +hwgraph_info_get_LBL(vertex_hdl_t de, + char *name, + arbitrary_info_t *infop) +{ + return(labelcl_info_get_LBL(de, name, NULL, infop)); +} + +/* + * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer + * of the given label for the device. The weird thing is that the label + * that matches the name is return irrespective of the info_desc value! + * Do not understand why the word "exported" is used! + */ +/* ARGSUSED */ +int +hwgraph_info_get_exported_LBL(vertex_hdl_t de, + char *name, + int *export_info, + arbitrary_info_t *infop) +{ + int rc; + arb_info_desc_t info_desc; + + rc = labelcl_info_get_LBL(de, name, &info_desc, infop); + if (rc == 0) + *export_info = (int)info_desc; + + return(rc); +} + +/* + * hwgraph_info_get_next_LBL - Returns the next label info given the + * current label entry in place. + * + * Once again this has no locking or reference count for protection. + * + */ +/* ARGSUSED */ +int +hwgraph_info_get_next_LBL(vertex_hdl_t de, + char *buf, + arbitrary_info_t *infop, + labelcl_info_place_t *place) +{ + return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place)); +} + +/* + * hwgraph_info_export_LBL - Retrieve the specified label entry and modify + * the info_desc field with the given value in nbytes. + */ +/* ARGSUSED */ +int +hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes) +{ + arbitrary_info_t info; + int rc; + + if (nbytes == 0) + nbytes = INFO_DESC_EXPORT; + + if (nbytes < 0) + return(-1); + + rc = labelcl_info_get_LBL(de, name, NULL, &info); + if (rc != 0) + return(rc); + + rc = labelcl_info_replace_LBL(de, name, + nbytes, info, NULL, NULL); + + return(rc); +} + +/* + * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the + * label info_descr filed to INFO_DESC_PRIVATE. + */ +/* ARGSUSED */ +int +hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name) +{ + arbitrary_info_t info; + int rc; + + rc = labelcl_info_get_LBL(de, name, NULL, &info); + if (rc != 0) + return(rc); + + rc = labelcl_info_replace_LBL(de, name, + INFO_DESC_PRIVATE, info, NULL, NULL); + + return(rc); +} + +/* + * hwgraph_path_lookup - return the handle for the given path. + * + */ +int +hwgraph_path_lookup(vertex_hdl_t start_vertex_handle, + char *lookup_path, + vertex_hdl_t *vertex_handle_ptr, + char **remainder) +{ + *vertex_handle_ptr = hwgfs_find_handle(start_vertex_handle, /* start dir */ + lookup_path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1); /* traverse symlinks */ + if (*vertex_handle_ptr == NULL) + return(-1); + else + return(0); +} + +/* + * hwgraph_traverse - Find and return the handle starting from de. + * + */ +graph_error_t +hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found) +{ + /* + * get the directory entry (path should end in a directory) + */ + + *found = hwgfs_find_handle(de, /* start dir */ + path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1); /* traverse symlinks */ + if (*found == NULL) + return(GRAPH_NOT_FOUND); + else + return(GRAPH_SUCCESS); +} + +/* + * hwgraph_path_to_vertex - Return the entry handle for the given + * pathname .. assume traverse symlinks too!. + */ +vertex_hdl_t +hwgraph_path_to_vertex(char *path) +{ + return(hwgfs_find_handle(NULL, /* start dir */ + path, /* path */ + 0, /* major */ + 0, /* minor */ + 0, /* char | block */ + 1)); /* traverse symlinks */ +} + +/* + * hwgraph_inventory_remove - Removes an inventory entry. + * + * Remove an inventory item associated with a vertex. It is the caller's + * responsibility to make sure that there are no races between removing + * inventory from a vertex and simultaneously removing that vertex. +*/ +int +hwgraph_inventory_remove( vertex_hdl_t de, + int class, + int type, + major_t controller, + minor_t unit, + int state) +{ + return(0); /* Just a Stub for IRIX code. */ +} + +/* + * Find the canonical name for a given vertex by walking back through + * connectpt's until we hit the hwgraph root vertex (or until we run + * out of buffer space or until something goes wrong). + * + * COMPATIBILITY FUNCTIONALITY + * Walks back through 'parents', not necessarily the same as connectpts. + * + * Need to resolve the fact that does not return the path from + * "/" but rather it just stops right before /dev .. + */ +int +hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen) +{ + char *locbuf; + int pos; + + if (buflen < 1) + return(-1); /* XXX should be GRAPH_BAD_PARAM ? */ + + locbuf = kmalloc(buflen, GFP_KERNEL); + + pos = hwgfs_generate_path(vhdl, locbuf, buflen); + if (pos < 0) { + kfree(locbuf); + return pos; + } + + strcpy(buf, &locbuf[pos]); + kfree(locbuf); + return 0; +} + +/* +** vertex_to_name converts a vertex into a canonical name by walking +** back through connect points until we hit the hwgraph root (or until +** we run out of buffer space). +** +** Usually returns a pointer to the original buffer, filled in as +** appropriate. If the buffer is too small to hold the entire name, +** or if anything goes wrong while determining the name, vertex_to_name +** returns "UnknownDevice". +*/ + +#define DEVNAME_UNKNOWN "UnknownDevice" + +char * +vertex_to_name(vertex_hdl_t vhdl, char *buf, uint buflen) +{ + if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS) + return(buf); + else + return(DEVNAME_UNKNOWN); +} + +graph_error_t +hwgraph_edge_remove(vertex_hdl_t from, char *name, vertex_hdl_t *toptr) +{ + return(GRAPH_ILLEGAL_REQUEST); +} + +graph_error_t +hwgraph_vertex_unref(vertex_hdl_t vhdl) +{ + return(GRAPH_ILLEGAL_REQUEST); +} + + +EXPORT_SYMBOL(hwgraph_mk_dir); +EXPORT_SYMBOL(hwgraph_path_add); +EXPORT_SYMBOL(hwgraph_register); +EXPORT_SYMBOL(hwgraph_vertex_destroy); +EXPORT_SYMBOL(hwgraph_fastinfo_get); +EXPORT_SYMBOL(hwgraph_fastinfo_set); +EXPORT_SYMBOL(hwgraph_connectpt_set); +EXPORT_SYMBOL(hwgraph_connectpt_get); +EXPORT_SYMBOL(hwgraph_info_add_LBL); +EXPORT_SYMBOL(hwgraph_info_remove_LBL); +EXPORT_SYMBOL(hwgraph_info_replace_LBL); +EXPORT_SYMBOL(hwgraph_info_get_LBL); +EXPORT_SYMBOL(hwgraph_info_get_exported_LBL); +EXPORT_SYMBOL(hwgraph_info_get_next_LBL); +EXPORT_SYMBOL(hwgraph_info_export_LBL); +EXPORT_SYMBOL(hwgraph_info_unexport_LBL); +EXPORT_SYMBOL(hwgraph_path_lookup); +EXPORT_SYMBOL(hwgraph_traverse); +EXPORT_SYMBOL(hwgraph_vertex_name_get); diff -Nru a/arch/ia64/sn/io/hwgfs/hcl_util.c b/arch/ia64/sn/io/hwgfs/hcl_util.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/hcl_util.c Fri May 16 11:50:50 2003 @@ -0,0 +1,200 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static vertex_hdl_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE; +extern vertex_hdl_t hwgraph_root; + + +/* +** Return the "master" for a given vertex. A master vertex is a +** controller or adapter or other piece of hardware that the given +** vertex passes through on the way to the rest of the system. +*/ +vertex_hdl_t +device_master_get(vertex_hdl_t vhdl) +{ + graph_error_t rc; + vertex_hdl_t master; + + rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master); + if (rc == GRAPH_SUCCESS) + return(master); + else + return(GRAPH_VERTEX_NONE); +} + +/* +** Set the master for a given vertex. +** Returns 0 on success, non-0 indicates failure +*/ +int +device_master_set(vertex_hdl_t vhdl, vertex_hdl_t master) +{ + graph_error_t rc; + + rc = hwgraph_edge_add(vhdl, master, EDGE_LBL_MASTER); + return(rc != GRAPH_SUCCESS); +} + + +/* +** Return the compact node id of the node that ultimately "owns" the specified +** vertex. In order to do this, we walk back through masters and connect points +** until we reach a vertex that represents a node. +*/ +cnodeid_t +master_node_get(vertex_hdl_t vhdl) +{ + cnodeid_t cnodeid; + vertex_hdl_t master; + + for (;;) { + cnodeid = nodevertex_to_cnodeid(vhdl); + if (cnodeid != CNODEID_NONE) + return(cnodeid); + + master = device_master_get(vhdl); + + /* Check for exceptional cases */ + if (master == vhdl) { + /* Since we got a reference to the "master" thru + * device_master_get() we should decrement + * its reference count by 1 + */ + return(CNODEID_NONE); + } + + if (master == GRAPH_VERTEX_NONE) { + master = hwgraph_connectpt_get(vhdl); + if ((master == GRAPH_VERTEX_NONE) || + (master == vhdl)) { + return(CNODEID_NONE); + } + } + + vhdl = master; + } +} + +static vertex_hdl_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; +extern int maxcpus; + +void +mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid) +{ + if (cpuid == CPU_NONE) + return; + + (void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT, + (arbitrary_info_t)cpuid); + { + char cpuid_buffer[10]; + + if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) { + (void)hwgraph_path_add( hwgraph_root, + EDGE_LBL_CPUNUM, + &hwgraph_all_cpuids); + } + + sprintf(cpuid_buffer, "%ld", cpuid); + (void)hwgraph_edge_add( hwgraph_all_cpuids, + vhdl, + cpuid_buffer); + } +} + +/* +** If the specified device represents a node, return its +** compact node ID; otherwise, return CNODEID_NONE. +*/ +cnodeid_t +nodevertex_to_cnodeid(vertex_hdl_t vhdl) +{ + int rv = 0; + arbitrary_info_t cnodeid = CNODEID_NONE; + + rv = labelcl_info_get_LBL(vhdl, INFO_LBL_CNODEID, NULL, &cnodeid); + + return((cnodeid_t)cnodeid); +} + +void +mark_nodevertex_as_node(vertex_hdl_t vhdl, cnodeid_t cnodeid) +{ + if (cnodeid == CNODEID_NONE) + return; + + cnodeid_to_vertex(cnodeid) = vhdl; + labelcl_info_add_LBL(vhdl, INFO_LBL_CNODEID, INFO_DESC_EXPORT, + (arbitrary_info_t)cnodeid); + + { + char cnodeid_buffer[10]; + + if (hwgraph_all_cnodes == GRAPH_VERTEX_NONE) { + (void)hwgraph_path_add( hwgraph_root, + EDGE_LBL_NODENUM, + &hwgraph_all_cnodes); + } + + sprintf(cnodeid_buffer, "%d", cnodeid); + (void)hwgraph_edge_add( hwgraph_all_cnodes, + vhdl, + cnodeid_buffer); + } +} + +/* +** If the specified device represents a CPU, return its cpuid; +** otherwise, return CPU_NONE. +*/ +cpuid_t +cpuvertex_to_cpuid(vertex_hdl_t vhdl) +{ + arbitrary_info_t cpuid = CPU_NONE; + + (void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid); + + return((cpuid_t)cpuid); +} + + +/* +** dev_to_name converts a vertex_hdl_t into a canonical name. If the vertex_hdl_t +** represents a vertex in the hardware graph, it is converted in the +** normal way for vertices. If the vertex_hdl_t is an old vertex_hdl_t (one which +** does not represent a hwgraph vertex), we synthesize a name based +** on major/minor number. +** +** Usually returns a pointer to the original buffer, filled in as +** appropriate. If the buffer is too small to hold the entire name, +** or if anything goes wrong while determining the name, dev_to_name +** returns "UnknownDevice". +*/ +char * +dev_to_name(vertex_hdl_t dev, char *buf, uint buflen) +{ + return(vertex_to_name(dev, buf, buflen)); +} + + diff -Nru a/arch/ia64/sn/io/hwgfs/interface.c b/arch/ia64/sn/io/hwgfs/interface.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/interface.c Fri May 16 11:50:50 2003 @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Portions based on Adam Richter's smalldevfs and thus + * Copyright 2002-2003 Yggdrasil Computing, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +extern struct vfsmount *hwgfs_vfsmount; + +/* TODO: Move this to some .h file or, more likely, use a slightly + different interface from lookup_create. */ +extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); + +static int +walk_parents_mkdir( + const char **path, + struct nameidata *nd, + int is_dir) +{ + char *slash; + char buf[strlen(*path)+1]; + int error; + + while ((slash = strchr(*path, '/')) != NULL) { + int len = slash - *path; + memcpy(buf, *path, len); + buf[len] = '\0'; + + error = link_path_walk(buf, nd); + if (unlikely(error)) + return error; + + nd->dentry = lookup_create(nd, is_dir); + if (unlikely(IS_ERR(nd->dentry))) + return PTR_ERR(nd->dentry); + + if (!nd->dentry->d_inode) + error = vfs_mkdir(nd->dentry->d_parent->d_inode, + nd->dentry, 0755); + + up(&nd->dentry->d_parent->d_inode->i_sem); + if (unlikely(error)) + return error; + + *path += len + 1; + } + + return 0; +} + +/* On success, returns with parent_inode->i_sem taken. */ +static int +hwgfs_decode( + hwgfs_handle_t dir, + const char *name, + int is_dir, + struct inode **parent_inode, + struct dentry **dentry) +{ + struct nameidata nd; + int error; + + if (!dir) + dir = hwgfs_vfsmount->mnt_sb->s_root; + + memset(&nd, 0, sizeof(nd)); + nd.flags = LOOKUP_PARENT; + nd.mnt = mntget(hwgfs_vfsmount); + nd.dentry = dget(dir); + + error = walk_parents_mkdir(&name, &nd, is_dir); + if (unlikely(error)) + return error; + + error = link_path_walk(name, &nd); + if (unlikely(error)) + return error; + + *dentry = lookup_create(&nd, is_dir); + + if (unlikely(IS_ERR(*dentry))) + return PTR_ERR(*dentry); + *parent_inode = (*dentry)->d_parent->d_inode; + return 0; +} + +static int +path_len( + struct dentry *de, + struct dentry *root) +{ + int len = 0; + + while (de != root) { + len += de->d_name.len + 1; /* count the '/' */ + de = de->d_parent; + } + return len; /* -1 because we omit the leading '/', + +1 because we include trailing '\0' */ +} + +int +hwgfs_generate_path( + hwgfs_handle_t de, + char *path, + int buflen) +{ + struct dentry *hwgfs_root; + int len; + char *path_orig = path; + + if (unlikely(de == NULL)) + return -EINVAL; + + hwgfs_root = hwgfs_vfsmount->mnt_sb->s_root; + if (unlikely(de == hwgfs_root)) + return -EINVAL; + + spin_lock(&dcache_lock); + len = path_len(de, hwgfs_root); + if (len > buflen) { + spin_unlock(&dcache_lock); + return -ENAMETOOLONG; + } + + path += len - 1; + *path = '\0'; + + for (;;) { + path -= de->d_name.len; + memcpy(path, de->d_name.name, de->d_name.len); + de = de->d_parent; + if (de == hwgfs_root) + break; + *(--path) = '/'; + } + + spin_unlock(&dcache_lock); + BUG_ON(path != path_orig); + return 0; +} + +hwgfs_handle_t +hwgfs_register( + hwgfs_handle_t dir, + const char *name, + unsigned int flags, + unsigned int major, + unsigned int minor, + umode_t mode, + void *ops, + void *info) +{ + dev_t devnum = MKDEV(major, minor); + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_mknod(parent_inode, dentry, mode, devnum); + if (likely(!error)) { + /* + * Do this inside parents i_sem to avoid racing + * with lookups. + */ + if (S_ISCHR(mode)) + dentry->d_inode->i_fop = ops; + dentry->d_fsdata = info; + up(&parent_inode->i_sem); + } else { + up(&parent_inode->i_sem); + dput(dentry); + dentry = NULL; + } + } + + return dentry; +} + +int +hwgfs_mk_symlink( + hwgfs_handle_t dir, + const char *name, + unsigned int flags, + const char *link, + hwgfs_handle_t *handle, + void *info) +{ + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_symlink(parent_inode, dentry, link); + dentry->d_fsdata = info; + if (handle) + *handle = dentry; + up(&parent_inode->i_sem); + /* dput(dentry); */ + } + return error; +} + +hwgfs_handle_t +hwgfs_mk_dir( + hwgfs_handle_t dir, + const char *name, + void *info) +{ + struct inode *parent_inode; + struct dentry *dentry; + int error; + + error = hwgfs_decode(dir, name, 1, &parent_inode, &dentry); + if (likely(!error)) { + error = vfs_mkdir(parent_inode, dentry, 0755); + up(&parent_inode->i_sem); + + if (unlikely(error)) { + dput(dentry); + dentry = NULL; + } else { + dentry->d_fsdata = info; + } + } + return dentry; +} + +void +hwgfs_unregister( + hwgfs_handle_t de) +{ + struct inode *parent_inode = de->d_parent->d_inode; + + if (S_ISDIR(de->d_inode->i_mode)) + vfs_rmdir(parent_inode, de); + else + vfs_unlink(parent_inode, de); +} + +/* XXX: this function is utterly bogus. Every use of it is racy and the + prototype is stupid. You have been warned. --hch. */ +hwgfs_handle_t +hwgfs_find_handle( + hwgfs_handle_t base, + const char *name, + unsigned int major, /* IGNORED */ + unsigned int minor, /* IGNORED */ + char type, /* IGNORED */ + int traverse_symlinks) +{ + struct dentry *dentry = NULL; + struct nameidata nd; + int error; + + BUG_ON(*name=='/'); + + memset(&nd, 0, sizeof(nd)); + + nd.mnt = mntget(hwgfs_vfsmount); + nd.dentry = dget(base ? base : hwgfs_vfsmount->mnt_sb->s_root); + if (traverse_symlinks) + nd.flags = LOOKUP_FOLLOW; + + error = link_path_walk(name, &nd); + if (likely(!error)) { + dentry = nd.dentry; + path_release(&nd); /* stale data from here! */ + } + + return dentry; +} + +hwgfs_handle_t +hwgfs_get_parent( + hwgfs_handle_t de) +{ + struct dentry *parent; + + spin_lock(&de->d_lock); + parent = de->d_parent; + spin_unlock(&de->d_lock); + + return parent; +} + +int +hwgfs_set_info( + hwgfs_handle_t de, + void *info) +{ + if (unlikely(de == NULL)) + return -EINVAL; + de->d_fsdata = info; + return 0; +} + +void * +hwgfs_get_info( + hwgfs_handle_t de) +{ + return de->d_fsdata; +} + +EXPORT_SYMBOL(hwgfs_generate_path); +EXPORT_SYMBOL(hwgfs_register); +EXPORT_SYMBOL(hwgfs_unregister); +EXPORT_SYMBOL(hwgfs_mk_symlink); +EXPORT_SYMBOL(hwgfs_mk_dir); +EXPORT_SYMBOL(hwgfs_find_handle); +EXPORT_SYMBOL(hwgfs_get_parent); +EXPORT_SYMBOL(hwgfs_set_info); +EXPORT_SYMBOL(hwgfs_get_info); diff -Nru a/arch/ia64/sn/io/hwgfs/invent_stub.c b/arch/ia64/sn/io/hwgfs/invent_stub.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/invent_stub.c Fri May 16 11:50:50 2003 @@ -0,0 +1,148 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +/* + * Hardware Inventory + * + * See sys/sn/invent.h for an explanation of the hardware inventory contents. + * + */ +#include +#include +#include +#include +#include +#include +#include + +void +inventinit(void) +{ +} + +/* + * For initializing/updating an inventory entry. + */ +void +replace_in_inventory( + inventory_t *pinv, int class, int type, + int controller, int unit, int state) +{ +} + +/* + * Inventory addition + * + * XXX NOTE: Currently must be called after dynamic memory allocator is + * initialized. + * + */ +void +add_to_inventory(int class, int type, int controller, int unit, int state) +{ +} + + +/* + * Inventory retrieval + * + * These two routines are intended to prevent the caller from having to know + * the internal structure of the inventory table. + * + * The caller of get_next_inventory is supposed to call start_scan_invent + * before the irst call to get_next_inventory, and the caller is required + * to call end_scan_invent after the last call to get_next_inventory. + */ +inventory_t * +get_next_inventory(invplace_t *place) +{ + return((inventory_t *) NULL); +} + +/* ARGSUSED */ +int +get_sizeof_inventory(int abi) +{ + return sizeof(inventory_t); +} + +/* Must be called prior to first call to get_next_inventory */ +void +start_scan_inventory(invplace_t *iplace) +{ +} + +/* Must be called after last call to get_next_inventory */ +void +end_scan_inventory(invplace_t *iplace) +{ +} + +/* + * Hardware inventory scanner. + * + * Calls fun() for every entry in inventory list unless fun() returns something + * other than 0. + */ +int +scaninvent(int (*fun)(inventory_t *, void *), void *arg) +{ + return 0; +} + +/* + * Find a particular inventory object + * + * pinv can be a pointer to an inventory entry and the search will begin from + * there, or it can be 0 in which case the search starts at the beginning. + * A -1 for any of the other arguments is a wildcard (i.e. it always matches). + */ +inventory_t * +find_inventory(inventory_t *pinv, int class, int type, int controller, + int unit, int state) +{ + return((inventory_t *) NULL); +} + + +/* +** Retrieve inventory data associated with a device. +*/ +inventory_t * +device_inventory_get_next( vertex_hdl_t device, + invplace_t *invplace) +{ + return((inventory_t *) NULL); +} + + +/* +** Associate canonical inventory information with a device (and +** add it to the general inventory). +*/ +void +device_inventory_add( vertex_hdl_t device, + int class, + int type, + major_t controller, + minor_t unit, + int state) +{ +} + +int +device_controller_num_get(vertex_hdl_t device) +{ + return (0); +} + +void +device_controller_num_set(vertex_hdl_t device, int contr_num) +{ +} diff -Nru a/arch/ia64/sn/io/hwgfs/labelcl.c b/arch/ia64/sn/io/hwgfs/labelcl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/labelcl.c Fri May 16 11:50:50 2003 @@ -0,0 +1,657 @@ +/* labelcl - SGI's Hwgraph Compatibility Layer. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. +*/ + +#include +#include +#include +#include +#include +#include /* needed for smp_lock.h :( */ +#include +#include +#include +#include +#include +#include + +/* +** Very simple and dumb string table that supports only find/insert. +** In practice, if this table gets too large, we may need a more +** efficient data structure. Also note that currently there is no +** way to delete an item once it's added. Therefore, name collision +** will return an error. +*/ + +struct string_table label_string_table; + + + +/* + * string_table_init - Initialize the given string table. + */ +void +string_table_init(struct string_table *string_table) +{ + string_table->string_table_head = NULL; + string_table->string_table_generation = 0; + + /* + * We nedd to initialize locks here! + */ + + return; +} + + +/* + * string_table_destroy - Destroy the given string table. + */ +void +string_table_destroy(struct string_table *string_table) +{ + struct string_table_item *item, *next_item; + + item = string_table->string_table_head; + while (item) { + next_item = item->next; + + STRTBL_FREE(item); + item = next_item; + } + + /* + * We need to destroy whatever lock we have here + */ + + return; +} + + + +/* + * string_table_insert - Insert an entry in the string table .. duplicate + * names are not allowed. + */ +char * +string_table_insert(struct string_table *string_table, char *name) +{ + struct string_table_item *item, *new_item = NULL, *last_item = NULL; + +again: + /* + * Need to lock the table .. + */ + item = string_table->string_table_head; + last_item = NULL; + + while (item) { + if (!strcmp(item->string, name)) { + /* + * If we allocated space for the string and the found that + * someone else already entered it into the string table, + * free the space we just allocated. + */ + if (new_item) + STRTBL_FREE(new_item); + + + /* + * Search optimization: move the found item to the head + * of the list. + */ + if (last_item != NULL) { + last_item->next = item->next; + item->next = string_table->string_table_head; + string_table->string_table_head = item; + } + goto out; + } + last_item = item; + item=item->next; + } + + /* + * name was not found, so add it to the string table. + */ + if (new_item == NULL) { + long old_generation = string_table->string_table_generation; + + new_item = STRTBL_ALLOC(strlen(name)); + + strcpy(new_item->string, name); + + /* + * While we allocated memory for the new string, someone else + * changed the string table. + */ + if (old_generation != string_table->string_table_generation) { + goto again; + } + } else { + /* At this we only have the string table lock in access mode. + * Promote the access lock to an update lock for the string + * table insertion below. + */ + long old_generation = + string_table->string_table_generation; + + /* + * After we did the unlock and wer waiting for update + * lock someone could have potentially updated + * the string table. Check the generation number + * for this case. If it is the case we have to + * try all over again. + */ + if (old_generation != + string_table->string_table_generation) { + goto again; + } + } + + /* + * At this point, we're committed to adding new_item to the string table. + */ + new_item->next = string_table->string_table_head; + item = string_table->string_table_head = new_item; + string_table->string_table_generation++; + +out: + /* + * Need to unlock here. + */ + return(item->string); +} + +/* + * labelcl_info_create - Creates the data structure that will hold the + * device private information asscoiated with a entry. + * The pointer to this structure is what gets stored in the + * (void * info). + */ +labelcl_info_t * +labelcl_info_create() +{ + + labelcl_info_t *new = NULL; + + /* Initial allocation does not include any area for labels */ + if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL ) + return NULL; + + memset (new, 0, sizeof(labelcl_info_t)); + new->hwcl_magic = LABELCL_MAGIC; + return( new); + +} + +/* + * labelcl_info_destroy - Frees the data structure that holds the + * device private information asscoiated with a entry. This + * data structure was created by device_info_create(). + * + * The caller is responsible for nulling the (void *info) in the + * corresponding entry. + */ +int +labelcl_info_destroy(labelcl_info_t *labelcl_info) +{ + + if (labelcl_info == NULL) + return(0); + + /* Free the label list */ + if (labelcl_info->label_list) + kfree(labelcl_info->label_list); + + /* Now free the label info area */ + labelcl_info->hwcl_magic = 0; + kfree(labelcl_info); + + return(0); +} + +/* + * labelcl_info_add_LBL - Adds a new label entry in the labelcl info + * structure. + * + * Error is returned if we find another label with the same name. + */ +int +labelcl_info_add_LBL(vertex_hdl_t de, + char *info_name, + arb_info_desc_t info_desc, + arbitrary_info_t info) +{ + labelcl_info_t *labelcl_info = NULL; + int num_labels; + int new_label_list_size; + label_info_t *old_label_list, *new_label_list = NULL; + char *name; + int i; + + if (de == NULL) + return(-1); + + labelcl_info = hwgfs_get_info(de); + if (labelcl_info == NULL) + return(-1); + + if (labelcl_info->hwcl_magic != LABELCL_MAGIC) + return(-1); + + if (info_name == NULL) + return(-1); + + if (strlen(info_name) >= LABEL_LENGTH_MAX) + return(-1); + + name = string_table_insert(&label_string_table, info_name); + + num_labels = labelcl_info->num_labels; + new_label_list_size = sizeof(label_info_t) * (num_labels+1); + + /* + * Create a new label info area. + */ + if (new_label_list_size != 0) { + new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); + + if (new_label_list == NULL) + return(-1); + } + + /* + * At this point, we are committed to adding the labelled info, + * if there isn't already information there with the same name. + */ + old_label_list = labelcl_info->label_list; + + /* + * Look for matching info name. + */ + for (i=0; inum_labels = num_labels+1; + labelcl_info->label_list = new_label_list; + + if (old_label_list != NULL) + kfree(old_label_list); + + return(0); +} + +/* + * labelcl_info_remove_LBL - Remove a label entry. + */ +int +labelcl_info_remove_LBL(vertex_hdl_t de, + char *info_name, + arb_info_desc_t *info_desc, + arbitrary_info_t *info) +{ + labelcl_info_t *labelcl_info = NULL; + int num_labels; + int new_label_list_size; + label_info_t *old_label_list, *new_label_list = NULL; + arb_info_desc_t label_desc_found; + arbitrary_info_t label_info_found; + int i; + + if (de == NULL) + return(-1); + + labelcl_info = hwgfs_get_info(de); + if (labelcl_info == NULL) + return(-1); + + if (labelcl_info->hwcl_magic != LABELCL_MAGIC) + return(-1); + + num_labels = labelcl_info->num_labels; + if (num_labels == 0) { + return(-1); + } + + /* + * Create a new info area. + */ + new_label_list_size = sizeof(label_info_t) * (num_labels-1); + if (new_label_list_size) { + new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); + if (new_label_list == NULL) + return(-1); + } + + /* + * At this point, we are committed to removing the labelled info, + * if it still exists. + */ + old_label_list = labelcl_info->label_list; + + /* + * Find matching info name. + */ + for (i=0; inum_labels = num_labels+1; + labelcl_info->label_list = new_label_list; + + kfree(old_label_list); + + if (info != NULL) + *info = label_info_found; + + if (info_desc != NULL) + *info_desc = label_desc_found; + + return(0); +} + + +/* + * labelcl_info_replace_LBL - Replace an existing label entry with the + * given new information. + * + * Label entry must exist. + */ +int +labelcl_info_replace_LBL(vertex_hdl_t de, + char *info_name, + arb_info_desc_t info_desc, + arbitrary_info_t info, + arb_info_desc_t *old_info_desc, + arbitrary_info_t *old_info) +{ + labelcl_info_t *labelcl_info = NULL; + int num_labels; + label_info_t *label_list; + int i; + + if (de == NULL) + return(-1); + + labelcl_info = hwgfs_get_info(de); + if (labelcl_info == NULL) + return(-1); + + if (labelcl_info->hwcl_magic != LABELCL_MAGIC) + return(-1); + + num_labels = labelcl_info->num_labels; + if (num_labels == 0) { + return(-1); + } + + if (info_name == NULL) + return(-1); + + label_list = labelcl_info->label_list; + + /* + * Verify that information under info_name already exists. + */ + for (i=0; ihwcl_magic != LABELCL_MAGIC) + return(-1); + + num_labels = labelcl_info->num_labels; + if (num_labels == 0) { + return(-1); + } + + label_list = labelcl_info->label_list; + + /* + * Find information under info_name. + */ + for (i=0; ihwcl_magic != LABELCL_MAGIC) + return(-1); + + which_info = *placeptr; + + if (which_info >= labelcl_info->num_labels) { + return(-1); + } + + label_list = (label_info_t *) labelcl_info->label_list; + + if (buffer != NULL) + strcpy(buffer, label_list[which_info].name); + + if (infop) + *infop = label_list[which_info].info; + + if (info_descp) + *info_descp = label_list[which_info].desc; + + *placeptr = which_info + 1; + + return(0); +} + + +int +labelcl_info_replace_IDX(vertex_hdl_t de, + int index, + arbitrary_info_t info, + arbitrary_info_t *old_info) +{ + arbitrary_info_t *info_list_IDX; + labelcl_info_t *labelcl_info = NULL; + + if (de == NULL) { + printk(KERN_ALERT "labelcl: NULL handle given.\n"); + return(-1); + } + + labelcl_info = hwgfs_get_info(de); + if (labelcl_info == NULL) { + printk(KERN_ALERT "labelcl: Entry %p does not have info pointer.\n", (void *)de); + return(-1); + } + + if (labelcl_info->hwcl_magic != LABELCL_MAGIC) + return(-1); + + if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) + return(-1); + + /* + * Replace information at the appropriate index in this vertex with + * the new info. + */ + info_list_IDX = labelcl_info->IDX_list; + if (old_info != NULL) + *old_info = info_list_IDX[index]; + info_list_IDX[index] = info; + + return(0); + +} + +/* + * labelcl_info_connectpt_set - Sets the connectpt. + */ +int +labelcl_info_connectpt_set(hwgfs_handle_t de, + hwgfs_handle_t connect_de) +{ + arbitrary_info_t old_info; + int rv; + + rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, + (arbitrary_info_t) connect_de, &old_info); + + if (rv) { + return(rv); + } + + return(0); +} + + +/* + * labelcl_info_get_IDX - Returns the information pointed at by index. + * + */ +int +labelcl_info_get_IDX(vertex_hdl_t de, + int index, + arbitrary_info_t *info) +{ + arbitrary_info_t *info_list_IDX; + labelcl_info_t *labelcl_info = NULL; + + if (de == NULL) + return(-1); + + labelcl_info = hwgfs_get_info(de); + if (labelcl_info == NULL) + return(-1); + + if (labelcl_info->hwcl_magic != LABELCL_MAGIC) + return(-1); + + if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) + return(-1); + + /* + * Return information at the appropriate index in this vertex. + */ + info_list_IDX = labelcl_info->IDX_list; + if (info != NULL) + *info = info_list_IDX[index]; + + return(0); +} + +/* + * labelcl_info_connectpt_get - Retrieve the connect point for a device entry. + */ +hwgfs_handle_t +labelcl_info_connectpt_get(hwgfs_handle_t de) +{ + int rv; + arbitrary_info_t info; + + rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); + if (rv) + return(NULL); + + return((hwgfs_handle_t) info); +} diff -Nru a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/hwgfs/ramfs.c Fri May 16 11:50:50 2003 @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Mostly shameless copied from Linus Torvalds' ramfs and thus + * Copyright (C) 2000 Linus Torvalds. + * 2000 Transmeta Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include + +/* some random number */ +#define HWGFS_MAGIC 0x12061983 + +static struct super_operations hwgfs_ops; +static struct address_space_operations hwgfs_aops; +static struct file_operations hwgfs_file_operations; +static struct inode_operations hwgfs_file_inode_operations; +static struct inode_operations hwgfs_dir_inode_operations; + +static struct backing_dev_info hwgfs_backing_dev_info = { + .ra_pages = 0, /* No readahead */ + .memory_backed = 1, /* Does not contribute to dirty memory */ +}; + +struct inode *hwgfs_get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode * inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &hwgfs_aops; + inode->i_mapping->backing_dev_info = &hwgfs_backing_dev_info; + 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 = &hwgfs_file_inode_operations; + inode->i_fop = &hwgfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &hwgfs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inode->i_nlink++; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + } + } + return inode; +} + +static int hwgfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +{ + struct inode * inode = hwgfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); /* Extra count - pin the dentry in core */ + error = 0; + } + return error; +} + +static int hwgfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + return hwgfs_mknod(dir, dentry, mode | S_IFDIR, 0); +} + +static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return hwgfs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static int hwgfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) +{ + struct inode *inode; + int error = -ENOSPC; + + inode = hwgfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + if (inode) { + int l = strlen(symname)+1; + error = page_symlink(inode, symname, l); + if (!error) { + d_instantiate(dentry, inode); + dget(dentry); + } else + iput(inode); + } + return error; +} + +static struct address_space_operations hwgfs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, + .commit_write = simple_commit_write +}; + +static struct file_operations hwgfs_file_operations = { + .read = generic_file_read, + .write = generic_file_write, + .mmap = generic_file_mmap, + .fsync = simple_sync_file, + .sendfile = generic_file_sendfile, +}; + +static struct inode_operations hwgfs_file_inode_operations = { + .getattr = simple_getattr, +}; + +static struct inode_operations hwgfs_dir_inode_operations = { + .create = hwgfs_create, + .lookup = simple_lookup, + .link = simple_link, + .unlink = simple_unlink, + .symlink = hwgfs_symlink, + .mkdir = hwgfs_mkdir, + .rmdir = simple_rmdir, + .mknod = hwgfs_mknod, + .rename = simple_rename, +}; + +static struct super_operations hwgfs_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static int hwgfs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * inode; + struct dentry * root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = HWGFS_MAGIC; + sb->s_op = &hwgfs_ops; + inode = hwgfs_get_inode(sb, S_IFDIR | 0755, 0); + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return 0; +} + +static struct super_block *hwgfs_get_sb(struct file_system_type *fs_type, + int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, hwgfs_fill_super); +} + +static struct file_system_type hwgfs_fs_type = { + .owner = THIS_MODULE, + .name = "hwgfs", + .get_sb = hwgfs_get_sb, + .kill_sb = kill_litter_super, +}; + +struct vfsmount *hwgfs_vfsmount; + +int __init init_hwgfs_fs(void) +{ + int error; + + error = register_filesystem(&hwgfs_fs_type); + if (error) + return error; + + hwgfs_vfsmount = kern_mount(&hwgfs_fs_type); + if (IS_ERR(hwgfs_vfsmount)) + goto fail; + return 0; + +fail: + unregister_filesystem(&hwgfs_fs_type); + return PTR_ERR(hwgfs_vfsmount); +} + +static void __exit exit_hwgfs_fs(void) +{ + unregister_filesystem(&hwgfs_fs_type); +} + +MODULE_LICENSE("GPL"); + +module_init(init_hwgfs_fs) +module_exit(exit_hwgfs_fs) diff -Nru a/arch/ia64/sn/io/ifconfig_net.c b/arch/ia64/sn/io/ifconfig_net.c --- a/arch/ia64/sn/io/ifconfig_net.c Tue Dec 3 10:07:23 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,298 +0,0 @@ -/* $Id: ifconfig_net.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * ifconfig_net - SGI's Persistent Network Device names. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SGI_IFCONFIG_NET "SGI-PERSISTENT NETWORK DEVICE NAME DRIVER" -#define SGI_IFCONFIG_NET_VERSION "1.0" - -/* - * Some Global definitions. - */ -devfs_handle_t ifconfig_net_handle = NULL; -unsigned long ifconfig_net_debug = 0; - -/* - * ifconfig_net_open - Opens the special device node "/devhw/.ifconfig_net". - */ -static int ifconfig_net_open(struct inode * inode, struct file * filp) -{ - if (ifconfig_net_debug) { - printk("ifconfig_net_open called.\n"); - } - - return(0); - -} - -/* - * ifconfig_net_close - Closes the special device node "/devhw/.ifconfig_net". - */ -static int ifconfig_net_close(struct inode * inode, struct file * filp) -{ - - if (ifconfig_net_debug) { - printk("ifconfig_net_close called.\n"); - } - - return(0); -} - -/* - * assign_ifname - Assign the next available interface name from the persistent list. - */ -void -assign_ifname(struct net_device *dev, - struct ifname_num *ifname_num) - -{ - - /* - * Handle eth devices. - */ - if ( (memcmp(dev->name, "eth", 3) == 0) ) { - if (ifname_num->next_eth != -1) { - /* - * Assign it the next available eth interface number. - */ - memset(dev->name, 0, strlen(dev->name)); - sprintf(dev->name, "eth%d", (int)ifname_num->next_eth); - ifname_num->next_eth++; - } - - return; - } - - /* - * Handle fddi devices. - */ - if ( (memcmp(dev->name, "fddi", 4) == 0) ) { - if (ifname_num->next_fddi != -1) { - /* - * Assign it the next available fddi interface number. - */ - memset(dev->name, 0, strlen(dev->name)); - sprintf(dev->name, "fddi%d", (int)ifname_num->next_fddi); - ifname_num->next_fddi++; - } - - return; - } - - /* - * Handle hip devices. - */ - if ( (memcmp(dev->name, "hip", 3) == 0) ) { - if (ifname_num->next_hip != -1) { - /* - * Assign it the next available hip interface number. - */ - memset(dev->name, 0, strlen(dev->name)); - sprintf(dev->name, "hip%d", (int)ifname_num->next_hip); - ifname_num->next_hip++; - } - - return; - } - - /* - * Handle tr devices. - */ - if ( (memcmp(dev->name, "tr", 2) == 0) ) { - if (ifname_num->next_tr != -1) { - /* - * Assign it the next available tr interface number. - */ - memset(dev->name, 0, strlen(dev->name)); - sprintf(dev->name, "tr%d", (int)ifname_num->next_tr); - ifname_num->next_tr++; - } - - return; - } - - /* - * Handle fc devices. - */ - if ( (memcmp(dev->name, "fc", 2) == 0) ) { - if (ifname_num->next_fc != -1) { - /* - * Assign it the next available fc interface number. - */ - memset(dev->name, 0, strlen(dev->name)); - sprintf(dev->name, "fc%d", (int)ifname_num->next_fc); - ifname_num->next_fc++; - } - - return; - } -} - -/* - * find_persistent_ifname: Returns the entry that was seen in previous boot. - */ -struct ifname_MAC * -find_persistent_ifname(struct net_device *dev, - struct ifname_MAC *ifname_MAC) - -{ - - while (ifname_MAC->addr_len) { - if (memcmp(dev->dev_addr, ifname_MAC->dev_addr, dev->addr_len) == 0) - return(ifname_MAC); - - ifname_MAC++; - } - - return(NULL); -} - -/* - * ifconfig_net_ioctl: ifconfig_net driver ioctl interface. - */ -static int ifconfig_net_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - - extern struct net_device *__dev_get_by_name(const char *); -#ifdef CONFIG_NET - struct net_device *dev; - struct ifname_MAC *found; - char temp[64]; -#endif - struct ifname_MAC *ifname_MAC; - struct ifname_MAC *new_devices, *temp_new_devices; - struct ifname_num *ifname_num; - unsigned long size; - - - if (ifconfig_net_debug) { - printk("HCL: hcl_ioctl called.\n"); - } - - /* - * Read in the header and see how big of a buffer we really need to - * allocate. - */ - ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), - GFP_KERNEL); - copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num)); - size = ifname_num->size; - kfree(ifname_num); - ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL); - ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) ); - - copy_from_user( ifname_num, (char *) arg, size); - new_devices = kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL); - temp_new_devices = new_devices; - - memset(new_devices, 0, size - sizeof(struct ifname_num)); - -#ifdef CONFIG_NET - /* - * Go through the net device entries and make them persistent! - */ - for (dev = dev_base; dev != NULL; dev = dev->next) { - /* - * Skip NULL entries or "lo" - */ - if ( (dev->addr_len == 0) || ( !strncmp(dev->name, "lo", strlen(dev->name))) ){ - continue; - } - - /* - * See if we have a persistent interface name for this device. - */ - found = NULL; - found = find_persistent_ifname(dev, ifname_MAC); - if (found) { - strcpy(dev->name, found->name); - } else { - /* Never seen this before .. */ - assign_ifname(dev, ifname_num); - - /* - * Save the information for the next boot. - */ - sprintf(temp,"%s %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - strcpy(temp_new_devices->name, dev->name); - temp_new_devices->addr_len = dev->addr_len; - memcpy(temp_new_devices->dev_addr, dev->dev_addr, dev->addr_len); - temp_new_devices++; - } - - } -#endif - - /* - * Copy back to the User Buffer area any new devices encountered. - */ - copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, - size - sizeof(struct ifname_num)); - - return(0); - -} - -struct file_operations ifconfig_net_fops = { - ioctl:ifconfig_net_ioctl, /* ioctl */ - open:ifconfig_net_open, /* open */ - release:ifconfig_net_close /* release */ -}; - - -/* - * init_ifconfig_net() - Boot time initialization. Ensure that it is called - * after devfs has been initialized. - * - */ -#ifdef MODULE -int init_module (void) -#else -int __init init_ifconfig_net(void) -#endif -{ - ifconfig_net_handle = NULL; - ifconfig_net_handle = hwgraph_register(hwgraph_root, ".ifconfig_net", - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &ifconfig_net_fops, NULL); - - if (ifconfig_net_handle == NULL) { - panic("Unable to create SGI PERSISTENT NETWORK DEVICE Name Driver.\n"); - } - - return(0); - -} diff -Nru a/arch/ia64/sn/io/invent.c b/arch/ia64/sn/io/invent.c --- a/arch/ia64/sn/io/invent.c Wed Dec 4 07:04:36 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,224 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * Hardware Inventory - * - * See sys/sn/invent.h for an explanation of the hardware inventory contents. - * - */ -#include -#include -#include -#include -#include - -void -inventinit(void) -{ -} - -/* - * For initializing/updating an inventory entry. - */ -void -replace_in_inventory( - inventory_t *pinv, int class, int type, - int controller, int unit, int state) -{ - pinv->inv_class = class; - pinv->inv_type = type; - pinv->inv_controller = controller; - pinv->inv_unit = unit; - pinv->inv_state = state; -} - -/* - * Inventory addition - * - * XXX NOTE: Currently must be called after dynamic memory allocator is - * initialized. - * - */ -void -add_to_inventory(int class, int type, int controller, int unit, int state) -{ - (void)device_inventory_add((devfs_handle_t)GRAPH_VERTEX_NONE, class, type, - controller, unit, state); -} - - -/* - * Inventory retrieval - * - * These two routines are intended to prevent the caller from having to know - * the internal structure of the inventory table. - * - * The caller of get_next_inventory is supposed to call start_scan_invent - * before the irst call to get_next_inventory, and the caller is required - * to call end_scan_invent after the last call to get_next_inventory. - */ -inventory_t * -get_next_inventory(invplace_t *place) -{ - inventory_t *pinv; - devfs_handle_t device = place->invplace_vhdl; - int rv; - - while ((pinv = device_inventory_get_next(device, place)) == NULL) { - /* - * We've exhausted inventory items on the last device. - * Advance to next device. - */ - place->invplace_inv = NULL; /* Start from beginning invent on this device */ - rv = hwgraph_vertex_get_next(&device, &place->invplace_vplace); - if (rv == LABELCL_SUCCESS) { - place->invplace_vhdl = device; - } - else { - place->invplace_vhdl = GRAPH_VERTEX_NONE; - return(NULL); - } - } - - return(pinv); -} - -/* ARGSUSED */ -int -get_sizeof_inventory(int abi) -{ - return sizeof(inventory_t); -} - -/* Must be called prior to first call to get_next_inventory */ -void -start_scan_inventory(invplace_t *iplace) -{ - *iplace = INVPLACE_NONE; -} - -/* Must be called after last call to get_next_inventory */ -void -end_scan_inventory(invplace_t *iplace) -{ - devfs_handle_t vhdl = iplace->invplace_vhdl; - if (vhdl != GRAPH_VERTEX_NONE) - hwgraph_vertex_unref(vhdl); - *iplace = INVPLACE_NONE; /* paranoia */ -} - -/* - * Hardware inventory scanner. - * - * Calls fun() for every entry in inventory list unless fun() returns something - * other than 0. - */ -int -scaninvent(int (*fun)(inventory_t *, void *), void *arg) -{ - inventory_t *ie; - invplace_t iplace = { NULL,NULL, NULL }; - int rc; - - ie = 0; - rc = 0; - start_scan_inventory(&iplace); - while ((ie = (inventory_t *)get_next_inventory(&iplace))) { - rc = (*fun)(ie, arg); - if (rc) - break; - } - end_scan_inventory(&iplace); - return rc; -} - -/* - * Find a particular inventory object - * - * pinv can be a pointer to an inventory entry and the search will begin from - * there, or it can be 0 in which case the search starts at the beginning. - * A -1 for any of the other arguments is a wildcard (i.e. it always matches). - */ -inventory_t * -find_inventory(inventory_t *pinv, int class, int type, int controller, - int unit, int state) -{ - invplace_t iplace = { NULL,NULL, NULL }; - - start_scan_inventory(&iplace); - while ((pinv = (inventory_t *)get_next_inventory(&iplace)) != NULL) { - if (class != -1 && pinv->inv_class != class) - continue; - if (type != -1 && pinv->inv_type != type) - continue; - - /* XXXX - perhaps the "state" entry should be ignored so an - * an existing entry can be updated. See vino_init() and - * ml/IP22.c:add_ioboard() for an example. - */ - if (state != -1 && pinv->inv_state != state) - continue; - if (controller != -1 - && pinv->inv_controller != controller) - continue; - if (unit != -1 && pinv->inv_unit != unit) - continue; - break; - } - end_scan_inventory(&iplace); - - return(pinv); -} - - -/* -** Retrieve inventory data associated with a device. -*/ -inventory_t * -device_inventory_get_next( devfs_handle_t device, - invplace_t *invplace) -{ - inventory_t *pinv; - int rv; - - rv = hwgraph_inventory_get_next(device, invplace, &pinv); - if (rv == LABELCL_SUCCESS) - return(pinv); - else - return(NULL); -} - - -/* -** Associate canonical inventory information with a device (and -** add it to the general inventory). -*/ -void -device_inventory_add( devfs_handle_t device, - int class, - int type, - major_t controller, - minor_t unit, - int state) -{ - hwgraph_inventory_add(device, class, type, controller, unit, state); -} - -int -device_controller_num_get(devfs_handle_t device) -{ - return (hwgraph_controller_num_get(device)); -} - -void -device_controller_num_set(devfs_handle_t device, int contr_num) -{ - hwgraph_controller_num_set(device, contr_num); -} diff -Nru a/arch/ia64/sn/io/io.c b/arch/ia64/sn/io/io.c --- a/arch/ia64/sn/io/io.c Fri Feb 14 15:08:57 2003 +++ b/arch/ia64/sn/io/io.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -29,17 +29,11 @@ #include extern xtalk_provider_t hub_provider; -extern void hub_intr_init(devfs_handle_t hubv); +extern void hub_intr_init(vertex_hdl_t hubv); +static int force_fire_and_forget = 1; +static int ignore_conveyor_override; -/* - * Perform any initializations needed to support hub-based I/O. - * Called once during startup. - */ -void -hubio_init(void) -{ -} /* * Implementation of hub iobus operations. @@ -58,8 +52,8 @@ /* * Setup pio structures needed for a particular hub. */ -void -hub_pio_init(devfs_handle_t hubv) +static void +hub_pio_init(vertex_hdl_t hubv) { xwidgetnum_t widget; hubinfo_t hubinfo; @@ -114,7 +108,7 @@ */ /* ARGSUSED */ hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +hub_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -123,7 +117,7 @@ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); hubinfo_t hubinfo; hub_piomap_t bw_piomap; int bigwin, free_bw_index; @@ -288,7 +282,7 @@ void hub_piomap_free(hub_piomap_t hub_piomap) { - devfs_handle_t hubv; + vertex_hdl_t hubv; hubinfo_t hubinfo; nasid_t nasid; unsigned long s; @@ -371,7 +365,7 @@ */ /* ARGSUSED */ caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ +hub_piotrans_addr( vertex_hdl_t dev, /* translate to this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -379,7 +373,7 @@ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); hub_piomap_t hub_piomap; hubinfo_t hubinfo; caddr_t addr; @@ -416,7 +410,7 @@ */ /* ARGSUSED */ hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for this device */ +hub_dmamap_alloc( vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) /* defined in dma.h */ @@ -424,7 +418,7 @@ hub_dmamap_t dmamap; xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); - devfs_handle_t hubv = xwidget_info_master_get(widget_info); + vertex_hdl_t hubv = xwidget_info_master_get(widget_info); dmamap = kmalloc(sizeof(struct hub_dmamap_s), GFP_ATOMIC); dmamap->hdma_xtalk_info.xd_dev = dev; @@ -460,7 +454,7 @@ paddr_t paddr, /* map for this address */ size_t byte_count) /* map this many bytes */ { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); @@ -479,12 +473,7 @@ } /* There isn't actually any DMA mapping hardware on the hub. */ -#ifdef CONFIG_IA64_SGI_SN2 return( (PHYS_TO_DMA(paddr)) ); -#else - /* no translation needed */ - return(paddr); -#endif } /* @@ -498,7 +487,7 @@ alenlist_t palenlist, /* map this area of memory */ unsigned flags) { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); @@ -527,7 +516,7 @@ void hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */ { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED; @@ -549,18 +538,13 @@ */ /* ARGSUSED */ iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_addr( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags) /* defined in dma.h */ { -#ifdef CONFIG_IA64_SGI_SN2 return( (PHYS_TO_DMA(paddr)) ); -#else - /* no translation needed */ - return(paddr); -#endif } /* @@ -570,7 +554,7 @@ */ /* ARGSUSED */ alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_list( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags) /* defined in dma.h */ @@ -589,7 +573,7 @@ /*ARGSUSED*/ void -hub_dmaaddr_drain( devfs_handle_t vhdl, +hub_dmaaddr_drain( vertex_hdl_t vhdl, paddr_t addr, size_t bytes) { @@ -598,7 +582,7 @@ /*ARGSUSED*/ void -hub_dmalist_drain( devfs_handle_t vhdl, +hub_dmalist_drain( vertex_hdl_t vhdl, alenlist_t list) { /* XXX- flush caches, if cache coherency WAR is needed */ @@ -612,10 +596,8 @@ * Perform initializations that allow this hub to start crosstalk support. */ void -hub_provider_startup(devfs_handle_t hubv) +hub_provider_startup(vertex_hdl_t hubv) { - extern void hub_pio_init(devfs_handle_t hubv); - hub_pio_init(hubv); hub_intr_init(hubv); } @@ -624,7 +606,7 @@ * Shutdown crosstalk support from a hub. */ void -hub_provider_shutdown(devfs_handle_t hub) +hub_provider_shutdown(vertex_hdl_t hub) { /* TBD */ xtalk_provider_unregister(hub); @@ -666,46 +648,6 @@ /* - * Determine whether two PCI addresses actually refer to the same device. - * This only works if both addresses are in small windows. It's used to - * determine whether prom addresses refer to particular PCI devices. - */ -/* - * XXX - This won't work as written if we ever have more than two nodes - * on a crossbow. In that case, we'll need an array or partners. - */ -int -hub_check_pci_equiv(void *addra, void *addrb) -{ - nasid_t nasida, nasidb; - - /* - * This is for a permanent workaround that causes us to use a - * big window in place of small window 0. - */ - if (!hub_check_window_equiv(addra, addrb)) - return 0; - - /* If the offsets aren't the same, forget it. */ - if (SWIN_WIDGETADDR((__psunsigned_t)addra) != - (SWIN_WIDGETADDR((__psunsigned_t)addrb))) - return 0; - - /* Now, check the nasids */ - nasida = NASID_GET(addra); - nasidb = NASID_GET(addrb); - - ASSERT(NASID_TO_COMPACT_NODEID(nasida) != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasidb) != INVALID_NASID); - - /* - * Either the NASIDs must be the same or they must be crossbow - * partners (on the same crossbow). - */ - return (check_nasid_equiv(nasida, nasidb)); -} - -/* * hub_setup_prb(nasid, prbnum, credits, conveyor) * * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, @@ -716,8 +658,6 @@ { iprb_t prb; int prb_offset; - extern int force_fire_and_forget; - extern volatile int ignore_conveyor_override; if (force_fire_and_forget && !ignore_conveyor_override) if (conveyor == HUB_PIO_CONVEYOR) @@ -776,13 +716,8 @@ int direct_connect; hubii_wcr_t ii_wcr; int prbnum; - int cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); - if (nasid == get_console_nasid()) { - PUTBUF_LOCK(s); - cons_lock = 1; - } ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); @@ -812,9 +747,6 @@ } REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); - - if (cons_lock) - PUTBUF_UNLOCK(s); } /* Interface to allow special drivers to set hub specific * device flags. @@ -842,90 +774,6 @@ return 1; } -/* Interface to allow special drivers to set hub specific - * device flags. - * Return 0 on failure , 1 on success - */ -int -hub_device_flags_set(devfs_handle_t widget_vhdl, - hub_widget_flags_t flags) -{ - xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); - xwidgetnum_t widget_num = xwidget_info_id_get(widget_info); - devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); - hubinfo_t hub_info = 0; - nasid_t nasid; - unsigned long s; - int rv; - - /* Use the nasid from the hub info hanging off the hub vertex - * and widget number from the widget vertex - */ - hubinfo_get(hub_vhdl, &hub_info); - /* Being over cautious by grabbing a lock */ - s = mutex_spinlock(&hub_info->h_bwlock); - nasid = hub_info->h_nasid; - rv = hub_widget_flags_set(nasid,widget_num,flags); - mutex_spinunlock(&hub_info->h_bwlock, s); - - return rv; -} - -/* - * hub_device_inquiry - * Find out the xtalk widget related information stored in this - * hub's II. - */ -void -hub_device_inquiry(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - devfs_handle_t xconn, hub_vhdl; - char widget_name[8]; - hubreg_t ii_iidem,ii_iiwa, ii_iowa; - hubinfo_t hubinfo; - nasid_t nasid; - int d; - - sprintf(widget_name, "%d", widget); - if (hwgraph_traverse(xbus_vhdl, widget_name, &xconn) - != GRAPH_SUCCESS) - return; - - hub_vhdl = device_master_get(xconn); - if (hub_vhdl == GRAPH_VERTEX_NONE) - return; - - hubinfo_get(hub_vhdl, &hubinfo); - if (!hubinfo) - return; - - nasid = hubinfo->h_nasid; - - ii_iidem = REMOTE_HUB_L(nasid, IIO_IIDEM); - ii_iiwa = REMOTE_HUB_L(nasid, IIO_IIWA); - ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA); - -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("Inquiry Info for %v\n", xconn); -#else - printk("Inquiry Info for %p\n", (void *)xconn); -#endif - - printk("\tDevices shutdown [ "); - - for (d = 0 ; d <= 7 ; d++) - if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d)))) - printk(" %d", d); - - printk("]\n"); - - printk("\tInbound access ? %s\n", - ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no"); - - printk("\tOutbound access ? %s\n", - ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no"); - -} /* * A pointer to this structure hangs off of every hub hwgraph vertex. @@ -955,8 +803,6 @@ (xtalk_intr_free_f *) hub_intr_free, (xtalk_intr_connect_f *) hub_intr_connect, (xtalk_intr_disconnect_f *) hub_intr_disconnect, - (xtalk_intr_cpu_get_f *) hub_intr_cpu_get, - (xtalk_provider_startup_f *) hub_provider_startup, (xtalk_provider_shutdown_f *) hub_provider_shutdown, }; diff -Nru a/arch/ia64/sn/io/ioconfig_bus.c b/arch/ia64/sn/io/ioconfig_bus.c --- a/arch/ia64/sn/io/ioconfig_bus.c Mon Feb 24 04:55:13 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,402 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * ioconfig_bus - SGI's Persistent PCI Bus Numbering. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING" -#define SGI_IOCONFIG_BUS_VERSION "1.0" - -/* - * Some Global definitions. - */ -devfs_handle_t ioconfig_bus_handle = NULL; -unsigned long ioconfig_bus_debug = 0; - -#ifdef IOCONFIG_BUS_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -u64 ioconfig_file = 0; -u64 ioconfig_file_size = 0; -u64 ioconfig_activated = 0; -char ioconfig_kernopts[128]; - -/* - * For debugging purpose .. hardcode a table .. - */ -struct ascii_moduleid *ioconfig_bus_table; -u64 ioconfig_bus_table_size = 0; - - -int free_entry = 0; -int new_entry = 0; - -int next_basebus_number = 0; - -void -ioconfig_get_busnum(char *io_moduleid, int *bus_num) -{ - struct ascii_moduleid *temp; - int index; - - DBG("ioconfig_get_busnum io_moduleid %s\n", io_moduleid); - - *bus_num = -1; - temp = ioconfig_bus_table; - for (index = 0; index < free_entry; temp++, index++) { - if ( (io_moduleid[0] == temp->io_moduleid[0]) && - (io_moduleid[1] == temp->io_moduleid[1]) && - (io_moduleid[2] == temp->io_moduleid[2]) && - (io_moduleid[4] == temp->io_moduleid[4]) && - (io_moduleid[5] == temp->io_moduleid[5]) ) { - *bus_num = index * 0x10; - return; - } - } - - /* - * New IO Brick encountered. - */ - if (((int)io_moduleid[0]) == 0) { - DBG("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid); - return; - } - - io_moduleid[3] = '#'; - strcpy((char *)&(ioconfig_bus_table[free_entry].io_moduleid), io_moduleid); - *bus_num = free_entry * 0x10; - free_entry++; -} - -void -dump_ioconfig_table() -{ - - int index = 0; - struct ascii_moduleid *temp; - - temp = ioconfig_bus_table; - while (index < free_entry) { - DBG("ASSCI Module ID %s\n", temp->io_moduleid); - temp++; - index++; - } -} - -/* - * nextline - * This routine returns the nextline in the buffer. - */ -int nextline(char *buffer, char **next, char *line) -{ - - char *temp; - - if (buffer[0] == 0x0) { - return(0); - } - - temp = buffer; - while (*temp != 0) { - *line = *temp; - if (*temp != '\n'){ - *line = *temp; - temp++; line++; - } else - break; - } - - if (*temp == 0) - *next = temp; - else - *next = ++temp; - - return(1); -} - -/* - * build_pcibus_name - * This routine parses the ioconfig contents read into - * memory by ioconfig command in EFI and builds the - * persistent pci bus naming table. - */ -void -build_moduleid_table(char *file_contents, struct ascii_moduleid *table) -{ - /* - * Read the whole file into memory. - */ - int rc; - char *name; - char *temp; - char *next; - char *current; - char *line; - struct ascii_moduleid *moduleid; - - line = kmalloc(256, GFP_KERNEL); - memset(line, 0,256); - name = kmalloc(125, GFP_KERNEL); - memset(name, 0, 125); - moduleid = table; - current = file_contents; - while (nextline(current, &next, line)){ - - DBG("current 0x%lx next 0x%lx\n", current, next); - - temp = line; - /* - * Skip all leading Blank lines .. - */ - while (isspace(*temp)) - if (*temp != '\n') - temp++; - else - break; - - if (*temp == '\n') { - current = next; - memset(line, 0, 256); - continue; - } - - /* - * Skip comment lines - */ - if (*temp == '#') { - current = next; - memset(line, 0, 256); - continue; - } - - /* - * Get the next free entry in the table. - */ - rc = sscanf(temp, "%s", name); - strcpy(&moduleid->io_moduleid[0], name); - DBG("Found %s\n", name); - moduleid++; - free_entry++; - current = next; - memset(line, 0, 256); - } - - new_entry = free_entry; - kfree(line); - kfree(name); - - return; -} - -void -ioconfig_bus_init(void) -{ - - struct ia64_sal_retval ret_stuff; - u64 *temp; - int cnode; - - DBG("ioconfig_bus_init called.\n"); - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid_t nasid; - /* - * Make SAL call to get the address of the bus configuration table. - */ - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - nasid = COMPACT_TO_NASID_NODEID(cnode); - SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, nasid, 0, 0, 0, 0, 0); - temp = (u64 *)TO_NODE_CAC(nasid, ret_stuff.v0); - ioconfig_file = *temp; - DBG("ioconfig_bus_init: Nasid %d ret_stuff.v0 0x%lx\n", nasid, - ret_stuff.v0); - if (ioconfig_file) { - ioconfig_file_size = ret_stuff.v1; - ioconfig_file = (ioconfig_file | CACHEABLE_MEM_SPACE); - ioconfig_activated = 1; - break; - } - } - - DBG("ioconfig_bus_init: ret_stuff.v0 %p ioconfig_file %p %d\n", - ret_stuff.v0, (void *)ioconfig_file, (int)ioconfig_file_size); - - ioconfig_bus_table = kmalloc( 512, GFP_KERNEL ); - memset(ioconfig_bus_table, 0, 512); - - /* - * If ioconfig options are given on the bootline .. take it. - */ - if (*ioconfig_kernopts != '\0') { - /* - * ioconfig="..." kernel options given. - */ - DBG("ioconfig_bus_init: Kernel Options given.\n"); - (void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table); - (void) dump_ioconfig_table(ioconfig_bus_table); - return; - } - - if (ioconfig_activated) { - DBG("ioconfig_bus_init: ioconfig file given.\n"); - (void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table); - (void) dump_ioconfig_table(ioconfig_bus_table); - } else { - DBG("ioconfig_bus_init: ioconfig command not executed in prom\n"); - } - -} - -void -ioconfig_bus_new_entries(void) -{ - - - int index = 0; - struct ascii_moduleid *temp; - - if ((ioconfig_activated) && (free_entry > new_entry)) { - printk("### Please add the following new IO Bricks Module ID \n"); - printk("### to your Persistent Bus Numbering Config File\n"); - } else - return; - - index = new_entry; - temp = &ioconfig_bus_table[index]; - while (index < free_entry) { - printk("%s\n", temp); - temp++; - index++; - } - printk("### End\n"); - -} -static int ioconfig_bus_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - - struct ioconfig_parm parm; - - /* - * Copy in the parameters. - */ - copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm)); - parm.number = free_entry - new_entry; - parm.ioconfig_activated = ioconfig_activated; - copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm)); - copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry)); - - return 0; -} - -/* - * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus". - */ -static int ioconfig_bus_open(struct inode * inode, struct file * filp) -{ - if (ioconfig_bus_debug) { - DBG("ioconfig_bus_open called.\n"); - } - - return(0); - -} - -/* - * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus". - */ -static int ioconfig_bus_close(struct inode * inode, struct file * filp) -{ - - if (ioconfig_bus_debug) { - DBG("ioconfig_bus_close called.\n"); - } - - return(0); -} - -struct file_operations ioconfig_bus_fops = { - ioctl:ioconfig_bus_ioctl, - open:ioconfig_bus_open, /* open */ - release:ioconfig_bus_close /* release */ -}; - - -/* - * init_ifconfig_bus() - Boot time initialization. Ensure that it is called - * after devfs has been initialized. - * - */ -int init_ioconfig_bus(void) -{ - ioconfig_bus_handle = NULL; - ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &ioconfig_bus_fops, NULL); - - if (ioconfig_bus_handle == NULL) { - panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n"); - } - - return(0); - -} - -static int __init ioconfig_bus_setup (char *str) -{ - - char *temp; - - DBG("ioconfig_bus_setup: Kernel Options %s\n", str); - - temp = (char *)ioconfig_kernopts; - memset(temp, 0, 128); - while ( (*str != '\0') && !isspace (*str) ) { - if (*str == ',') { - *temp = '\n'; - temp++; - str++; - continue; - } - *temp = *str; - temp++; - str++; - } - - return(0); - -} -__setup("ioconfig=", ioconfig_bus_setup); diff -Nru a/arch/ia64/sn/io/klconflib.c b/arch/ia64/sn/io/klconflib.c --- a/arch/ia64/sn/io/klconflib.c Sun May 25 17:00:00 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1040 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define printf printk -int hasmetarouter; - -#define LDEBUG 0 -#define NIC_UNKNOWN ((nic_t) -1) - -#undef DEBUG_KLGRAPH -#ifdef DEBUG_KLGRAPH -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_KLGRAPH */ - -static void sort_nic_names(lboard_t *) ; - -u64 klgraph_addr[MAX_COMPACT_NODES]; - -lboard_t * -find_lboard(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (start->brd_type == brd_type) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_class(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -klinfo_t * -find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) -{ - int index, j; - - if (kli == (klinfo_t *)NULL) { - index = 0; - } else { - for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { - if (kli == KLCF_COMP(brd, j)) - break; - } - index = j; - if (index == KLCF_NUM_COMPS(brd)) { - DBG("find_component: Bad pointer: 0x%p\n", kli); - return (klinfo_t *)NULL; - } - index++; /* next component */ - } - - for (; index < KLCF_NUM_COMPS(brd); index++) { - kli = KLCF_COMP(brd, index); - DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); - if (KLCF_COMP_TYPE(kli) == struct_type) - return kli; - } - - /* Didn't find it. */ - return (klinfo_t *)NULL; -} - -klinfo_t * -find_first_component(lboard_t *brd, unsigned char struct_type) -{ - return find_component(brd, (klinfo_t *)NULL, struct_type); -} - -lboard_t * -find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod) && - (start->brd_slot == slot)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module(lboard_t *start, moduleid_t mod) -{ - /* Search all boards stored on this node. */ - while (start) { - if (MODULE_MATCH(start->brd_module, mod)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_type) -{ - while (start) { - - DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type); - - if (MODULE_MATCH(start->brd_module, mod) && - (KLCLASS(start->brd_type) == KLCLASS(brd_type))) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - - -/* - * Convert a NIC name to a name for use in the hardware graph. - */ -void -nic_name_convert(char *old_name, char *new_name) -{ - int i; - char c; - char *compare_ptr; - - if ((old_name[0] == '\0') || (old_name[1] == '\0')) { - strcpy(new_name, EDGE_LBL_XWIDGET); - } else { - for (i = 0; i < strlen(old_name); i++) { - c = old_name[i]; - - if (isalpha(c)) - new_name[i] = tolower(c); - else if (isdigit(c)) - new_name[i] = c; - else - new_name[i] = '_'; - } - new_name[i] = '\0'; - } - - /* XXX - - * Since a bunch of boards made it out with weird names like - * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and - * replace it with "baseio" to avoid confusion in the field. - * We also have to make sure we don't report media_io instead of - * baseio. - */ - - /* Skip underscores at the beginning of the name */ - for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) - ; - - /* - * Check for some names we need to replace. Early boards - * had junk following the name so check only the first - * characters. - */ - if (!strncmp(new_name, "io6", 3) || - !strncmp(new_name, "mio", 3) || - !strncmp(new_name, "media_io", 8)) - strcpy(new_name, "baseio"); - else if (!strncmp(new_name, "divo", 4)) - strcpy(new_name, "divo") ; - -} - -/* Check if the given board corresponds to the global - * master io6 - */ -int -is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot) -{ - lboard_t *board; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -/* If this works then look for callers of is_master_baseio() - * (e.g. iograph.c) and let them pass in a slot if they want - */ - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module); -#else - board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), module, slot); -#endif - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - board = find_lboard_module((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module); -#else - board = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - module, slot); -#endif - } -#endif - if (!board) - return(0); - return(board->brd_flags & GLOBAL_MASTER_IO6); -} -/* - * Find the lboard structure and get the board name. - * If we can't find the structure or it's too low a revision, - * use default name. - */ -lboard_t * -get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name) -{ - lboard_t *brd; - - brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - mod, slot); - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) - brd = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - mod, slot); - } -#endif - - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, name); - } - - /* - * PV # 540860 - * If the name is not 'baseio' - * get the lowest of all the names in the nic string. - * This is needed for boards like divo, which can have - * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio - * but it has some special case names that we would not - * like to disturb at this point. - */ - - /* gfx boards don't need any of this name scrambling */ - if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { - return(brd); - } - - if (!(!strcmp(name, "baseio") )) { - if (brd) { - sort_nic_names(brd) ; - /* Convert to small case, '-' to '_' etc */ - nic_name_convert(brd->brd_name, name) ; - } - } - - return(brd); -} - -/* - * get_actual_nasid - * - * Completely disabled brds have their klconfig on - * some other nasid as they have no memory. But their - * actual nasid is hidden in the klconfig. Use this - * routine to get it. Works for normal boards too. - */ -nasid_t -get_actual_nasid(lboard_t *brd) -{ - klhub_t *hub ; - - if (!brd) - return INVALID_NASID ; - - /* find out if we are a completely disabled brd. */ - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - if (!hub) - return INVALID_NASID ; - if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ - return hub->hub_info.physid ; - else - return brd->brd_nasid ; -} - -int -xbow_port_io_enabled(nasid_t nasid, int link) -{ - lboard_t *brd; - klxbow_t *xbow_p; - - /* - * look for boards that might contain an xbow or xbridge - */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW); - if (brd == NULL) return 0; - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return 0; - - if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) - return 0; - - DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p); - - return 1; -} - -void -board_to_path(lboard_t *brd, char *path) -{ - moduleid_t modnum; - char *board_name; - - ASSERT(brd); - - switch (KLCLASS(brd->brd_type)) { - - case KLCLASS_NODE: - board_name = EDGE_LBL_NODE; - break; - case KLCLASS_ROUTER: - if (brd->brd_type == KLTYPE_META_ROUTER) { - board_name = EDGE_LBL_META_ROUTER; - hasmetarouter++; - } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { - board_name = EDGE_LBL_REPEATER_ROUTER; - hasmetarouter++; - } else - board_name = EDGE_LBL_ROUTER; - break; - case KLCLASS_MIDPLANE: - board_name = EDGE_LBL_MIDPLANE; - break; - case KLCLASS_IO: - board_name = EDGE_LBL_IO; - break; - case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PBRICK) - board_name = EDGE_LBL_PBRICK; - else if (brd->brd_type == KLTYPE_IBRICK) - board_name = EDGE_LBL_IBRICK; - else if (brd->brd_type == KLTYPE_XBRICK) - board_name = EDGE_LBL_XBRICK; - else - board_name = EDGE_LBL_IOBRICK; - break; - default: - board_name = EDGE_LBL_UNKNOWN; - } - - modnum = brd->brd_module; - - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); -#ifdef __ia64 - { - char buffer[16]; - memset(buffer, 0, 16); - format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); - sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name); - } -#else - sprintf(path, "%H/%s", modnum, board_name); -#endif -} - -/* - * Get the module number for a NASID. - */ -moduleid_t -get_module_id(nasid_t nasid) -{ - lboard_t *brd; - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (!brd) - return INVALID_MODULE; - else - return brd->brd_module; -} - - -#define MHZ 1000000 - - -/* Get the canonical hardware graph name for the given pci component - * on the given io board. - */ -void -device_component_canonical_name_get(lboard_t *brd, - klinfo_t *component, - char *name) -{ - moduleid_t modnum; - slotid_t slot; - char board_name[20]; - - ASSERT(brd); - - /* Get the module number of this board */ - modnum = brd->brd_module; - - /* Convert the [ CLASS | TYPE ] kind of slotid - * into a string - */ - slot = brd->brd_slot; - ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); - - /* Get the io board name */ - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, board_name); - } - - /* Give out the canonical name of the pci device*/ - sprintf(name, - "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/" - EDGE_LBL_PCI"/%d", - modnum, board_name,KLCF_BRIDGE_W_ID(component)); -} - -/* - * Get the serial number of the main component of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - * Assumptions: Nic manufacturing string has the following format - * *Serial:;* - */ -static int -component_serial_number_get(lboard_t *board, - klconf_off_t mfg_nic_offset, - char *serial_number, - char *key_pattern) -{ - - char *mfg_nic_string; - char *serial_string,*str; - int i; - char *serial_pattern = "Serial:"; - - /* We have an error on a null mfg nic offset */ - if (!mfg_nic_offset) - return(1); - /* Get the hub's manufacturing nic information - * which is in the form of a pre-formatted string - */ - mfg_nic_string = - (char *)NODE_OFFSET_TO_K0(NASID_GET(board), - mfg_nic_offset); - /* There is no manufacturing nic info */ - if (!mfg_nic_string) - return(1); - - str = mfg_nic_string; - /* Look for the key pattern first (if it is specified) - * and then print the serial number corresponding to that. - */ - if (strcmp(key_pattern,"") && - !(str = strstr(mfg_nic_string,key_pattern))) - return(1); - - /* There is no serial number info in the manufacturing - * nic info - */ - if (!(serial_string = strstr(str,serial_pattern))) - return(1); - - serial_string = serial_string + strlen(serial_pattern); - /* Copy the serial number information from the klconfig */ - i = 0; - while (serial_string[i] != ';') { - serial_number[i] = serial_string[i]; - i++; - } - serial_number[i] = 0; - - return(0); -} -/* - * Get the serial number of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - */ - -int -board_serial_number_get(lboard_t *board,char *serial_number) -{ - ASSERT(board && serial_number); - if (!board || !serial_number) - return(1); - - strcpy(serial_number,""); - switch(KLCLASS(board->brd_type)) { - case KLCLASS_CPU: { /* Node board */ - klhub_t *hub; - - /* Get the hub component information */ - hub = (klhub_t *)find_first_component(board, - KLSTRUCT_HUB); - /* If we don't have a hub component on an IP27 - * then we have a weird klconfig. - */ - if (!hub) - return(1); - /* Get the serial number information from - * the hub's manufacturing nic info - */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - "IP37")) -#else - "IP27")) - /* Try with IP31 key if IP27 key fails */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, - "IP31")) -#endif /* CONFIG_IA64_SGI_SN1 */ - return(1); - break; - } - case KLCLASS_IO: { /* IO board */ - if (KLTYPE(board->brd_type) == KLTYPE_TPU) { - /* Special case for TPU boards */ - kltpu_t *tpu; - - /* Get the tpu component information */ - tpu = (kltpu_t *)find_first_component(board, - KLSTRUCT_TPU); - /* If we don't have a tpu component on a tpu board - * then we have a weird klconfig. - */ - if (!tpu) - return(1); - /* Get the serial number information from - * the tpu's manufacturing nic info - */ - if (component_serial_number_get(board, - tpu->tpu_mfg_nic, - serial_number, - "")) - return(1); - break; - } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) || - (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) { - /* Special case for GSN boards */ - klgsn_t *gsn; - - /* Get the gsn component information */ - gsn = (klgsn_t *)find_first_component(board, - ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ? - KLSTRUCT_GSN_A : KLSTRUCT_GSN_B)); - /* If we don't have a gsn component on a gsn board - * then we have a weird klconfig. - */ - if (!gsn) - return(1); - /* Get the serial number information from - * the gsn's manufacturing nic info - */ - if (component_serial_number_get(board, - gsn->gsn_mfg_nic, - serial_number, - "")) - return(1); - break; - } else { - klbri_t *bridge; - - /* Get the bridge component information */ - bridge = (klbri_t *)find_first_component(board, - KLSTRUCT_BRI); - /* If we don't have a bridge component on an IO board - * then we have a weird klconfig. - */ - if (!bridge) - return(1); - /* Get the serial number information from - * the bridge's manufacturing nic info - */ - if (component_serial_number_get(board, - bridge->bri_mfg_nic, - serial_number, - "")) - return(1); - break; - } - } - case KLCLASS_ROUTER: { /* Router board */ - klrou_t *router; - - /* Get the router component information */ - router = (klrou_t *)find_first_component(board, - KLSTRUCT_ROU); - /* If we don't have a router component on a router board - * then we have a weird klconfig. - */ - if (!router) - return(1); - /* Get the serial number information from - * the router's manufacturing nic info - */ - if (component_serial_number_get(board, - router->rou_mfg_nic, - serial_number, - "")) - return(1); - break; - } - case KLCLASS_GFX: { /* Gfx board */ - klgfx_t *graphics; - - /* Get the graphics component information */ - graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); - /* If we don't have a gfx component on a gfx board - * then we have a weird klconfig. - */ - if (!graphics) - return(1); - /* Get the serial number information from - * the graphics's manufacturing nic info - */ - if (component_serial_number_get(board, - graphics->gfx_mfg_nic, - serial_number, - "")) - return(1); - break; - } - default: - strcpy(serial_number,""); - break; - } - return(0); -} - -#include "asm/sn/sn_private.h" - -xwidgetnum_t -nodevertex_widgetnum_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - return(hubinfo_p->h_widgetid); -} - -devfs_handle_t -nodevertex_xbow_peer_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - nasid_t xbow_peer_nasid; - cnodeid_t xbow_peer; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; - if(xbow_peer_nasid == INVALID_NASID) - return ( (devfs_handle_t)-1); - xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); - return(NODEPDA(xbow_peer)->node_vertex); -} - -/* NIC Sorting Support */ - -#define MAX_NICS_PER_STRING 32 -#define MAX_NIC_NAME_LEN 32 - -static char * -get_nic_string(lboard_t *lb) -{ - int i; - klinfo_t *k = NULL ; - klconf_off_t mfg_off = 0 ; - char *mfg_nic = NULL ; - - for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { - k = KLCF_COMP(lb, i) ; - switch(k->struct_type) { - case KLSTRUCT_BRI: - mfg_off = ((klbri_t *)k)->bri_mfg_nic ; - break ; - - case KLSTRUCT_HUB: - mfg_off = ((klhub_t *)k)->hub_mfg_nic ; - break ; - - case KLSTRUCT_ROU: - mfg_off = ((klrou_t *)k)->rou_mfg_nic ; - break ; - - case KLSTRUCT_GFX: - mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; - break ; - - case KLSTRUCT_TPU: - mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; - break ; - - case KLSTRUCT_GSN_A: - case KLSTRUCT_GSN_B: - mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; - break ; - - case KLSTRUCT_XTHD: - mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; - break; - - default: - mfg_off = 0 ; - break ; - } - if (mfg_off) - break ; - } - - if ((mfg_off) && (k)) - mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; - - return mfg_nic ; -} - -char * -get_first_string(char **ptrs, int n) -{ - int i ; - char *tmpptr ; - - if ((ptrs == NULL) || (n == 0)) - return NULL ; - - tmpptr = ptrs[0] ; - - if (n == 1) - return tmpptr ; - - for (i = 0 ; i < n ; i++) { - if (strcmp(tmpptr, ptrs[i]) > 0) - tmpptr = ptrs[i] ; - } - - return tmpptr ; -} - -int -get_ptrs(char *idata, char **ptrs, int n, char *label) -{ - int i = 0 ; - char *tmp = idata ; - - if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) - return 0 ; - - while ( (tmp = strstr(tmp, label)) ){ - tmp += strlen(label) ; - /* check for empty name field, and last NULL ptr */ - if ((i < (n-1)) && (*tmp != ';')) { - ptrs[i++] = tmp ; - } - } - - ptrs[i] = NULL ; - - return i ; -} - -/* - * sort_nic_names - * - * Does not really do sorting. Find the alphabetically lowest - * name among all the nic names found in a nic string. - * - * Return: - * Nothing - * - * Side Effects: - * - * lb->brd_name gets the new name found - */ - -static void -sort_nic_names(lboard_t *lb) -{ - char *nic_str ; - char *ptrs[MAX_NICS_PER_STRING] ; - char name[MAX_NIC_NAME_LEN] ; - char *tmp, *tmp1 ; - - *name = 0 ; - - /* Get the nic pointer from the lb */ - - if ((nic_str = get_nic_string(lb)) == NULL) - return ; - - tmp = get_first_string(ptrs, - get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; - - if (tmp == NULL) - return ; - - if ( (tmp1 = strchr(tmp, ';')) ){ - strlcpy(name, tmp, tmp1-tmp) ; - } else { - strlcpy(name, tmp, (sizeof(name))) ; - } - - strlcpy(lb->brd_name, name, sizeof(lb->brd_name)) ; -} - - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdp789012345"; - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - int rack, position; - char brickchar; - - rack = MODULE_GET_RACK(m); - ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); - brickchar = MODULE_GET_BTCHAR(m); - position = MODULE_GET_BPOS(m); - - if (fmt == MODULE_FORMAT_BRIEF) { - /* Brief module number format, eg. 002c15 */ - - /* Decompress the rack number */ - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - /* Add the brick type */ - *buffer++ = brickchar; - } - else if (fmt == MODULE_FORMAT_LONG) { - /* Fuller hwgraph format, eg. rack/002/bay/15 */ - - strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); - - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); - } - - /* Add the bay position, using at least two digits */ - if (position < 10) - *buffer++ = '0'; - sprintf(buffer, "%d", position); - -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - * The long form does not include a brick type, so it defaults to 0 (CBrick) - */ -int -parse_module_id(char *buffer) -{ - unsigned int v, rack, bay, type, form; - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) { - form = MODULE_FORMAT_LONG; - buffer += strlen(EDGE_LBL_RACK "/"); - - /* A long module ID must be exactly 5 non-template chars. */ - if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5) - return -1; - } - else { - form = MODULE_FORMAT_BRIEF; - - /* A brief module id must be exactly 6 characters */ - if (strlen(buffer) != 6) - return -2; - } - - /* The rack number must be exactly 3 digits */ - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2]))) - return -3; - - rack = 0; - v = *buffer++ - '0'; - if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return -4; - RACK_ADD_CLASS(rack, v); - - v = *buffer++ - '0'; - if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return -5; - RACK_ADD_GROUP(rack, v); - - v = *buffer++ - '0'; - /* rack numbers are 1-based */ - if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return -6; - RACK_ADD_NUM(rack, v); - - if (form == MODULE_FORMAT_BRIEF) { - /* Next should be a module type character. Accept ucase or lcase. */ - c = *buffer++; - if (!isalpha(c)) - return -7; - - /* strchr() returns a pointer into brick_types[], or NULL */ - type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types); - if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT) - return -8; - } - else { - /* Hardcode the module type, and skip over the boilerplate */ - type = MODULE_CBRICK; - - if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer) - return -9; - - buffer += strlen("/" EDGE_LBL_RPOS "/"); - } - - /* The bay number is last. Make sure it's exactly two digits */ - - if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2])) - return -10; - - bay = 10 * (buffer[0] - '0') + (buffer[1] - '0'); - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return -11; - - m = RBT_TO_MODULE(rack, bay, type); - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#else /* CONFIG_IA64_SGI_SN1 */ - -/* - * Format a module id for printing. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - if (fmt == MODULE_FORMAT_BRIEF) { - sprintf(buffer, "%d", m); - } - else if (fmt == MODULE_FORMAT_LONG) { - sprintf(buffer, EDGE_LBL_MODULE "/%d", m); - } -} - -/* - * Parse a module id, in either brief or long form. - * Returns < 0 on error. - */ -int -parse_module_id(char *buffer) -{ - moduleid_t m; - char c; - - if (strstr(buffer, EDGE_LBL_MODULE "/") == buffer) - buffer += strlen(EDGE_LBL_MODULE "/"); - - for (m = 0; *buffer; buffer++) { - c = *buffer; - if (!isdigit(c)) - return -1; - m = 10 * m + (c - '0'); - } - - /* avoid sign extending the moduleid_t */ - return (int)(unsigned short)m; -} - -#endif /* CONFIG_IA64_SGI_SN1 */ - - diff -Nru a/arch/ia64/sn/io/klgraph.c b/arch/ia64/sn/io/klgraph.c --- a/arch/ia64/sn/io/klgraph.c Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,804 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * klgraph.c- - * This file specifies the interface between the kernel and the PROM's - * configuration data structures. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define KLGRAPH_DEBUG 1 */ -#ifdef KLGRAPH_DEBUG -#define GRPRINTF(x) printk x -#define CE_GRPANIC CE_PANIC -#else -#define GRPRINTF(x) -#define CE_GRPANIC CE_PANIC -#endif - -#include - -extern char arg_maxnodes[]; -extern u64 klgraph_addr[]; - -/* - * Support for verbose inventory via hardware graph. - * klhwg_invent_alloc allocates the necessary size of inventory information - * and fills in the generic information. - */ -invent_generic_t * -klhwg_invent_alloc(cnodeid_t cnode, int class, int size) -{ - invent_generic_t *invent; - - invent = kern_malloc(size); - if (!invent) return NULL; - - invent->ig_module = NODE_MODULEID(cnode); - invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode)); - invent->ig_invclass = class; - - return invent; -} - -/* - * Add information about the baseio prom version number - * as a part of detailed inventory info in the hwgraph. - */ -void -klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) -{ - invent_miscinfo_t *baseio_inventory; - unsigned char version = 0,revision = 0; - - /* Allocate memory for the "detailed inventory" info - * for the baseio - */ - baseio_inventory = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t)); - baseio_inventory->im_type = INV_IO6PROM; - /* Read the io6prom revision from the nvram */ -#ifdef LATER - nvram_prom_version_get(&version,&revision); -#endif - /* Store the revision info in the inventory */ - baseio_inventory->im_version = version; - baseio_inventory->im_rev = revision; - /* Put the inventory info in the hardware graph */ - hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) baseio_inventory); - /* Make the information available to the user programs - * thru hwgfs. - */ - hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -char *hub_rev[] = { - "0.0", - "1.0", - "2.0", - "2.1", - "2.2", - "2.3" -}; - -/* - * Add detailed cpu inventory info to the hardware graph. - */ -void -klhwg_hub_invent_info(devfs_handle_t hubv, - cnodeid_t cnode, - klhub_t *hub) -{ - invent_miscinfo_t *hub_invent; - - hub_invent = (invent_miscinfo_t *) - klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t)); - if (!hub_invent) - return; - - if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub)) - hub_invent->im_gen.ig_flag = INVENT_ENABLED; - - hub_invent->im_type = INV_HUB; - hub_invent->im_rev = hub->hub_info.revision; - hub_invent->im_speed = hub->hub_speed; - hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, - (arbitrary_info_t) hub_invent); - hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT, - sizeof(invent_miscinfo_t)); -} - -/* ARGSUSED */ -void -klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) -{ -#if defined(CONFIG_IA64_SGI_SN1) - devfs_handle_t myhubv; - devfs_handle_t hub_mon; - devfs_handle_t synergy; - devfs_handle_t fsb0; - devfs_handle_t fsb1; - int rc; - extern struct file_operations hub_mon_fops; - - GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB)); - - (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); - rc = device_master_set(myhubv, node_vertex); - - /* - * hub perf stats. - */ - rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO, - (arbitrary_info_t)(&NODEPDA(cnode)->hubstats)); - - if (rc != GRAPH_SUCCESS) { - printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d", - (void *)myhubv, rc); - } - - klhwg_hub_invent_info(myhubv, cnode, hub); - - hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &hub_mon_fops, - (void *)(long)cnode); - - init_hub_stats(cnode, NODEPDA(cnode)); - - /* - * synergy perf - */ - (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy); - (void) hwgraph_path_add(synergy, "0", &fsb0); - (void) hwgraph_path_add(synergy, "1", &fsb1); - - fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0)); - - fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1)); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) -{ - lboard_t *brd; - klxbow_t *xbow_p; - nasid_t hub_nasid; - cnodeid_t hub_cnode; - int widgetnum; - devfs_handle_t xbow_v, hubv; - /*REFERENCED*/ - graph_error_t err; - - if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL) - return; - - if (KL_CONFIG_DUPLICATE_BOARD(brd)) - return; - - GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n", - cnode, nasid)); - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return; - -#ifdef LATER - /* - * We cannot support this function in devfs .. see below where - * we use hwgraph_path_add() to create this vertex with a known - * name. - */ - err = hwgraph_vertex_create(&xbow_v); - ASSERT(err == GRAPH_SUCCESS); - - xswitch_vertex_init(xbow_v); -#endif /* LATER */ - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) - continue; - - hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - if (hub_nasid == INVALID_NASID) { - printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); - continue; - } - - hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid); - - if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) { - continue; - } - - hubv = cnodeid_to_vertex(hub_cnode); - - err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p to vertex 0x%p," - "error %d\n", - (void *)hubv, (void *)xbow_v, err); - } - xswitch_vertex_init(xbow_v); - - NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; - - /* - * XXX - This won't work is we ever hook up two hubs - * by crosstown through a crossbow. - */ - if (hub_nasid != nasid) { - NODEPDA(hub_cnode)->xbow_peer = nasid; - NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer = - hub_nasid; - } - - GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n", - hub_nasid, EDGE_LBL_XTALK, hubv)); - -#ifdef LATER - err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - PRINT_PANIC("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), " - "error %d\n", - hubv, hubv, xbow_v, xbow_v, err); - } -#endif - } -} - - -/* ARGSUSED */ -void -klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) -{ - nasid_t nasid; - lboard_t *brd; - klhub_t *hub; - devfs_handle_t node_vertex = NULL; - char path_buffer[100]; - int rv; - char *s; - int board_disabled = 0; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n", - cnode, nasid, brd)); - ASSERT(brd); - - do { - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Node vertex creation failed. " - "Path == %s", - path_buffer); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - if(hub->hub_info.flags & KLINFO_ENABLE) - board_disabled = 0; - else - board_disabled = 1; - - if(!board_disabled) { - mark_nodevertex_as_node(node_vertex, - cnode + board_disabled * numnodes); - - s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - NODEPDA(cnode)->hwg_node_name = - kmalloc(strlen(s) + 1, - GFP_KERNEL); - ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL); - strcpy(NODEPDA(cnode)->hwg_node_name, s); - - hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); - - /* Set up node board's slot */ - NODEPDA(cnode)->slotdesc = brd->brd_slot; - - /* Set up the module we're in */ - NODEPDA(cnode)->module_id = brd->brd_module; - NODEPDA(cnode)->module = module_lookup(brd->brd_module); - } - - if(!board_disabled) - klhwg_add_hub(node_vertex, hub, cnode); - - brd = KLCF_NEXT(brd); - if (brd) - brd = find_lboard(brd, KLTYPE_SNIA); - else - break; - } while(brd); -} - - -/* ARGSUSED */ -void -klhwg_add_all_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - devfs_handle_t node_vertex; - char path_buffer[100]; - int rv; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - /* No routers stored in this node's memory */ - continue; - - do { - ASSERT(brd); - GRPRINTF(("Router board struct is %p\n", brd)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) - continue; - - GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module)); - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("Router path is %s\n", path_buffer)); - - /* Add the router */ - GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n", - path_buffer, hwgraph_root)); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - - if (rv != GRAPH_SUCCESS) - PRINT_PANIC("Router vertex creation " - "failed. Path == %s", - path_buffer); - - GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n", - brd)); - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), - KLTYPE_ROUTER)) ); - - GRPRINTF(("klhwg_add_all_routers: Done.\n")); - } - -} - -/* ARGSUSED */ -void -klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, - cnodeid_t cnode, nasid_t nasid) -{ - klrou_t *router; - char path_buffer[50]; - char dest_path[50]; - devfs_handle_t router_hndl; - devfs_handle_t dest_hndl; - int rc; - int port; - lboard_t *dest_brd; - - GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n", - cnode)); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) { - GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n", - brd, cnode)); - return; - } - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); - - if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes)) - return; - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find router: %s", path_buffer); - - /* We don't know what to do with multiple router components */ - if (brd->brd_numcompts != 1) { - PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n", - brd->brd_numcompts); - return; - } - - - /* Convert component 0 to klrou_t ptr */ - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), - brd->brd_compts[0]); - - for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - /* See if the port's active */ - if (router->rou_port[port].port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", - port)); - continue; - } - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) - == INVALID_CNODEID) { - continue; - } - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find router: %s", dest_path); - } - GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n", - path_buffer, port, dest_path)); - - sprintf(dest_path, "%d", port); - - rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); - - if (rc == GRAPH_DUP) { - GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", - port, router->rou_port[port].port_nasid, - path_buffer, dest_path)); - continue; - } - - if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes)) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } -} - - -void -klhwg_connect_routers(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n", - cnode)); - - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - continue; - - do { - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - klhwg_connect_one_router(hwgraph_root, brd, - cnode, nasid); - - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); - } -} - - - -void -klhwg_connect_hubs(devfs_handle_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - klhub_t *hub; - lboard_t *dest_brd; - devfs_handle_t hub_hndl; - devfs_handle_t dest_hndl; - char path_buffer[50]; - char dest_path[50]; - graph_error_t rc; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - - GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n", - cnode)); - - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(brd); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - - /* See if the port's active */ - if (hub->hub_port.port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_hubs: port inactive.\n")); - continue; - } - - if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID) - continue; - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer)); - rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find hub: %s", path_buffer); - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - hub->hub_port.port_nasid, - hub->hub_port.port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - PRINT_PANIC("Can't find board: %s", dest_path); - } else { - - - GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n", - path_buffer, dest_path)); - - rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT); - - if (rc != GRAPH_SUCCESS) - PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - - } - } -} - -/* Store the pci/vme disabled board information as extended administrative - * hints which can later be used by the drivers using the device/driver - * admin interface. - */ -void -klhwg_device_disable_hints_add(void) -{ - cnodeid_t cnode; /* node we are looking at */ - nasid_t nasid; /* nasid of the node */ - lboard_t *board; /* board we are looking at */ - int comp_index; /* component index */ - klinfo_t *component; /* component in the board we are - * looking at - */ - char device_name[MAXDEVNAME]; - -#ifdef LATER - device_admin_table_init(); -#endif - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - /* Check out all the board info stored on a node */ - while(board) { - /* No need to look at duplicate boards or non-io - * boards - */ - if (KL_CONFIG_DUPLICATE_BOARD(board) || - KLCLASS(board->brd_type) != KLCLASS_IO) { - board = KLCF_NEXT(board); - continue; - } - /* Check out all the components of a board */ - for (comp_index = 0; - comp_index < KLCF_NUM_COMPS(board); - comp_index++) { - component = KLCF_COMP(board,comp_index); - /* If the component is enabled move on to - * the next component - */ - if (KLCONFIG_INFO_ENABLED(component)) - continue; - /* NOTE : Since the prom only supports - * the disabling of pci devices the following - * piece of code makes sense. - * Make sure that this assumption is valid - */ - /* This component is disabled. Store this - * hint in the extended device admin table - */ - /* Get the canonical name of the pci device */ - device_component_canonical_name_get(board, - component, - device_name); -#ifdef LATER - device_admin_table_update(device_name, - ADMIN_LBL_DISABLED, - "yes"); -#endif -#ifdef DEBUG - printf("%s DISABLED\n",device_name); -#endif - } - /* go to the next board info stored on this - * node - */ - board = KLCF_NEXT(board); - } - } -} - -void -klhwg_add_all_modules(devfs_handle_t hwgraph_root) -{ - cmoduleid_t cm; - char name[128]; - devfs_handle_t vhdl; - int rc; - char buffer[16]; - - /* Add devices under each module */ - - for (cm = 0; cm < nummodules; cm++) { - /* Use module as module vertex fastinfo */ - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF); - sprintf(name, EDGE_LBL_MODULE "/%s", buffer); -#else - sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]); - - /* Add system controller */ - -#ifdef __ia64 - sprintf(name, - EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, - buffer); -#else - sprintf(name, - EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1, - modules[cm]->id); -#endif - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT_ALWAYS(rc == GRAPH_SUCCESS); - rc = rc; - - hwgraph_info_add_LBL(vhdl, - INFO_LBL_ELSC, - (arbitrary_info_t) (__psint_t) 1); - -#ifdef LATER - sndrv_attach(vhdl); -#else - /* - * We need to call the drivers attach routine .. - */ - FIXME("klhwg_add_all_modules: Need code to call driver attach.\n"); -#endif - } -} - -void -klhwg_add_all_nodes(devfs_handle_t hwgraph_root) -{ - //gda_t *gdap = GDA; - gda_t *gdap; - cnodeid_t cnode; - - gdap = (gda_t *)0xe000000000002400; - - FIXME("klhwg_add_all_nodes: FIX GDA\n"); - - for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - klhwg_add_node(hwgraph_root, cnode, gdap); - } - - for (cnode = 0; cnode < numnodes; cnode++) { - ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID); - - klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]); - } - - /* - * As for router hardware inventory information, we set this - * up in router.c. - */ - - klhwg_add_all_routers(hwgraph_root); - klhwg_connect_routers(hwgraph_root); - klhwg_connect_hubs(hwgraph_root); - - /* Assign guardian nodes to each of the - * routers in the system. - */ - -#ifdef LATER - router_guardians_set(hwgraph_root); -#endif - - /* Go through the entire system's klconfig - * to figure out which pci components have been disabled - */ - klhwg_device_disable_hints_add(); - -} diff -Nru a/arch/ia64/sn/io/klgraph_hack.c b/arch/ia64/sn/io/klgraph_hack.c --- a/arch/ia64/sn/io/klgraph_hack.c Tue Dec 3 10:07:23 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,341 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -/* - * This is a temporary file that statically initializes the expected - * initial klgraph information that is normally provided by prom. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -extern u64 klgraph_addr[]; -void * real_port; -void * real_io_base; -void * real_addr; - -char *BW0 = NULL; - -kl_config_hdr_t *linux_klcfg; - -#ifdef DEFINE_DUMP_RTNS -/* forward declarations */ -static void dump_ii(void), dump_crossbow(void); -static void clear_ii_error(void); -#endif /* DEFINE_DUMP_RTNS */ - -#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) -#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) -#define HUBREG ((char *)0xc0000a0001e00000) -#define WIDGET0 ((char *)0xc0000a0000000000) -#define WIDGET4 ((char *)0xc0000a0000000004) - -#define SYNERGY_WIDGET ((char *)0xc0000e0000000000) -#define SYNERGY_SWIZZLE ((char *)0xc0000e0000000400) -#define HUBREG ((char *)0xc0000a0001e00000) -#define WIDGET0 ((char *)0xc0000a0000000000) - -#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c - -void -klgraph_hack_init(void) -{ - - u64 *temp; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * We need to know whether we are booting from PROM or - * boot from disk. - */ - linux_klcfg = (kl_config_hdr_t *)0xe000000000030000; - if (linux_klcfg->ch_magic == 0xbeedbabe) { - return; - } else { - panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n"); - } - - convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000); - -#else - - if (IS_RUNNING_ON_SIMULATOR()) { - printk("Creating FAKE Klconfig Structure for Embeded Kernel\n"); - klgraph_addr[0] = 0xe000003000030000; - - /* - * klconfig entries initialization - mankato - */ - convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000); - convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178); - convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000); - convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000); - convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070); - convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70); - convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330); - convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101); - convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67); - convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40); - convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0); - convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000); - convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000); - convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000); - convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101); - convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff); - convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50); - convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070); - convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000); - convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000); - convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101); - convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff); - convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0); - convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140); - convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000); - convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000); - convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101); - convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff); - convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190); - convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000); - convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140); - convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000); - convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000); - convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000); - convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000); - /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */ - convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000); - convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000); - convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000); - convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000); - convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000); - convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000); - convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001); - convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000); - convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff); - convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200); - convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000); - convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000); - convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000); - convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff); - convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000); - convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000); - convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000); - convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000); - convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a); - convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000); - convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000); - convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e); - convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000); - convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000); - convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e); - convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000); - convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff); - convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077); - convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8); - convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000); - convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002); - convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000); - convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000); - convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000); - convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f); - convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff); - convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9); - convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c); - convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0); - convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000); - convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003); - convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000); - convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000); - convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); - convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004); - convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000); - convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000); - convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000); - convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000); - convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000); - convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005); - convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000); - convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); - convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000); - convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006); - convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000); - convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000); - convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000); - convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000); - convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff); - convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000); - convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000); - convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001); - convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff); - convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000); - convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000); - convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002); - convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff); - convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000); - convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000); - convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003); - convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff); - convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000); -} - -#endif - -} - - - - - -#ifdef DEFINE_DUMP_RTNS -/* - * these were useful for printing out registers etc - * during bringup - */ - -static void -xdump(long long *addr, int count) -{ - int ii; - volatile long long *xx = addr; - - for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%p\n", (void *)xx, (void *)*xx); - } -} - -static void -xdump32(unsigned int *addr, int count) -{ - int ii; - volatile unsigned int *xx = addr; - - for ( ii = 0; ii < count; ii++, xx++ ) { - printk("0x%p : 0x%0x\n", (void *)xx, (int)*xx); - } -} - -static void -clear_ii_error(void) -{ - volatile long long *tmp; - - printk("... WSTAT "); - xdump((long long *)0xc0000a0001c00008, 1); - printk("... WCTRL "); - xdump((long long *)0xc0000a0001c00020, 1); - printk("... WLCSR "); - xdump((long long *)0xc0000a0001c00128, 1); - printk("... IIDSR "); - xdump((long long *)0xc0000a0001c00138, 1); - printk("... IOPRBs "); - xdump((long long *)0xc0000a0001c00198, 9); - printk("... IXSS "); - xdump((long long *)0xc0000a0001c00210, 1); - printk("... IBLS0 "); - xdump((long long *)0xc0000a0001c10000, 1); - printk("... IBLS1 "); - xdump((long long *)0xc0000a0001c20000, 1); - - /* Write IOERR clear to clear the CRAZY bit in the status */ - tmp = (long long *)0xc0000a0001c001f8; *tmp = (long long)0xffffffff; - - /* dump out local block error registers */ - printk("... "); - xdump((long long *)0xc0000a0001e04040, 1); /* LB_ERROR_BITS */ - printk("... "); - xdump((long long *)0xc0000a0001e04050, 1); /* LB_ERROR_HDR1 */ - printk("... "); - xdump((long long *)0xc0000a0001e04058, 1); /* LB_ERROR_HDR2 */ - /* and clear the LB_ERROR_BITS */ - tmp = (long long *)0xc0000a0001e04040; *tmp = 0x0; - printk("clr: "); - xdump((long long *)0xc0000a0001e04040, 1); /* LB_ERROR_BITS */ - tmp = (long long *)0xc0000a0001e04050; *tmp = 0x0; - tmp = (long long *)0xc0000a0001e04058; *tmp = 0x0; -} - - -static void -dump_ii(void) -{ - printk("===== Dump the II regs =====\n"); - xdump((long long *)0xc0000a0001c00000, 2); - xdump((long long *)0xc0000a0001c00020, 1); - xdump((long long *)0xc0000a0001c00100, 37); - xdump((long long *)0xc0000a0001c00300, 98); - xdump((long long *)0xc0000a0001c10000, 6); - xdump((long long *)0xc0000a0001c20000, 6); - xdump((long long *)0xc0000a0001c30000, 2); - - xdump((long long *)0xc0000a0000000000, 1); - xdump((long long *)0xc0000a0001000000, 1); - xdump((long long *)0xc0000a0002000000, 1); - xdump((long long *)0xc0000a0003000000, 1); - xdump((long long *)0xc0000a0004000000, 1); - xdump((long long *)0xc0000a0005000000, 1); - xdump((long long *)0xc0000a0006000000, 1); - xdump((long long *)0xc0000a0007000000, 1); - xdump((long long *)0xc0000a0008000000, 1); - xdump((long long *)0xc0000a0009000000, 1); - xdump((long long *)0xc0000a000a000000, 1); - xdump((long long *)0xc0000a000b000000, 1); - xdump((long long *)0xc0000a000c000000, 1); - xdump((long long *)0xc0000a000d000000, 1); - xdump((long long *)0xc0000a000e000000, 1); - xdump((long long *)0xc0000a000f000000, 1); -} - -static void -dump_crossbow(void) -{ - printk("===== Dump the Crossbow regs =====\n"); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000000004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000000000, 1); - printk("and again..\n"); - xdump32((unsigned int *)0xc0000a0000000000, 1); - xdump32((unsigned int *)0xc0000a0000000000, 1); - - - clear_ii_error(); - - xdump32((unsigned int *)0xc000020000000004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc000020000000000, 1); - clear_ii_error(); - - xdump32((unsigned int *)0xc0000a0000800004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc0000a0000800000, 1); - clear_ii_error(); - - xdump32((unsigned int *)0xc000020000800004, 1); - clear_ii_error(); - xdump32((unsigned int *)0xc000020000800000, 1); - clear_ii_error(); - - -} -#endif /* DEFINE_DUMP_RTNS */ diff -Nru a/arch/ia64/sn/io/l1.c b/arch/ia64/sn/io/l1.c --- a/arch/ia64/sn/io/l1.c Sun Mar 2 23:29:53 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,3056 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* In general, this file is organized in a hierarchy from lower-level - * to higher-level layers, as follows: - * - * UART routines - * Bedrock/L1 "PPP-like" protocol implementation - * System controller "message" interface (allows multiplexing - * of various kinds of requests and responses with - * console I/O) - * Console interface: - * "l1_cons", the glue that allows the L1 to act - * as the system console for the stdio libraries - * - * Routines making use of the system controller "message"-style interface - * can be found in l1_command.c. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Make all console writes atomic */ -#define SYNC_CONSOLE_WRITE 1 - - -/********************************************************************* - * Hardware-level (UART) driver routines. - */ - -/* macros for reading/writing registers */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -/* location of uart receive/xmit data register */ -#if defined(CONFIG_IA64_SGI_SN1) -#define L1_UART_BASE(n) ((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080)) -#define LOCK_HUB REMOTE_HUB_ADDR -#elif defined(CONFIG_IA64_SGI_SN2) -#define L1_UART_BASE(n) ((ulong)REMOTE_HUB((n), SH_JUNK_BUS_UART0)) -#define LOCK_HUB REMOTE_HUB -typedef u64 rtc_time_t; -#endif - - -#define ADDR_L1_REG(n, r) ( L1_UART_BASE(n) | ( (r) << 3 ) ) -#define READ_L1_UART_REG(n, r) ( LD(ADDR_L1_REG((n), (r))) ) -#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) ) - -/* upper layer interface calling methods */ -#define SERIAL_INTERRUPT_MODE 0 -#define SERIAL_POLLED_MODE 1 - - -/* UART-related #defines */ - -#define UART_BAUD_RATE 57600 -#define UART_FIFO_DEPTH 16 -#define UART_DELAY_SPAN 10 -#define UART_PUTC_TIMEOUT 50000 -#define UART_INIT_TIMEOUT 100000 - -/* error codes */ -#define UART_SUCCESS 0 -#define UART_TIMEOUT (-1) -#define UART_LINK (-2) -#define UART_NO_CHAR (-3) -#define UART_VECTOR (-4) - -#define UART_DELAY(x) udelay(x) - -/* Some debug counters */ -#define L1C_INTERRUPTS 0 -#define L1C_OUR_R_INTERRUPTS 1 -#define L1C_OUR_X_INTERRUPTS 2 -#define L1C_SEND_CALLUPS 3 -#define L1C_RECEIVE_CALLUPS 4 -#define L1C_SET_BAUD 5 -#define L1C_ALREADY_LOCKED L1C_SET_BAUD -#define L1C_R_IRQ 6 -#define L1C_R_IRQ_RET 7 -#define L1C_LOCK_TIMEOUTS 8 -#define L1C_LOCK_COUNTER 9 -#define L1C_UNLOCK_COUNTER 10 -#define L1C_REC_STALLS 11 -#define L1C_CONNECT_CALLS 12 -#define L1C_SIZE L1C_CONNECT_CALLS /* Set to the last one */ - -uint64_t L1_collectibles[L1C_SIZE + 1]; - - -/* - * Some macros for handling Endian-ness - */ - -#define COPY_INT_TO_BUFFER(_b, _i, _n) \ - { \ - _b[_i++] = (_n >> 24) & 0xff; \ - _b[_i++] = (_n >> 16) & 0xff; \ - _b[_i++] = (_n >> 8) & 0xff; \ - _b[_i++] = _n & 0xff; \ - } - -#define COPY_BUFFER_TO_INT(_b, _i, _n) \ - { \ - _n = (_b[_i++] << 24) & 0xff; \ - _n |= (_b[_i++] << 16) & 0xff; \ - _n |= (_b[_i++] << 8) & 0xff; \ - _n |= _b[_i++] & 0xff; \ - } - -#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn) \ - { \ - char *_xyz = (char *)_bn; \ - _xyz[3] = _b[_i++]; \ - _xyz[2] = _b[_i++]; \ - _xyz[1] = _b[_i++]; \ - _xyz[0] = _b[_i++]; \ - } - -void snia_kmem_free(void *where, int size); - -#define ALREADY_LOCKED 1 -#define NOT_LOCKED 0 -static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ ); - -#define BCOPY(x,y,z) memcpy(y,x,z) - -uint8_t L1_interrupts_connected; /* Non-zero when we are in interrupt mode */ - - -/* - * Console locking defines and functions. - * - */ - -uint8_t L1_cons_is_inited = 0; /* non-zero when console is init'd */ -nasid_t Master_console_nasid = (nasid_t)-1; -extern nasid_t console_nasid; - -u64 ia64_sn_get_console_nasid(void); - -inline nasid_t -get_master_nasid(void) -{ -#if defined(CONFIG_IA64_SGI_SN1) - nasid_t nasid = Master_console_nasid; - - if ( nasid == (nasid_t)-1 ) { - nasid = (nasid_t)ia64_sn_get_console_nasid(); - if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) { - /* Out of bounds, use local */ - console_nasid = nasid = get_nasid(); - } - else { - /* Got a valid nasid, set the console_nasid */ - char xx[100]; -/* zzzzzz - force nasid to 0 for now */ - sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid); -nasid = 0; -/* end zzzzzz */ - xx[99] = (char)0; - early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED); - Master_console_nasid = console_nasid = nasid; - } - } - return(nasid); -#else - return((nasid_t)0); -#endif /* CONFIG_IA64_SGI_SN1 */ -} - - -#if defined(CONFIG_IA64_SGI_SN1) - -#define HUB_LOCK 16 - -#define PRIMARY_LOCK_TIMEOUT 10000000 -#define HUB_LOCK_REG(n) LOCK_HUB(n, MD_PERF_CNT0) - -#define SET_BITS(reg, bits) SD(reg, LD(reg) | (bits)) -#define CLR_BITS(reg, bits) SD(reg, LD(reg) & ~(bits)) -#define TST_BITS(reg, bits) ((LD(reg) & (bits)) != 0) - -#define HUB_TEST_AND_SET(n) LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ)) -#define HUB_CLEAR(n) SD(LOCK_HUB(n,LB_SCRATCH_REG3),0) - -#define RTC_TIME_MAX ((rtc_time_t) ~0ULL) - -/* - * primary_lock - * - * Allows CPU's 0-3 to mutually exclude the hub from one another by - * obtaining a blocking lock. Does nothing if only one CPU is active. - * - * This lock should be held just long enough to set or clear a global - * lock bit. After a relatively short timeout period, this routine - * figures something is wrong, and steals the lock. It does not set - * any other CPU to "dead". - */ -inline void -primary_lock(nasid_t nasid) -{ - rtc_time_t expire; - - expire = rtc_time() + PRIMARY_LOCK_TIMEOUT; - - while (HUB_TEST_AND_SET(nasid)) { - if (rtc_time() > expire) { - HUB_CLEAR(nasid); - } - } -} - -/* - * primary_unlock (internal) - * - * Counterpart to primary_lock - */ - -inline void -primary_unlock(nasid_t nasid) -{ - HUB_CLEAR(nasid); -} - -/* - * hub_unlock - * - * Counterpart to hub_lock_timeout and hub_lock - */ - -inline void -hub_unlock(nasid_t nasid, int level) -{ - uint64_t mask = 1ULL << level; - - primary_lock(nasid); - CLR_BITS(HUB_LOCK_REG(nasid), mask); - primary_unlock(nasid); -} - -/* - * hub_lock_timeout - * - * Uses primary_lock to implement multiple lock levels. - * - * There are 20 lock levels from 0 to 19 (limited by the number of bits - * in HUB_LOCK_REG). To prevent deadlock, multiple locks should be - * obtained in order of increasingly higher level, and released in the - * reverse order. - * - * A timeout value of 0 may be used for no timeout. - * - * Returns 0 if successful, -1 if lock times out. - */ - -inline int -hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout) -{ - uint64_t mask = 1ULL << level; - rtc_time_t expire = (timeout ? rtc_time() + timeout : RTC_TIME_MAX); - int done = 0; - - while (! done) { - while (TST_BITS(HUB_LOCK_REG(nasid), mask)) { - if (rtc_time() > expire) - return -1; - } - - primary_lock(nasid); - - if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) { - SET_BITS(HUB_LOCK_REG(nasid), mask); - done = 1; - } - primary_unlock(nasid); - } - return 0; -} - - -#define LOCK_TIMEOUT (0x1500000 * 1) /* 0x1500000 is ~30 sec */ - -void -lock_console(nasid_t nasid) -{ - int ret; - - /* If we already have it locked, just return */ - L1_collectibles[L1C_LOCK_COUNTER]++; - - ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - if ( ret != 0 ) { - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - /* timeout */ - hub_unlock(nasid, HUB_LOCK); - /* If the 2nd lock fails, just pile ahead.... */ - hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT); - L1_collectibles[L1C_LOCK_TIMEOUTS]++; - } -} - -inline void -unlock_console(nasid_t nasid) -{ - L1_collectibles[L1C_UNLOCK_COUNTER]++; - hub_unlock(nasid, HUB_LOCK); -} - -#else /* SN2 */ -inline void lock_console(nasid_t n) {} -inline void unlock_console(nasid_t n) {} - -#endif /* CONFIG_IA64_SGI_SN1 */ - -int -get_L1_baud(void) -{ - return UART_BAUD_RATE; -} - - -/* uart driver functions */ - -static inline void -uart_delay( rtc_time_t delay_span ) -{ - UART_DELAY( delay_span ); -} - -#define UART_PUTC_READY(n) (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE) - -static int -uart_putc( l1sc_t *sc ) -{ - WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] ); - return UART_SUCCESS; -} - - -static int -uart_getc( l1sc_t *sc ) -{ - u_char lsr_reg = 0; - nasid_t nasid = sc->nasid; - - if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & - (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( lsr_reg & LSR_RCA ) - return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) ); - else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -#define PROM_SER_CLK_SPEED 12000000 -#define PROM_SER_DIVISOR(x) (PROM_SER_CLK_SPEED / ((x) * 16)) - -static void -uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + UART_INIT_TIMEOUT; - nasid = sc->nasid; - - /* make sure the transmit FIFO is empty */ - while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) { - uart_delay( UART_DELAY_SPAN ); - if( rtc_time() > expire ) { - break; - } - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* Setup for the proper baud rate */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - - /* 8bit, one stop, clear request to send, auto flow control */ - WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs, trigger on 1 */ - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -uart_intr_enable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg |= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} - -/* This requires the console lock */ -static void -uart_intr_disable( l1sc_t *sc, u_char mask ) -{ - u_char lcr_reg, icr_reg; - nasid_t nasid = sc->nasid; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(nasid); - - /* make sure that the DLAB bit in the LCR register is 0 - */ - lcr_reg = READ_L1_UART_REG( nasid, REG_LCR ); - lcr_reg &= ~(LCR_DLAB); - WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg ); - - /* enable indicated interrupts - */ - icr_reg = READ_L1_UART_REG( nasid, REG_ICR ); - icr_reg &= mask; - WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ ); - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(nasid); -} -#endif /* CONFIG_IA64_SGI_SN1 */ - -#define uart_enable_xmit_intr(sc) \ - uart_intr_enable((sc), ICR_TIEN) - -#define uart_disable_xmit_intr(sc) \ - uart_intr_disable((sc), ~(ICR_TIEN)) - -#define uart_enable_recv_intr(sc) \ - uart_intr_enable((sc), ICR_RIEN) - -#define uart_disable_recv_intr(sc) \ - uart_intr_disable((sc), ~(ICR_RIEN)) - - -/********************************************************************* - * Routines for accessing a remote (router) UART - */ - -#define READ_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_read_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define WRITE_RTR_L1_UART_REG(p, n, r, v) \ - { \ - if( vector_write_node( (p), (n), 0, \ - RR_JBUS1(r), (v) ) ) { \ - return UART_VECTOR; \ - } \ - } - -#define RTR_UART_PUTC_TIMEOUT UART_PUTC_TIMEOUT*10 -#define RTR_UART_DELAY_SPAN UART_DELAY_SPAN -#define RTR_UART_INIT_TIMEOUT UART_INIT_TIMEOUT*10 - -static int -rtr_uart_putc( l1sc_t *sc ) -{ - uint64_t regval, c; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT; - - c = (sc->send[sc->sent] & 0xffULL); - - while( 1 ) - { - /* Check for "tx hold reg empty" bit. */ - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XHRE ) - { - WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c ); - return UART_SUCCESS; - } - - if( rtc_time() >= expire ) - { - return UART_TIMEOUT; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } -} - - -static int -rtr_uart_getc( l1sc_t *sc ) -{ - uint64_t regval; - nasid_t nasid = sc->nasid; - net_vec_t path = sc->uart; - - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) ) - { - if( regval & LSR_RCA ) - { - READ_RTR_L1_UART_REG( path, nasid, REG_DAT, ®val ); - return( (int)regval ); - } - else - { - return UART_LINK; - } - } - - return UART_NO_CHAR; -} - - -static int -rtr_uart_init( l1sc_t *sc, int baud ) -{ - rtc_time_t expire; - int clkdiv; - nasid_t nasid; - net_vec_t path; - uint64_t regval; - - clkdiv = PROM_SER_DIVISOR(baud); - expire = rtc_time() + RTR_UART_INIT_TIMEOUT; - nasid = sc->nasid; - path = sc->uart; - - /* make sure the transmit FIFO is empty */ - while(1) { - READ_RTR_L1_UART_REG( path, nasid, REG_LSR, ®val ); - if( regval & LSR_XSRE ) { - break; - } - if( rtc_time() > expire ) { - break; - } - uart_delay( RTR_UART_DELAY_SPAN ); - } - - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff ); - uart_delay( UART_DELAY_SPAN ); - - /* set operating parameters and set DLAB to 0 */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE ); - uart_delay( UART_DELAY_SPAN ); - - /* disable interrupts */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0 ); - uart_delay( UART_DELAY_SPAN ); - - /* enable FIFO mode and reset both FIFOs */ - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN ); - uart_delay( UART_DELAY_SPAN ); - WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, - FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO ); - - return 0; -} - -/********************************************************************* - * locking macros - */ - -#define L1SC_SEND_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); } -#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); } -#define L1SC_RECV_LOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } -#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); } - - -/********************************************************************* - * subchannel manipulation - * - * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel - * allocation. SUBCH_DATA_[UN]LOCK control access to data structures - * associated with particular subchannels (e.g., receive queues). - * - */ -#define SUBCH_LOCK(sc, p) spin_lock_irqsave( &((sc)->subch_lock), p ) -#define SUBCH_UNLOCK(sc, p) spin_unlock_irqrestore( &((sc)->subch_lock), p ) -#define SUBCH_DATA_LOCK(sbch, p) spin_lock_irqsave( &((sbch)->data_lock), p ) -#define SUBCH_DATA_UNLOCK(sbch, p) spin_unlock_irqrestore( &((sbch)->data_lock), p ) - - -/* - * set a function to be called for subchannel ch in the event of - * a transmission low-water interrupt from the uart - */ -void -subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - - L1SC_SEND_LOCK( sc, pl ); -#if !defined(SYNC_CONSOLE_WRITE) - if ( func && !sc->send_in_use ) - uart_enable_xmit_intr( sc ); -#endif - sc->subch[ch].tx_notify = func; - L1SC_SEND_UNLOCK(sc, pl ); -} - -/* - * set a function to be called for subchannel ch when data is received - */ -void -subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - SUBCH_DATA_LOCK( subch, pl ); - sc->subch[ch].rx_notify = func; - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/********************************************************************* - * Queue manipulation macros - * - * - */ -#define NEXT(p) (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */ - -#define cq_init(q) bzero((q), sizeof (*(q))) -#define cq_empty(q) ((q)->ipos == (q)->opos) -#define cq_full(q) (NEXT((q)->ipos) == (q)->opos) -#define cq_used(q) ((q)->opos <= (q)->ipos ? \ - (q)->ipos - (q)->opos : \ - BRL1_QSIZE + (q)->ipos - (q)->opos) -#define cq_room(q) ((q)->opos <= (q)->ipos ? \ - BRL1_QSIZE - 1 + (q)->opos - (q)->ipos : \ - (q)->opos - (q)->ipos - 1) -#define cq_add(q, c) ((q)->buf[(q)->ipos] = (u_char) (c), \ - (q)->ipos = NEXT((q)->ipos)) -#define cq_rem(q, c) ((c) = (q)->buf[(q)->opos], \ - (q)->opos = NEXT((q)->opos)) -#define cq_discard(q) ((q)->opos = NEXT((q)->opos)) - -#define cq_tent_full(q) (NEXT((q)->tent_next) == (q)->opos) -#define cq_tent_len(q) ((q)->ipos <= (q)->tent_next ? \ - (q)->tent_next - (q)->ipos : \ - BRL1_QSIZE + (q)->tent_next - (q)->ipos) -#define cq_tent_add(q, c) \ - ((q)->buf[(q)->tent_next] = (u_char) (c), \ - (q)->tent_next = NEXT((q)->tent_next)) -#define cq_commit_tent(q) \ - ((q)->ipos = (q)->tent_next) -#define cq_discard_tent(q) \ - ((q)->tent_next = (q)->ipos) - - - - -/********************************************************************* - * CRC-16 (for checking bedrock/L1 packets). - * - * These are based on RFC 1662 ("PPP in HDLC-like framing"). - */ - -static unsigned short fcstab[256] = { - 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, - 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, - 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, - 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, - 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, - 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, - 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, - 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, - 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, - 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, - 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, - 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, - 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, - 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, - 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, - 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, - 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, - 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, - 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, - 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, - 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, - 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, - 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, - 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, - 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, - 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, - 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, - 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, - 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, - 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, - 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, - 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 -}; - -#define INIT_CRC 0xFFFF /* initial CRC value */ -#define GOOD_CRC 0xF0B8 /* "good" final CRC value */ - -static unsigned short crc16_calc( unsigned short crc, u_char c ) -{ - return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] ); -} - - -/*********************************************************************** - * The following functions implement the PPP-like bedrock/L1 protocol - * layer. - * - */ - -#define BRL1_FLAG_CH 0x7e -#define BRL1_ESC_CH 0x7d -#define BRL1_XOR_CH 0x20 - -/* L1<->Bedrock packet types */ -#define BRL1_REQUEST 0x00 -#define BRL1_RESPONSE 0x20 -#define BRL1_EVENT 0x40 - -#define BRL1_PKT_TYPE_MASK 0xE0 -#define BRL1_SUBCH_MASK 0x1F - -#define PKT_TYPE(tsb) ((tsb) & BRL1_PKT_TYPE_MASK) -#define SUBCH(tsb) ((tsb) & BRL1_SUBCH_MASK) - -/* timeouts */ -#define BRL1_INIT_TIMEOUT 500000 - -/* - * brl1_discard_packet is a dummy "receive callback" used to get rid - * of packets we don't want - */ -void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch = &sc->subch[ch]; - - sc_cq_t *q = subch->iqp; - SUBCH_DATA_LOCK( subch, pl ); - q->opos = q->ipos; - atomic_set(&(subch->packet_arrived), 0); - SUBCH_DATA_UNLOCK( subch, pl ); -} - - -/* - * brl1_send_chars sends the send buffer in the l1sc_t structure - * out through the uart. Assumes that the caller has locked the - * UART (or send buffer in the kernel). - * - * This routine doesn't block-- if you want it to, call it in - * a loop. - */ -static int -brl1_send_chars( l1sc_t *sc ) -{ - /* We track the depth of the C brick's UART's - * fifo in software, and only check if the UART is accepting - * characters when our count indicates that the fifo should - * be full. - * - * For remote (router) UARTs, we check with the UART before sending every - * character. - */ - if( sc->uart == BRL1_LOCALHUB_UART ) { - if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) ) - sc->fifo_space = UART_FIFO_DEPTH; - - while( (sc->sent < sc->send_len) && (sc->fifo_space) ) { - uart_putc( sc ); - sc->fifo_space--; - sc->sent++; - } - } - else { - - /* remote (router) UARTs */ - - int result; - int tries = 0; - - while( sc->sent < sc->send_len ) { - result = sc->putc_f( sc ); - if( result >= 0 ) { - (sc->sent)++; - continue; - } - if( result == UART_TIMEOUT ) { - tries++; - /* send this character in TIMEOUT_RETRIES... */ - if( tries < 30 /* TIMEOUT_RETRIES */ ) { - continue; - } - /* ...or else... */ - else { - /* ...drop the packet. */ - sc->sent = sc->send_len; - return sc->send_len; - } - } - if( result < 0 ) { - return result; - } - } - } - return sc->sent; -} - - -/* brl1_send formats up a packet and (at least begins to) send it - * to the uart. If the send buffer is in use when this routine obtains - * the lock, it will behave differently depending on the "wait" parameter. - * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"), - * hopefully encouraging the caller to back off (unlock any high-level - * spinlocks) and allow the buffer some time to drain. For wait==1 (high- - * priority I/O along the lines of kernel error messages), we will flush - * the current contents of the send buffer and beat on the uart - * until our message has been completely transmitted. - */ - -static int -brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait ) -{ - unsigned long pl = 0; - int index; - int pkt_len = 0; - unsigned short crc = INIT_CRC; - char *send_ptr = sc->send; - - - if( sc->send_in_use && !(wait) ) { - /* We are in the middle of sending, but can wait until done */ - return 0; - } - else if( sc->send_in_use ) { - /* buffer's in use, but we're synchronous I/O, so we're going - * to send whatever's in there right now and take the buffer - */ - int counter = 0; - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - while( sc->sent < sc->send_len ) { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (1)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } - } - else { - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - sc->send_in_use = 1; - } - *send_ptr++ = BRL1_FLAG_CH; - *send_ptr++ = type_and_subch; - pkt_len += 2; - crc = crc16_calc( crc, type_and_subch ); - - /* limit number of characters accepted to max payload size */ - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - /* copy in the message buffer (inserting PPP - * framing info where necessary) - */ - for( index = 0; index < len; index++ ) { - - switch( *msg ) { - - case BRL1_FLAG_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - case BRL1_ESC_CH: - *send_ptr++ = BRL1_ESC_CH; - *send_ptr++ = (*msg) ^ BRL1_XOR_CH; - pkt_len += 2; - break; - - default: - *send_ptr++ = *msg; - pkt_len++; - } - crc = crc16_calc( crc, *msg ); - msg++; - } - crc ^= 0xffff; - - for( index = 0; index < sizeof(crc); index++ ) { - char crc_char = (char)(crc & 0x00FF); - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - *send_ptr++ = BRL1_ESC_CH; - pkt_len++; - crc_char ^= BRL1_XOR_CH; - } - *send_ptr++ = crc_char; - pkt_len++; - crc >>= 8; - } - - *send_ptr++ = BRL1_FLAG_CH; - pkt_len++; - - sc->send_len = pkt_len; - sc->sent = 0; - - { - int counter = 0; - do { - brl1_send_chars( sc ); - if ( counter++ > 0xfffff ) { - char *str = "Looping waiting for uart to clear (2)\n"; - early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED); - break; - } - } while( (sc->sent < sc->send_len) && wait ); - } - - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - - if( sc->sent == sc->send_len ) { - /* success! release the send buffer and call the callup */ -#if !defined(SYNC_CONSOLE_WRITE) - brl1_notif_t callup; -#endif - - sc->send_in_use = 0; - /* call any upper layer that's asked for notification */ -#if defined(XX_SYNC_CONSOLE_WRITE) - /* - * This is probably not a good idea - since the l1_ write func can be called multiple - * time within the callup function. - */ - callup = subch->tx_notify; - if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) { - L1_collectibles[L1C_SEND_CALLUPS]++; - (*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id, - sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch)); - } -#endif /* SYNC_CONSOLE_WRITE */ - } -#if !defined(SYNC_CONSOLE_WRITE) - else if ( !wait ) { - /* enable low-water interrupts so buffer will be drained */ - uart_enable_xmit_intr(sc); - } -#endif - - L1SC_SEND_UNLOCK(sc, pl); - - return len; -} - -/* brl1_send_cont is intended to be called as an interrupt service - * routine. It sends until the UART won't accept any more characters, - * or until an error is encountered (in which case we surrender the - * send buffer and give up trying to send the packet). Once the - * last character in the packet has been sent, this routine releases - * the send buffer and calls any previously-registered "low-water" - * output routines. - */ - -#if !defined(SYNC_CONSOLE_WRITE) - -int -brl1_send_cont( l1sc_t *sc ) -{ - unsigned long pl = 0; - int done = 0; - brl1_notif_t callups[BRL1_NUM_SUBCHANS]; - brl1_notif_t *callup; - brl1_sch_t *subch; - int index; - - /* - * I'm not sure how I think this is to be handled - whether the lock is held - * over the interrupt - but it seems like it is a bad idea.... - */ - - if ( sc->uart == BRL1_LOCALHUB_UART ) - lock_console(sc->nasid); - L1SC_SEND_LOCK(sc, pl); - brl1_send_chars( sc ); - done = (sc->sent == sc->send_len); - if( done ) { - sc->send_in_use = 0; -#if !defined(SYNC_CONSOLE_WRITE) - uart_disable_xmit_intr(sc); -#endif - } - if ( sc->uart == BRL1_LOCALHUB_UART ) - unlock_console(sc->nasid); - /* Release the lock */ - L1SC_SEND_UNLOCK(sc, pl); - - return 0; -} -#endif /* SYNC_CONSOLE_WRITE */ - -/* internal function -- used by brl1_receive to read a character - * from the uart and check whether errors occurred in the process. - */ -static int -read_uart( l1sc_t *sc, int *c, int *result ) -{ - *c = sc->getc_f( sc ); - - /* no character is available */ - if( *c == UART_NO_CHAR ) { - *result = BRL1_NO_MESSAGE; - return 0; - } - - /* some error in UART */ - if( *c < 0 ) { - *result = BRL1_LINK; - return 0; - } - - /* everything's fine */ - *result = BRL1_VALID; - return 1; -} - - -/* - * brl1_receive - * - * This function reads a Bedrock-L1 protocol packet into the l1sc_t - * response buffer. - * - * The operation of this function can be expressed as a finite state - * machine: - * - -START STATE INPUT TRANSITION -========================================================== -BRL1_IDLE (reset or error) flag BRL1_FLAG - other BRL1_IDLE@ - -BRL1_FLAG (saw a flag (0x7e)) flag BRL1_FLAG - escape BRL1_IDLE@ - header byte BRL1_HDR - other BRL1_IDLE@ - -BRL1_HDR (saw a type/subch byte)(see below) BRL1_BODY - BRL1_HDR - -BRL1_BODY (reading packet body) flag BRL1_FLAG - escape BRL1_ESC - other BRL1_BODY - -BRL1_ESC (saw an escape (0x7d)) flag BRL1_FLAG@ - escape BRL1_IDLE@ - other BRL1_BODY -========================================================== - -"@" denotes an error transition. - - * The BRL1_HDR state is a transient state which doesn't read input, - * but just provides a way in to code which decides to whom an - * incoming packet should be directed. - * - * brl1_receive can be used to poll for input from the L1, or as - * an interrupt service routine. It reads as much data as is - * ready from the junk bus UART and places into the appropriate - * input queues according to subchannel. The header byte is - * stripped from console-type data, but is retained for message- - * type data (L1 responses). A length byte will also be - * prepended to message-type packets. - * - * This routine is non-blocking; if the caller needs to block - * for input, it must call brl1_receive in a loop. - * - * brl1_receive returns when there is no more input, the queue - * for the current incoming message is full, or there is an - * error (parity error, bad header, bad CRC, etc.). - */ - -#define STATE_SET(l,s) ((l)->brl1_state = (s)) -#define STATE_GET(l) ((l)->brl1_state) - -#define LAST_HDR_SET(l,h) ((l)->brl1_last_hdr = (h)) -#define LAST_HDR_GET(l) ((l)->brl1_last_hdr) - -#define VALID_HDR(c) \ - ( SUBCH((c)) <= SC_CONS_SYSTEM \ - ? PKT_TYPE((c)) == BRL1_REQUEST \ - : ( PKT_TYPE((c)) == BRL1_RESPONSE || \ - PKT_TYPE((c)) == BRL1_EVENT ) ) - -#define IS_TTY_PKT(l) ( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 ) - - -int -brl1_receive( l1sc_t *sc, int mode ) -{ - int result; /* value to be returned by brl1_receive */ - int c; /* most-recently-read character */ - int done; /* set done to break out of recv loop */ - unsigned long pl = 0, cpl = 0; - sc_cq_t *q; /* pointer to queue we're working with */ - - result = BRL1_NO_MESSAGE; - - L1SC_RECV_LOCK(sc, cpl); - - done = 0; - while( !done ) - { - switch( STATE_GET(sc) ) - { - - case BRL1_IDLE: - /* Initial or error state. Waiting for a flag character - * to resynchronize with the L1. - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* saw a flag character */ - STATE_SET( sc, BRL1_FLAG ); - continue; - } - break; - - case BRL1_FLAG: - /* One or more flag characters have been read; look for - * the beginning of a packet (header byte). - */ - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* multiple flags are OK */ - continue; - } - - if( !VALID_HDR( c ) ) { - /* if c isn't a flag it should have been - * a valid header, so we have an error - */ - result = BRL1_PROTOCOL; - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - /* we have a valid header byte */ - LAST_HDR_SET( sc, c ); - STATE_SET( sc, BRL1_HDR ); - - break; - - case BRL1_HDR: - /* A header byte has been read. Do some bookkeeping. */ - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - if( !IS_TTY_PKT(sc) ) { - /* if this is an event or command response rather - * than console I/O, we need to reserve a couple - * of extra spaces in the queue for the header - * byte and a length byte; if we can't, stay in - * the BRL1_HDR state. - */ - if( cq_room( q ) < 2 ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - cq_tent_add( q, 0 ); /* reserve length byte */ - cq_tent_add( q, LAST_HDR_GET( sc ) ); /* record header byte */ - } - STATE_SET( sc, BRL1_BODY ); - - break; - - case BRL1_BODY: - /* A header byte has been read. We are now attempting - * to receive the packet body. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) - STATE_SET( sc, BRL1_IDLE ); - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* prepare to unescape the next character */ - STATE_SET( sc, BRL1_ESC ); - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag signifies the end of a packet */ - - unsigned short crc; /* holds the crc as we calculate it */ - int i; /* index variable */ - brl1_sch_t *subch; /* subchannel for received packet */ - brl1_notif_t callup; /* "data ready" callup */ - - /* whatever else may happen, we've seen a flag and we're - * starting a new packet - */ - STATE_SET( sc, BRL1_FLAG ); - - /* if the packet body has less than 2 characters, - * it can't be a well-formed packet. Discard it. - */ - if( cq_tent_len( q ) < /* 2 + possible length byte */ - (2 + (IS_TTY_PKT(sc) ? 0 : 1)) ) - { - result = BRL1_PROTOCOL; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* check CRC */ - - /* accumulate CRC, starting with the header byte and - * ending with the transmitted CRC. This should - * result in a known good value. - */ - crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) ); - for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE; - i != q->tent_next; - i = (i + 1) % BRL1_QSIZE ) - { - crc = crc16_calc( crc, q->buf[i] ); - } - - /* verify the caclulated crc against the "good" crc value; - * if we fail, discard the bad packet and return an error. - */ - if( crc != (unsigned short)GOOD_CRC ) { - result = BRL1_CRC; - cq_discard_tent( q ); - STATE_SET( sc, BRL1_FLAG ); - done = 1; - continue; - } - - /* so the crc check was ok. Now we discard the CRC - * from the end of the received bytes. - */ - q->tent_next += (BRL1_QSIZE - 2); - q->tent_next %= BRL1_QSIZE; - - /* get the subchannel and lock it */ - subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]); - SUBCH_DATA_LOCK( subch, pl ); - - /* if this isn't a console packet, we need to record - * a length byte - */ - if( !IS_TTY_PKT(sc) ) { - q->buf[q->ipos] = cq_tent_len( q ) - 1; - } - - /* record packet for posterity */ - cq_commit_tent( q ); - result = BRL1_VALID; - - /* notify subchannel owner that there's something - * on the queue for them - */ - atomic_inc(&(subch->packet_arrived)); - callup = subch->rx_notify; - SUBCH_DATA_UNLOCK( subch, pl ); - - if( callup && (mode == SERIAL_INTERRUPT_MODE) ) { - L1SC_RECV_UNLOCK( sc, cpl ); - L1_collectibles[L1C_RECEIVE_CALLUPS]++; - (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id, - sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs, - sc, SUBCH(LAST_HDR_GET(sc)) ); - L1SC_RECV_LOCK( sc, cpl ); - } - continue; /* go back for more! */ - } - - /* none of the special cases applied; we've got a normal - * body character - */ - cq_tent_add( q, c ); - - break; - - case BRL1_ESC: - /* saw an escape character. The next character will need - * to be unescaped. - */ - - q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp; - ASSERT(q); - - /* if the queue we want to write into is full, don't read from - * the uart (this provides backpressure to the L1 side) - */ - if( cq_tent_full( q ) ) { - result = BRL1_FULL_Q; - done = 1; - continue; - } - - if( !read_uart( sc, &c, &result ) ) { - - /* error reading uart */ - if( c != UART_NO_CHAR ) { - cq_discard_tent( q ); - STATE_SET( sc, BRL1_IDLE ); - } - done = 1; - continue; - } - - if( c == BRL1_FLAG_CH ) { - /* flag after escape is an error */ - STATE_SET( sc, BRL1_FLAG ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - if( c == BRL1_ESC_CH ) { - /* two consecutive escapes is an error */ - STATE_SET( sc, BRL1_IDLE ); - cq_discard_tent( q ); - result = BRL1_PROTOCOL; - done = 1; - continue; - } - - /* otherwise, we've got a character that needs - * to be unescaped - */ - cq_tent_add( q, (c ^ BRL1_XOR_CH) ); - STATE_SET( sc, BRL1_BODY ); - - break; - - } /* end of switch( STATE_GET(sc) ) */ - } /* end of while(!done) */ - - L1SC_RECV_UNLOCK( sc, cpl ); - - return result; -} - - -/* brl1_init initializes the Bedrock/L1 protocol layer. This includes - * zeroing out the send and receive state information. - */ - -void -brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - /* (for now, drop elscuart packets in the kernel) */ - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ ); - subch->tx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - subch->rx_notify = NULL; - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - subch->rx_notify = brl1_discard_packet; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - subch->iqp = &sc->garbage_q; - } - - /* initialize synchronization structures - */ - spin_lock_init( &(sc->subch_lock) ); - spin_lock_init( &(sc->send_lock) ); - spin_lock_init( &(sc->recv_lock) ); - - if( sc->uart == BRL1_LOCALHUB_UART ) { - uart_init( sc, UART_BAUD_RATE ); - } - else { - rtr_uart_init( sc, UART_BAUD_RATE ); - } - - /* Set up remaining fields using L1 command functions-- elsc_module_get - * to read the module id, elsc_debug_get to see whether or not we're - * in verbose mode. - */ - { - extern int elsc_module_get(l1sc_t *); - - sc->modid = elsc_module_get( sc ); - sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid); - sc->verbose = 1; - } -} - -/********************************************************************* - * These are interrupt-related functions used in the kernel to service - * the L1. - */ - -/* - * brl1_intrd is the function which is called on a console interrupt. - */ - -#if defined(CONFIG_IA64_SGI_SN1) - -static void -brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff) -{ - u_char isr_reg; - l1sc_t *sc = get_elsc(); - int ret; - - L1_collectibles[L1C_INTERRUPTS]++; - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - - /* Save for callup args in console */ - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id; - sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff; - -#if defined(SYNC_CONSOLE_WRITE) - while( isr_reg & ISR_RxRDY ) -#else - while( isr_reg & (ISR_RxRDY | ISR_TxRDY) ) -#endif - { - if( isr_reg & ISR_RxRDY ) { - L1_collectibles[L1C_OUR_R_INTERRUPTS]++; - ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - } -#if !defined(SYNC_CONSOLE_WRITE) - if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) { - L1_collectibles[L1C_OUR_X_INTERRUPTS]++; - brl1_send_cont(sc); - } -#endif /* SYNC_CONSOLE_WRITE */ - isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); - } -} -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when the send buffer - * has been emptied. - */ -static inline void -l1_tx_notif( brl1_notif_t func ) -{ - subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* - * Install a callback function for the system console subchannel - * to allow an upper layer to be notified when a packet has been - * received. - */ -static inline void -l1_rx_notif( brl1_notif_t func ) -{ - subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc, - SC_CONS_SYSTEM, func ); -} - - -/* brl1_intr is called directly from the uart interrupt; after it runs, the - * interrupt "daemon" xthread is signalled to continue. - */ -void -brl1_intr( void ) -{ -} - -#define BRL1_INTERRUPT_LEVEL 65 /* linux request_irq() value */ - -/* Return the current interrupt level */ - -//#define CONSOLE_POLLING_ALSO - -int -l1_get_intr_value( void ) -{ -#ifdef CONSOLE_POLLING_ALSO - return(0); -#else - return(BRL1_INTERRUPT_LEVEL); -#endif -} - -/* Disconnect the callup functions - throw away interrupts */ - -void -l1_unconnect_intr(void) -{ - /* UnRegister the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)NULL); - l1_tx_notif((brl1_notif_t)NULL); - /* We do NOT unregister the interrupts */ -} - -/* Set up uart interrupt handling for this node's uart */ - -void -l1_connect_intr(void *rx_notify, void *tx_notify) -{ - l1sc_t *sc; - nasid_t nasid; -#if defined(CONFIG_IA64_SGI_SN1) - int tmp; -#endif - nodepda_t *console_nodepda; - int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); - - if ( L1_interrupts_connected ) { - /* Interrupts are connected, so just register the callups */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - L1_collectibles[L1C_CONNECT_CALLS]++; - return; - } - else - L1_interrupts_connected = 1; - - nasid = get_master_nasid(); - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid)); - sc = &console_nodepda->module->elsc; - sc->intr_cpu = console_nodepda->node_first_cpu; - -#if defined(CONFIG_IA64_SGI_SN1) - if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - void synergy_intr_connect(int, int); - - synergy_intr_connect(UART_INTR, sc->intr_cpu); - L1_collectibles[L1C_R_IRQ]++; - tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc); - L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp; - if ( tmp ) { - L1_interrupts_connected = 0; /* FAILS !! */ - } - else { - /* Register the upper-level callup functions */ - l1_rx_notif((brl1_notif_t)rx_notify); - l1_tx_notif((brl1_notif_t)tx_notify); - - /* Set the uarts the way we like it */ - uart_enable_recv_intr( sc ); - uart_disable_xmit_intr( sc ); - } - } -#endif /* CONFIG_IA64_SGI_SN1 */ -} - - -/* Set the line speed */ - -void -l1_set_baud(int baud) -{ -#if 0 - nasid_t nasid; - static void uart_init(l1sc_t *, int); -#endif - - L1_collectibles[L1C_SET_BAUD]++; - -#if 0 - if ( L1_cons_is_inited ) { - nasid = get_master_nasid(); - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) - uart_init(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, baud); - } -#endif - return; -} - - -/* These are functions to use from serial_in/out when in protocol - * mode to send and receive uart control regs. These are external - * interfaces into the protocol driver. - */ - -void -l1_control_out(int offset, int value) -{ - nasid_t nasid = get_master_nasid(); - WRITE_L1_UART_REG(nasid, offset, value); -} - -/* Console input exported interface. Return a register value. */ - -int -l1_control_in_polled(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_POLLED_MODE)); -} - -int -l1_control_in(int offset) -{ - static int l1_control_in_local(int, int); - - return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE)); -} - -static int -l1_control_in_local(int offset, int mode) -{ - nasid_t nasid; - int ret, input; - static int l1_poll(l1sc_t *, int); - - nasid = get_master_nasid(); - ret = READ_L1_UART_REG(nasid, offset); - - if ( offset == REG_LSR ) { - ret |= (LSR_XHRE | LSR_XSRE); /* can send anytime */ - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode); - if ( input ) { - ret |= LSR_RCA; - } - } - } - } - return(ret); -} - -/* - * Console input exported interface. Return a character (if one is available) - */ - -int -l1_serial_in_polled(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_POLLED_MODE)); -} - -int -l1_serial_in(void) -{ - static int l1_serial_in_local(int mode); - - return(l1_serial_in_local(SERIAL_INTERRUPT_MODE)); -} - -static int -l1_serial_in_local(int mode) -{ - nasid_t nasid; - l1sc_t *sc; - int value; - static int l1_getc( l1sc_t *, int ); - static inline l1sc_t *early_sc_init(nasid_t); - - nasid = get_master_nasid(); - sc = early_sc_init(nasid); - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) { - sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc; - } - } - value = l1_getc(sc, mode); - return(value); -} - -/* Console output exported interface. Write message to the console. */ - -int -l1_serial_out( char *str, int len ) -{ - nasid_t nasid = get_master_nasid(); - int l1_write(l1sc_t *, char *, int, int); - - if ( L1_cons_is_inited ) { - if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) - return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len, -#if defined(SYNC_CONSOLE_WRITE) - 1 -#else - !L1_interrupts_connected -#endif - )); - } - return(early_l1_serial_out(nasid, str, len, NOT_LOCKED)); -} - - -/* - * These are the 'early' functions - when we need to do things before we have - * all the structs setup. - */ - -static l1sc_t Early_console; /* fake l1sc_t */ -static int Early_console_inited = 0; - -static void -early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - int i; - brl1_sch_t *subch; - - bzero( sc, sizeof( *sc ) ); - sc->nasid = nasid; - sc->uart = uart; - sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc); - sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc); - sc->sol = 1; - subch = sc->subch; - - /* initialize L1 subchannels - */ - - /* assign processor TTY channels */ - for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) { - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* assign system TTY channel (first free subchannel after each - * processor's individual TTY channel has been assigned) - */ - subch->use = BRL1_SUBCH_RSVD; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - if( sc->uart == BRL1_LOCALHUB_UART ) { - static sc_cq_t x_iqp; - - subch->iqp = &x_iqp; - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - } - else { - /* we shouldn't be getting console input from remote UARTs */ - subch->iqp = &sc->garbage_q; - } - subch++; i++; - - /* "reserved" subchannels (0x05-0x0F); for now, throw away - * incoming packets - */ - for( ; i < 0x10; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } - - /* remaining subchannels are free */ - for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) { - subch->use = BRL1_SUBCH_FREE; - subch->packet_arrived = ATOMIC_INIT(0); - subch->tx_notify = NULL; - subch->rx_notify = NULL; - subch->iqp = &sc->garbage_q; - } -} - -static inline l1sc_t * -early_sc_init(nasid_t nasid) -{ - /* This is for early I/O */ - if ( Early_console_inited == 0 ) { - early_brl1_init(&Early_console, nasid, BRL1_LOCALHUB_UART); - Early_console_inited = 1; - } - return(&Early_console); -} - -#define PUTCHAR(ch) \ - { \ - while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \ - (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \ - WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \ - } - -static int -early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state ) -{ - int ret, sent = 0; - char *msg = str; - static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state ); - - while ( sent < len ) { - ret = early_l1_send(nasid, msg, len - sent, lock_state); - sent += ret; - msg += ret; - } - return(len); -} - -static inline int -early_l1_send( nasid_t nasid, char *str, int len, int lock_state ) -{ - int sent; - char crc_char; - unsigned short crc = INIT_CRC; - - if( len > (BRL1_QSIZE - 1) ) - len = (BRL1_QSIZE - 1); - - sent = len; - if ( lock_state == NOT_LOCKED ) - lock_console(nasid); - - PUTCHAR( BRL1_FLAG_CH ); - PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM ); - crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) ); - - while( len ) { - - if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) { - PUTCHAR( BRL1_ESC_CH ); - PUTCHAR( (*str) ^ BRL1_XOR_CH ); - } - else { - PUTCHAR( *str ); - } - - crc = crc16_calc( crc, *str ); - - str++; len--; - } - - crc ^= 0xffff; - crc_char = crc & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - crc_char = (crc >> 8) & 0xff; - if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) { - crc_char ^= BRL1_XOR_CH; - PUTCHAR( BRL1_ESC_CH ); - } - PUTCHAR( crc_char ); - PUTCHAR( BRL1_FLAG_CH ); - - if ( lock_state == NOT_LOCKED ) - unlock_console(nasid); - return sent; -} - - -/********************************************************************* - * l1_cons functions - * - * These allow the L1 to act as the system console. They're intended - * to abstract away most of the br/l1 internal details from the - * _L1_cons_* functions (in the prom-- see "l1_console.c") and - * l1_* functions (in the kernel-- see "sio_l1.c") that they support. - * - */ - -static int -l1_poll( l1sc_t *sc, int mode ) -{ - int ret; - - /* in case this gets called before the l1sc_t structure for the module_t - * struct for this node is initialized (i.e., if we're called with a - * zero l1sc_t pointer)... - */ - - - if( !sc ) { - return 0; - } - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - - ret = brl1_receive( sc, mode ); - if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) ) - L1_collectibles[L1C_REC_STALLS] = ret; - - if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) { - return 1; - } - return 0; -} - - -/* pull a character off of the system console queue (if one is available) - */ -static int -l1_getc( l1sc_t *sc, int mode ) -{ - unsigned long pl = 0; - int c; - - brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]); - sc_cq_t *q = subch->iqp; - - if( !l1_poll( sc, mode ) ) { - return 0; - } - - SUBCH_DATA_LOCK( subch, pl ); - if( cq_empty( q ) ) { - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - return 0; - } - cq_rem( q, c ); - if( cq_empty( q ) ) - atomic_set(&subch->packet_arrived, 0); - SUBCH_DATA_UNLOCK( subch, pl ); - - return c; -} - -/* - * Write a message to the L1 on the system console subchannel. - * - * Danger: don't use a non-zero value for the wait parameter unless you're - * someone important (like a kernel error message). - */ - -int -l1_write( l1sc_t *sc, char *msg, int len, int wait ) -{ - int sent = 0, ret = 0; - - if ( wait ) { - while ( sent < len ) { - ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - sent += ret; - msg += ret; - } - ret = len; - } - else { - ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait ); - } - return(ret); -} - -/* initialize the system console subchannel - */ -void -l1_init(void) -{ - /* All we do now is remember that we have been called */ - L1_cons_is_inited = 1; -} - - -/********************************************************************* - * The following functions and definitions implement the "message"- - * style interface to the L1 system controller. - * - * Note that throughout this file, "sc" generally stands for "system - * controller", while "subchannels" tend to be represented by - * variables with names like subch or ch. - * - */ - -#ifdef L1_DEBUG -#define L1_DBG_PRF(x) printf x -#else -#define L1_DBG_PRF(x) -#endif - -/* - * sc_data_ready is called to signal threads that are blocked on l1 input. - */ -void -sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - - brl1_sch_t *subch = &(sc->subch[ch]); - SUBCH_DATA_LOCK( subch, pl ); - sv_signal( &(subch->arrive_sv) ); - SUBCH_DATA_UNLOCK( subch, pl ); -} - -/* sc_open reserves a subchannel to send a request to the L1 (the - * L1's response will arrive on the same channel). The number - * returned by sc_open is the system controller subchannel - * acquired. - */ -int -sc_open( l1sc_t *sc, uint target ) -{ - /* The kernel version implements a locking scheme to arbitrate - * subchannel assignment. - */ - int ch; - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - - /* Look for a free subchannel. Subchannels 0-15 are reserved - * for other purposes. - */ - for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; - ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) { - if( subch->use == BRL1_SUBCH_FREE ) - break; - } - - if( ch == BRL1_NUM_SUBCHANS ) { - /* there were no subchannels available! */ - SUBCH_UNLOCK( sc, pl ); - return SC_NSUBCH; - } - - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = target; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - return ch; -} - - -/* sc_close frees a Bedrock<->L1 subchannel. - */ -int -sc_close( l1sc_t *sc, int ch ) -{ - unsigned long pl = 0; - brl1_sch_t *subch; - - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[ch]); - if( subch->use != BRL1_SUBCH_RSVD ) { - /* we're trying to close a subchannel that's not open */ - SUBCH_UNLOCK( sc, pl ); - return SC_NOPEN; - } - - atomic_set(&subch->packet_arrived, 0); - subch->use = BRL1_SUBCH_FREE; - - sv_broadcast( &(subch->arrive_sv) ); - sv_destroy( &(subch->arrive_sv) ); - spin_lock_destroy( &(subch->data_lock) ); - - ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) ); - snia_kmem_free( subch->iqp, sizeof(sc_cq_t) ); - subch->iqp = &sc->garbage_q; - subch->tx_notify = NULL; - subch->rx_notify = brl1_discard_packet; - - SUBCH_UNLOCK( sc, pl ); - - return SC_SUCCESS; -} - - -/* sc_construct_msg builds a bedrock-to-L1 request in the supplied - * buffer. Returns the length of the message. The - * safest course when passing a buffer to be filled in is to use - * BRL1_QSIZE as the buffer size. - * - * Command arguments are passed as type/argument pairs, i.e., to - * pass the number 5 as an argument to an L1 command, call - * sc_construct_msg as follows: - * - * char msg[BRL1_QSIZE]; - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 2, - * L1_ARG_INT, 5 ); - * - * To pass an additional ASCII argument, you'd do the following: - * - * char *str; - * ... str points to a null-terminated ascii string ... - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 4, - * L1_ARG_INT, 5, - * L1_ARG_ASCII, str ); - * - * Finally, arbitrary data of unknown type is passed using the argtype - * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g. - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 3, - * L1_ARG_UNKNOWN, 32, bufptr ); - * - * ...passes 32 bytes of data starting at bufptr. Note that no string or - * "unknown"-type argument should be long enough to overflow the message - * buffer. - * - * To construct a message for an L1 command that requires no arguments, - * you'd use the following: - * - * msg_len = sc_construct_msg( msg, - * BRL1_QSIZE, - * target_component, - * L1_ADDR_TASK_BOGUSTASK, - * L1_BOGUSTASK_REQ_BOGUSREQ, - * 0 ); - * - * The final 0 means "no varargs". Notice that this parameter is used to hold - * the number of additional arguments to sc_construct_msg, _not_ the actual - * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII] - * type argument, and 3 per L1_ARG_UNKOWN type argument). A call to construct - * an L1 command which required three integer arguments and two arguments of - * some arbitrary (unknown) type would pass 12 as the value for this parameter. - * - * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth - * between byte arrays and four-byte big-endian integers. Depending on the - * system controller connection and endianness of future architectures, some - * rewriting might be necessary. - */ -int -sc_construct_msg( l1sc_t *sc, /* system controller struct */ - int ch, /* subchannel for this message */ - char *msg, /* message buffer */ - int msg_len, /* size of message buffer */ - l1addr_t addr_task, /* target system controller task */ - short req_code, /* 16-bit request code */ - int req_nargs, /* # of arguments (varargs) passed */ - ... ) /* any additional parameters */ -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold command argument addresses */ - va_list al; /* variable argument list */ - int index; /* current index into msg buffer */ - int argno; /* current position in varargs list */ - int l1_argno; /* running total of arguments to l1 */ - int l1_arg_t; /* argument type/length */ - int l1_argno_byte; /* offset of argument count byte */ - - index = argno = 0; - - /* set up destination address */ - if( (msg_len -= sizeof( buf32 )) < 0 ) - return -1; - L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task ); - COPY_INT_TO_BUFFER(msg, index, buf32); - - /* copy request code */ - if( (msg_len -= 2) < 0 ) - return( -1 ); - msg[index++] = ((req_code >> 8) & 0xff); - msg[index++] = (req_code & 0xff); - - if( !req_nargs ) { - return index; - } - - /* reserve a byte for the argument count */ - if( (msg_len -= 1) < 0 ) - return( -1 ); - l1_argno_byte = index++; - l1_argno = 0; - - /* copy additional arguments */ - va_start( al, req_nargs ); - while( argno < req_nargs ) { - l1_argno++; - l1_arg_t = va_arg( al, int ); argno++; - switch( l1_arg_t ) - { - case L1_ARG_INT: - if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_INT; - buf32 = (unsigned)va_arg( al, int ); argno++; - COPY_INT_TO_BUFFER(msg, index, buf32); - break; - - case L1_ARG_ASCII: - bufptr = va_arg( al, char* ); argno++; - if( (msg_len -= (strlen( bufptr ) + 2)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_ASCII; - strcpy( (char *)&(msg[index]), (char *)bufptr ); - index += (strlen( bufptr ) + 1); /* include terminating null */ - break; - - case L1_ARG_UNKNOWN: - { - int arglen; - - arglen = va_arg( al, int ); argno++; - bufptr = va_arg( al, void* ); argno++; - if( (msg_len -= (arglen + 1)) < 0 ) - return( -1 ); - msg[index++] = L1_ARG_UNKNOWN | arglen; - BCOPY( bufptr, &(msg[index]), arglen ); - index += arglen; - break; - } - - default: /* unhandled argument type */ - return -1; - } - } - - va_end( al ); - msg[l1_argno_byte] = l1_argno; - - return index; -} - - - -/* sc_interpret_resp verifies an L1 response to a bedrock request, and - * breaks the response data up into the constituent parts. If the - * response message indicates error, or if a mismatch is found in the - * expected number and type of arguments, an error is returned. The - * arguments to this function work very much like the arguments to - * sc_construct_msg, above, except that L1_ARG_INTs must be followed - * by a _pointer_ to an integer that can be filled in by this function. - */ -int -sc_interpret_resp( char *resp, /* buffer received from L1 */ - int resp_nargs, /* number of _varargs_ passed in */ - ... ) -{ - uint32_t buf32; /* 32-bit buffer used to bounce things around */ - void *bufptr; /* used to hold response field addresses */ - va_list al; /* variable argument list */ - int index; /* current index into response buffer */ - int argno; /* current position in varargs list */ - int l1_fldno; /* number of resp fields received from l1 */ - int l1_fld_t; /* field type/length */ - - index = argno = 0; - -#if defined(L1_DEBUG) -#define DUMP_RESP \ - { \ - int ix; \ - char outbuf[512]; \ - sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \ - for( ix = 0; ix < 16; ix++ ) { \ - sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] ); \ - } \ - printk( "%s\n", outbuf ); \ - } -#else -#define DUMP_RESP -#endif /* L1_DEBUG */ - - /* check response code */ - COPY_BUFFER_TO_INT(resp, index, buf32); - if( buf32 != L1_RESP_OK ) { - DUMP_RESP; - return buf32; - } - - /* get number of response fields */ - l1_fldno = resp[index++]; - - va_start( al, resp_nargs ); - - /* copy out response fields */ - while( argno < resp_nargs ) { - l1_fldno--; - l1_fld_t = va_arg( al, int ); argno++; - switch( l1_fld_t ) - { - case L1_ARG_INT: - if( resp[index++] != L1_ARG_INT ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, int* ); argno++; - COPY_BUFFER_TO_BUFFER(resp, index, bufptr); - break; - - case L1_ARG_ASCII: - if( resp[index++] != L1_ARG_ASCII ) { - /* type mismatch */ - va_end( al ); - DUMP_RESP; - return -1; - } - bufptr = va_arg( al, char* ); argno++; - strcpy( (char *)bufptr, (char *)&(resp[index]) ); - /* include terminating null */ - index += (strlen( &(resp[index]) ) + 1); - break; - - default: - if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN ) - { - int *arglen; - - arglen = va_arg( al, int* ); argno++; - bufptr = va_arg( al, void* ); argno++; - *arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff); - BCOPY( &(resp[index]), bufptr, *arglen ); - index += (*arglen); - } - - else { - /* unhandled type */ - va_end( al ); - DUMP_RESP; - return -1; - } - } - } - va_end( al ); - - if( (l1_fldno != 0) || (argno != resp_nargs) ) { - /* wrong number of arguments */ - DUMP_RESP; - return -1; - } - return 0; -} - - - - -/* sc_send takes as arguments a system controller struct, a - * buffer which contains a Bedrock<->L1 "request" message, - * the message length, and the subchannel (presumably obtained - * from an earlier invocation of sc_open) over which the - * message is to be sent. The final argument ("wait") indicates - * whether the send is to be performed synchronously or not. - * - * sc_send returns either zero or an error value. Synchronous sends - * (wait != 0) will not return until the data has actually been sent - * to the UART. Synchronous sends generally receive privileged - * treatment. The intent is that they be used sparingly, for such - * purposes as kernel printf's (the "ducons" routines). Run-of-the-mill - * console output and L1 requests should NOT use a non-zero value - * for wait. - */ -int -sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ) -{ - char type_and_subch; - int result; - - if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) { - return SC_BADSUBCH; - } - - /* Verify that this is an open subchannel - */ - if( sc->subch[ch].use == BRL1_SUBCH_FREE ) { - return SC_NOPEN; - } - - type_and_subch = (BRL1_REQUEST | ((u_char)ch)); - result = brl1_send( sc, msg, len, type_and_subch, wait ); - - /* If we sent as much as we asked to, return "ok". */ - if( result == len ) - return( SC_SUCCESS ); - - /* Or, if we sent less, than either the UART is busy or - * we're trying to send too large a packet anyway. - */ - else if( result >= 0 && result < len ) - return( SC_BUSY ); - - /* Or, if something else went wrong (result < 0), then - * return that error value. - */ - else - return( result ); -} - - - -/* subch_pull_msg pulls a message off the receive queue for subch - * and places it the buffer pointed to by msg. This routine should only - * be called when the caller already knows a message is available on the - * receive queue (and, in the kernel, only when the subchannel data lock - * is held by the caller). - */ -static void -subch_pull_msg( brl1_sch_t *subch, char *msg, int *len ) -{ - sc_cq_t *q; /* receive queue */ - int before_wrap, /* packet may be split into two different */ - after_wrap; /* pieces to accommodate queue wraparound */ - - /* pull message off the receive queue */ - q = subch->iqp; - - cq_rem( q, *len ); /* remove length byte and store */ - cq_discard( q ); /* remove type/subch byte and discard */ - - if ( *len > 0 ) - (*len)--; /* don't count type/subch byte in length returned */ - - if( (q->opos + (*len)) > BRL1_QSIZE ) { - before_wrap = BRL1_QSIZE - q->opos; - after_wrap = (*len) - before_wrap; - } - else { - before_wrap = (*len); - after_wrap = 0; - } - - BCOPY( q->buf + q->opos, msg, before_wrap ); - if( after_wrap ) { - BCOPY( q->buf, msg + before_wrap, after_wrap ); - q->opos = after_wrap; - } - else { - q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1)); - } - atomic_dec(&(subch->packet_arrived)); -} - - -/* sc_recv_poll can be called as a blocking or non-blocking function; - * it attempts to pull a message off of the subchannel specified - * in the argument list (ch). - * - * The "block" argument, if non-zero, is interpreted as a timeout - * delay (to avoid permanent waiting). - */ - -int -sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - rtc_time_t exp_time = rtc_time() + block; - - /* sanity check-- make sure this is an open subchannel */ - if( subch->use == BRL1_SUBCH_FREE ) - return( SC_NOPEN ); - - do { - - /* kick the next lower layer and see if it pulls anything in - */ - brl1_receive( sc, SERIAL_POLLED_MODE ); - is_msg = atomic_read(&subch->packet_arrived); - - } while( block && !is_msg && (rtc_time() < exp_time) ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - return( SC_NMSG ); - } - - SUBCH_DATA_LOCK( subch, pl ); - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - - -/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking - * or non-blocking mode. Rather than polling until an appointed timeout, - * however, sc_recv_intr sleeps on a syncrhonization variable until a - * signal from the lower layer tells us that a packet has arrived. - * - * sc_recv_intr can't be used with remote (router) L1s. - */ -int -sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ) -{ - int is_msg = 0; - unsigned long pl = 0; - brl1_sch_t *subch = &(sc->subch[ch]); - - do { - SUBCH_DATA_LOCK(subch, pl); - is_msg = atomic_read(&subch->packet_arrived); - if( !is_msg && block ) { - /* wake me when you've got something */ - subch->rx_notify = sc_data_ready; - sv_wait( &(subch->arrive_sv), 0, 0); - if( subch->use == BRL1_SUBCH_FREE ) { - /* oops-- somebody closed our subchannel while we were - * sleeping! - */ - - /* no need to unlock since the channel's closed anyhow */ - return( SC_NOPEN ); - } - } - } while( !is_msg && block ); - - if( !is_msg ) { - /* no message and we didn't care to wait for one */ - SUBCH_DATA_UNLOCK( subch, pl ); - return( SC_NMSG ); - } - - subch_pull_msg( subch, msg, len ); - SUBCH_DATA_UNLOCK( subch, pl ); - - return( SC_SUCCESS ); -} - -/* sc_command implements a (blocking) combination of sc_send and sc_recv. - * It is intended to be the SN1 equivalent of SN0's "elsc_command", which - * issued a system controller command and then waited for a response from - * the system controller before returning. - * - * cmd points to the outgoing command; resp points to the buffer in - * which the response is to be stored. Both buffers are assumed to - * be the same length; if there is any doubt as to whether the - * response buffer is long enough to hold the L1's response, then - * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any - * bigger. - * - * Be careful using the same buffer for both cmd and resp; it could get - * hairy if there were ever an L1 command request that spanned multiple - * packets. (On the other hand, that would require some additional - * rewriting of the L1 command interface anyway.) - */ -#define __RETRIES 50 -#define __WAIT_SEND 1 // ( sc->uart != BRL1_LOCALHUB_UART ) -#define __WAIT_RECV 10000000 - - -int -sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else - int result; - int retries; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - retries = __RETRIES; - - while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) { - if( result == SC_BUSY ) { - retries--; - if( retries <= 0 ) - return result; - uart_delay(500); - } - else { - return result; - } - } - - /* block on sc_recv_* */ - if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) { - return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) ); - } - else { - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); - } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - -/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command - * used in situations where the kernel has a command that shouldn't be - * delayed until the send buffer clears. sc_command should be used instead - * under most circumstances. - */ - -int -sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ) -{ -#ifndef CONFIG_SERIAL_SGI_L1_PROTOCOL - return SC_NMSG; -#else - int result; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return SC_NMSG; - - if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) { - return result; - } - - return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - - -/* sc_poll checks the queue corresponding to the given - * subchannel to see if there's anything available. If - * not, it kicks the brl1 layer and then checks again. - * - * Returns 1 if input is available on the given queue, - * 0 otherwise. - */ - -int -sc_poll( l1sc_t *sc, int ch ) -{ - brl1_sch_t *subch = &(sc->subch[ch]); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - brl1_receive( sc, SERIAL_POLLED_MODE ); - - if( atomic_read(&subch->packet_arrived) ) - return 1; - - return 0; -} - -/* for now, sc_init just calls brl1_init */ - -void -sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ) -{ - if ( !IS_RUNNING_ON_SIMULATOR() ) - brl1_init( sc, nasid, uart ); -} - -/* sc_dispatch_env_event handles events sent from the system control - * network's environmental monitor tasks. - */ - -#if defined(LINUX_KERNEL_THREADS) - -static void -sc_dispatch_env_event( uint code, int argc, char *args, int maxlen ) -{ - int j, i = 0; - uint32_t ESPcode; - - switch( code ) { - /* for now, all codes do the same thing: grab two arguments - * and print a cmn_err_tag message */ - default: - /* check number of arguments */ - if( argc != 2 ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected 2 arguments, got %d\n", argc )); - return; - } - - /* get ESP code (integer argument) */ - if( args[i++] != L1_ARG_INT ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected integer argument\n" )); - return; - } - /* WARNING: highly endian */ - COPY_BUFFER_TO_INT(args, i, ESPcode); - - /* verify string argument */ - if( args[i++] != L1_ARG_ASCII ) { - L1_DBG_PRF(( "sc_dispatch_env_event: " - "expected an ASCII string\n" )); - return; - } - for( j = i; j < maxlen; j++ ) { - if( args[j] == '\0' ) break; /* found string termination */ - } - if( j == maxlen ) { - j--; - L1_DBG_PRF(( "sc_dispatch_env_event: " - "message too long-- truncating\n" )); - } - - /* strip out trailing cr/lf */ - for( ; - j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); - j-- ); - args[j] = '\0'; - - /* strip out leading cr/lf */ - for( ; - i < j && ((args[i] == 0xd) || (args[i] == 0xa)); - i++ ); - } -} - - -/* sc_event waits for events to arrive from the system controller, and - * prints appropriate messages to the syslog. - */ - -static void -sc_event( l1sc_t *sc, int ch ) -{ - char event[BRL1_QSIZE]; - int i; - int result; - int event_len; - uint32_t ev_src; - uint32_t ev_code; - int ev_argc; - - while(1) { - - bzero( event, BRL1_QSIZE ); - - /* - * wait for an event - */ - result = sc_recv_intr( sc, ch, event, &event_len, 1 ); - if( result != SC_SUCCESS ) { - printk(KERN_WARNING "Error receiving sysctl event on nasid %d\n", - sc->nasid ); - } - else { - /* - * an event arrived; break it down into useful pieces - */ -#if defined(L1_DEBUG) && 0 - int ix; - printf( "Event packet received:\n" ); - for (ix = 0; ix < 64; ix++) { - printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)), - (event[ix] & ((uint64_t)0xf)) ); - if( (ix % 16) == 0xf ) printf( "\n" ); - } -#endif /* L1_DEBUG */ - - i = 0; - - /* get event source */ - COPY_BUFFER_TO_INT(event, i, ev_src); - COPY_BUFFER_TO_INT(event, i, ev_code); - - /* get arg count */ - ev_argc = (event[i++] & 0xffUL); - - /* dispatch events by task */ - switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT ) - { - case L1_ADDR_TASK_ENV: /* environmental monitor event */ - sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), - BRL1_QSIZE - i ); - break; - - default: /* unhandled task type */ - L1_DBG_PRF(( "Unhandled event type received from system " - "controllers: source task %x\n", - (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT - )); - } - } - - } -} - -/* sc_listen sets up a service thread to listen for incoming events. - */ - -void -sc_listen( l1sc_t *sc ) -{ - int result; - unsigned long pl = 0; - brl1_sch_t *subch; - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int ch; /* system controller subchannel used */ - - extern int msc_shutdown_pri; - - /* grab the designated "event subchannel" */ - SUBCH_LOCK( sc, pl ); - subch = &(sc->subch[BRL1_EVENT_SUBCH]); - if( subch->use != BRL1_SUBCH_FREE ) { - SUBCH_UNLOCK( sc, pl ); - printk(KERN_WARNING "sysctl event subchannel in use! " - "Not monitoring sysctl events.\n" ); - return; - } - subch->use = BRL1_SUBCH_RSVD; - SUBCH_UNLOCK( sc, pl ); - - atomic_set(&subch->packet_arrived, 0); - subch->target = BRL1_LOCALHUB_UART; - spin_lock_init( &(subch->data_lock) ); - sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */); - subch->tx_notify = NULL; - subch->rx_notify = sc_data_ready; - subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, - NASID_TO_COMPACT_NODEID(sc->nasid) ); - ASSERT( subch->iqp ); - cq_init( subch->iqp ); - - /* set up a thread to listen for events */ - sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri, - KT_PS, (st_func_t *) sc_event, - (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 ); - - /* signal the L1 to begin sending events */ - bzero( msg, BRL1_QSIZE ); - ch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EVENT_SUBCH, 2, - L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len )); - goto err_return; - } - - result = sc_command_kern( sc, ch, msg, msg, &len ); - if( result < 0 ) - { - sc_close( sc, ch ); - L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result )); - goto err_return; - } - - sc_close( sc, ch ); - - result = sc_interpret_resp( msg, 0 ); - if( result < 0 ) - { - L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result )); - goto err_return; - } - - /* everything went fine; just return */ - return; - -err_return: - /* there was a problem; complain */ - printk(KERN_WARNING "failed to set sysctl event-monitoring subchannel. " - "Sysctl events will not be monitored.\n" ); -} - -#endif /* LINUX_KERNEL_THREADS */ diff -Nru a/arch/ia64/sn/io/l1_command.c b/arch/ia64/sn/io/l1_command.c --- a/arch/ia64/sn/io/l1_command.c Sun May 25 17:00:00 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1377 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ -#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ - -#define LD(x) (*(volatile uint64_t *)(x)) -#define SD(x, v) (LD(x) = (uint64_t) (v)) - -#define hub_cpu_get() 0 - -#define LBYTE(caddr) (*(char *) caddr) - -extern char *bcopy(const char * src, char * dest, int count); - -#define LDEBUG 0 - -/* - * ELSC data is in NVRAM page 7 at the following offsets. - */ - -#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ -#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ -#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ -#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ -#define NVRAM_CFG 0x707 /* ELSC Configuration info */ -#define NVRAM_MODULE 0x708 /* system module number */ -#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ -#define NVRAM_PARTITION 0x70a /* module's partition id */ -#define NVRAM_DOMAIN 0x70b /* module's domain id */ -#define NVRAM_CLUSTER 0x70c /* module's cluster id */ -#define NVRAM_CELL 0x70d /* module's cellid */ - -#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ -#define NVRAM_SIZE 16 /* 16 bytes in nvram */ - -/* - * Declare a static ELSC NVRAM buffer to hold all data read from - * and written to NVRAM. This nvram "cache" will be used only during the - * IP27prom execution. - */ -static char elsc_nvram_buffer[NVRAM_SIZE]; - -#define SC_COMMAND sc_command - -/* - * elsc_init - * - * Initialize ELSC structure - */ - -void elsc_init(elsc_t *e, nasid_t nasid) -{ - sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART); -} - - -/* - * elsc_errmsg - * - * Given a negative error code, - * returns a corresponding static error string. - */ - -char *elsc_errmsg(int code) -{ - switch (code) { - case ELSC_ERROR_CMD_SEND: - return "Command send error"; - case ELSC_ERROR_CMD_CHECKSUM: - return "Command packet checksum error"; - case ELSC_ERROR_CMD_UNKNOWN: - return "Unknown command"; - case ELSC_ERROR_CMD_ARGS: - return "Invalid command argument(s)"; - case ELSC_ERROR_CMD_PERM: - return "Permission denied"; - case ELSC_ERROR_RESP_TIMEOUT: - return "System controller response timeout"; - case ELSC_ERROR_RESP_CHECKSUM: - return "Response packet checksum error"; - case ELSC_ERROR_RESP_FORMAT: - return "Response format error"; - case ELSC_ERROR_RESP_DIR: - return "Response direction error"; - case ELSC_ERROR_MSG_LOST: - return "Message lost because queue is full"; - case ELSC_ERROR_LOCK_TIMEOUT: - return "Timed out getting ELSC lock"; - case ELSC_ERROR_DATA_SEND: - return "Error sending data"; - case ELSC_ERROR_NIC: - return "NIC protocol error"; - case ELSC_ERROR_NVMAGIC: - return "Bad magic number in NVRAM"; - case ELSC_ERROR_MODULE: - return "Module location protocol error"; - default: - return "Unknown error"; - } -} - -/* - * elsc_nvram_init - * - * Initializes reads and writes to NVRAM. This will perform a single - * read to NVRAM, getting all data at once. When the PROM tries to - * read NVRAM, it returns the data from the buffer being read. If the - * PROM tries to write out to NVRAM, the write is done, and the internal - * buffer is updated. - */ - -void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data) -{ - /* This might require implementation of multiple-packet request/responses - * if it's to provide the same behavior that was available in SN0. - */ - nasid = nasid; - elsc_nvram_data = elsc_nvram_data; -} - -/* - * elsc_nvram_copy - * - * Copies the content of a buffer into the static buffer in this library. - */ - -void elsc_nvram_copy(uchar_t *elsc_nvram_data) -{ - memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE); -} - -/* - * elsc_nvram_write - * - * Copies bytes from 'buf' into NVRAM, starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. - */ - -int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len) -{ - /* Here again, we might need to work out the details of a - * multiple-packet protocol. - */ - - /* For now, pretend it worked. */ - e = e; - addr = addr; - buf = buf; - return (len < 0 ? -len : len); -} - -/* - * elsc_nvram_read - * - * Copies bytes from NVRAM into 'buf', starting at NVRAM address - * 'addr' which must be between 0 and 2047. - * - * If 'len' is non-negative, the routine copies 'len' bytes. - * - * If 'len' is negative, the routine treats the data as a string and - * copies bytes up to and including a NUL-terminating zero, but not - * to exceed '-len' bytes. NOTE: This method is no longer supported. - * It was never used in the first place. - */ - -int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len) -{ - /* multiple packets? */ - e = e; - addr = addr; - buf = buf; - len = len; - return -1; -} - - -/* - * Command Set - */ - -int elsc_version(elsc_t *e, char *result) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} - -int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2) -{ - /* shush compiler */ - e = e; - byte1 = byte1; - byte2 = byte2; - - /* fill in a buffer with the opcode & params; call sc_command */ - - return 0; -} - -int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int dbg_sw; /* holds debug switch settings */ - int len; /* number of msg buffer bytes used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RDBG, 0 ) ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* copy out debug switch settings (last two bytes of the - * integer response) - */ - *byte1 = ((dbg_sw >> 8) & 0xFF); - *byte2 = (dbg_sw & 0xFF); - - return 0; -} - - -/* - * elsc_rack_bay_get fills in the two int * arguments with the - * rack number and bay number of the L1 being addressed - */ -int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRACK, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - - /* send the request to the L1 */ - if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close(e, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -/* elsc_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - /* convert brick_type to lower case */ - *brick_type = *brick_type - 'A' + 'a'; - - return 0; -} - - -int elsc_module_get(elsc_t *e) -{ - extern char brick_types[]; - uint rnum, rack, bay, bricktype, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { - return ret; - } - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == bricktype ) - return RBT_TO_MODULE(rack, bay, t); - } - - return ELSC_ERROR_MODULE; -} - -int elsc_partition_set(elsc_t *e, int partition) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_SET, 2, - L1_ARG_INT, partition )) < 0 ) - { - - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( 0 ); -} - -int elsc_partition_get(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t partition_id; /* used to copy partition id out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PARTITION_GET, 0 )) < 0 ) - - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return( partition_id ); -} - - -/* - * elsc_cons_subch selects the "active" console subchannel for this node - * (i.e., the one that will currently receive input) - */ -int elsc_cons_subch(elsc_t *e, uint ch) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_SUBCH, 2, - L1_ARG_INT, ch)) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* - * elsc_cons_node should only be executed by one node. It declares to - * the system controller that the node from which it is called will be - * the owner of the system console. - */ -int elsc_cons_node(elsc_t *e) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_CONS_NODE, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( e, subch, msg, msg, &len ) ) { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_line writes up to 12 characters to either the top or bottom - * line of the L1 display. line points to a buffer containing the message - * to be displayed. The zero-based line number is specified by lnum (so - * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). - * Lines longer than 12 characters, or line numbers not less than - * L1_DISPLAY_LINES, cause elsc_display_line to return an error. - */ -int elsc_display_line(elsc_t *e, char *line, int lnum) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - - /* argument sanity checking */ - if( !(lnum < L1_DISPLAY_LINES) ) - return( ELSC_ERROR_CMD_ARGS ); - if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) ) - return( ELSC_ERROR_CMD_ARGS ); - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - (L1_REQ_DISP1+lnum), 2, - L1_ARG_ASCII, line )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( (l1sc_t *)e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -/* elsc_display_mesg silently drops message characters beyond the 12th. - */ -int elsc_display_mesg(elsc_t *e, char *chr) -{ - - char line[L1_DISPLAY_LINE_LENGTH+1]; - int numlines, i; - int result; - - numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) / - L1_DISPLAY_LINE_LENGTH; - - if( numlines > L1_DISPLAY_LINES ) - numlines = L1_DISPLAY_LINES; - - for( i = 0; i < numlines; i++ ) - { - strlcpy( line, chr, sizeof(line) ); - - /* generally we want to leave the first line of the L1 display - * alone (so the L1 can manipulate it). If you need to be able - * to display to both lines (for debugging purposes), define - * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES - * to your 'defs file. - */ -#if defined(L1_DISP_2LINES) - if( (result = elsc_display_line( e, line, i )) < 0 ) -#else - if( (result = elsc_display_line( e, line, i+1 )) < 0 ) -#endif - - return result; - - chr += L1_DISPLAY_LINE_LENGTH; - } - - return 0; -} - - -int elsc_password_set(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -int elsc_password_get(elsc_t *e, char *password) -{ - /* shush compiler */ - e = e; - password = password; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* - * sc_portspeed_get - * - * retrieve the current portspeed setting for the bedrock II - */ -int sc_portspeed_get(l1sc_t *sc) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int portspeed_a, portspeed_b; - /* ioport clock rates */ - - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCAL ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_PORTSPEED, - 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, - L1_ARG_INT, &portspeed_a, - L1_ARG_INT, &portspeed_b ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* for the c-brick, we ignore the portspeed_b value */ - return (portspeed_a ? 600 : 400); -} - -/* - * elsc_power_query - * - * To be used after system reset, this command returns 1 if the reset - * was the result of a power-on, 0 otherwise. - * - * The power query status is cleared to 0 after it is read. - */ - -int elsc_power_query(elsc_t *e) -{ - e = e; /* shush the compiler */ - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 1; -} - -int elsc_rpwr_query(elsc_t *e, int is_master) -{ - /* shush the compiler */ - e = e; - is_master = is_master; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - -/* - * elsc_power_down - * - * Sets up system to shut down in "sec" seconds (or modifies the - * shutdown time if one is already in effect). Use 0 to power - * down immediately. - */ - -int elsc_power_down(elsc_t *e, int sec) -{ - /* shush compiler */ - e = e; - sec = sec; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -int elsc_system_reset(elsc_t *e) -{ - char msg[BRL1_QSIZE]; - int subch; /* system controller subchannel used */ - int len; /* number of msg buffer bytes used */ - int result; - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) { - return ELSC_ERROR_CMD_SEND; - } - - if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RESET, 0 )) < 0 ) - { - sc_close( e, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( (result = sc_command( e, subch, msg, msg, &len )) ) { - sc_close( e, subch ); - if( result == SC_NMSG ) { - /* timeout is OK. We've sent the reset. Now it's just - * a matter of time... - */ - return( 0 ); - } - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( e, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - - -int elsc_power_cycle(elsc_t *e) -{ - /* shush compiler */ - e = e; - - /* fill in buffer with the opcode & params; call sc_command */ - - return 0; -} - - -/* - * L1 Support for reading - * cbrick uid. - */ - -int elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose) -{ - /* this parameter included only for SN0 compatibility */ - verbose = verbose; - - /* We don't go straight to the bedrock/L1 protocol on this one, but let - * the eeprom layer prepare the eeprom data as we would like it to - * appear to the caller - */ - return cbrick_uid_get( e->nasid, nic ); -} - - -int _elsc_hbt(elsc_t *e, int ival, int rdly) -{ - e = e; - ival = ival; - rdly = rdly; - - /* fill in buffer with the opcode & params; call elsc_command */ - - return 0; -} - - -/* send a command string to an L1 */ -int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay, - char *cmd ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - l1addr_t target; /* target system controller for command */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - - L1_BUILD_ADDR( &target, compt, rack, bay, 0 ); - subch = sc_open( sc, target ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2, - L1_ARG_ASCII, cmd )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; -} - -/* - * sc_power_down - * - * Shuts down the c-brick associated with sc, and any attached I/O bricks - * or other c-bricks (won't go through r-bricks). - */ - -int sc_power_down(l1sc_t *sc) -{ - return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); -} - - -/* - * sc_power_down_all - * - * Works similarly to sc_power_down, except that the request is sent to the - * closest L2 and EVERYBODY gets turned off. - */ - -int sc_power_down_all(l1sc_t *sc) -{ - if( nodepda->num_routers > 0 ) { - return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, - L1_ADDR_BAY_LOCAL, "* pwr d" ); - } - else { - return sc_power_down( sc ); - } -} - - -/* - * Routines for reading the R-brick's L1 - */ - -int router_module_get( nasid_t nasid, net_vec_t path ) -{ - uint rnum, rack, bay, t; - int ret; - l1sc_t sc; - - /* prepare l1sc_t struct */ - sc_init( &sc, nasid, path ); - - /* construct module ID from rack and slot info */ - - if ((ret = elsc_rack_bay_get(&sc, &rnum, &bay)) < 0) - return ret; - - /* report unset location info. with a special, otherwise invalid modid */ - if (rnum == 0 && bay == 0) - return MODULE_NOT_SET; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - ret = RBT_TO_MODULE(rack, bay, MODULE_RBRICK); - return ret; -} - - -/* - * iobrick routines - */ - -/* iobrick_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ -int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_RRBT, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, - L1_ARG_INT, brick_type ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - /* extract rack/bay info - * - * note that the 32-bit value returned by the L1 actually - * only uses the low-order sixteen bits for rack and bay - * information. A "normal" L1 address puts rack and bay - * information in bit positions 12 through 28. So if - * we initially shift the value returned 12 bits to the left, - * we can use the L1 addressing #define's to extract the - * values we need (see ksys/l1.h for a complete list of the - * various fields of an L1 address). - */ - buf32 <<= L1_ADDR_BAY_SHFT; - - *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - - return 0; -} - - -int iobrick_module_get(l1sc_t *sc) -{ - uint rnum, rack, bay, brick_type, t; - int ret; - - /* construct module ID from rack and slot info */ - - if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0) - return ret; - - if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) - return ELSC_ERROR_MODULE; - - /* Build a moduleid_t-compatible rack number */ - - rack = 0; - t = rnum / 100; /* rack class (CPU/IO) */ - if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_CLASS(rack, t); - rnum %= 100; - - t = rnum / 10; /* rack group */ - if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_GROUP(rack, t); - - t = rnum % 10; /* rack number (one-based) */ - if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack)) - return ELSC_ERROR_MODULE; - RACK_ADD_NUM(rack, t); - - switch( brick_type ) { - case 'I': - brick_type = MODULE_IBRICK; break; - case 'P': - brick_type = MODULE_PBRICK; break; - case 'X': - brick_type = MODULE_XBRICK; break; - } - - ret = RBT_TO_MODULE(rack, bay, brick_type); - - return ret; -} - -/* iobrick_get_sys_snum asks the attached iobrick for the system - * serial number. This function will only be relevant to the master - * cbrick (the one attached to the bootmaster ibrick); other nodes - * may call the function, but the value returned to the master node - * will be the one used as the system serial number by the kernel. - */ - -int -iobrick_get_sys_snum( l1sc_t *sc, char *snum_str ) -{ - char msg[BRL1_QSIZE]; /* L1 request/response info */ - int subch; /* system controller subchannel used */ - int len; /* length of message */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) { - return( ELSC_ERROR_CMD_SEND ); - } - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SYS_SERIAL, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) ); -} - - -/* - * The following functions apply (or cut off) power to the specified - * pci bus or slot. - */ - -int -iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code ) -{ -#if 0 /* The "bedrock request" method of performing this function - * seems to be broken in the L1, so for now use the command- - * interpreter method - */ - - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - req_code, 4, - L1_ARG_INT, bus, - L1_ARG_INT, slot )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 0 ) < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - return 0; - -#else - char cmd[64]; - char *fxn; - - switch( req_code ) - { - case L1_REQ_PCI_UP: - fxn = "u"; - break; - case L1_REQ_PCI_DOWN: - fxn = "d"; - break; - case L1_REQ_PCI_RESET: - fxn = "rst"; - break; - default: - return( ELSC_ERROR_CMD_ARGS ); - } - - if( slot == -1 ) - sprintf( cmd, "pci %d %s", bus, fxn ); - else - sprintf( cmd, "pci %d %d %s", bus, slot, fxn ); - - return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK, - L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd ); -#endif -} - -int -iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ) -{ - return iobrick_pci_pwr( sc, bus, slot, up ); -} - -int -iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ) -{ - return iobrick_pci_pwr( sc, bus, -1, up ); -} - - -int -iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot ) -{ - return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET ); -} - -int -iobrick_pci_bus_rst( l1sc_t *sc, int bus ) -{ - return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET ); -} - - -/* get the L1 firmware version for an iobrick */ -int -iobrick_sc_version( l1sc_t *sc, char *result ) -{ - char msg[BRL1_QSIZE]; - int len; /* length of message being sent */ - int subch; /* system controller subchannel used */ - int major, /* major rev number */ - minor, /* minor rev number */ - bugfix; /* bugfix rev number */ - - /* fill in msg with the opcode & params */ - bzero( msg, BRL1_QSIZE ); - subch = sc_open( sc, L1_ADDR_LOCALIO ); - - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_FW_REV, 0 )) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_ARGS ); - } - - /* send the request to the L1 */ - if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 ) - { - sc_close( sc, subch ); - return( ELSC_ERROR_CMD_SEND ); - } - - /* free up subchannel */ - sc_close( sc, subch ); - - /* check response */ - if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, - L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) - < 0 ) - { - return( ELSC_ERROR_RESP_FORMAT ); - } - - sprintf( result, "%d.%d.%d", major, minor, bugfix ); - - return 0; -} diff -Nru a/arch/ia64/sn/io/labelcl.c b/arch/ia64/sn/io/labelcl.c --- a/arch/ia64/sn/io/labelcl.c Wed Dec 4 07:04:52 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,654 +0,0 @@ -/* labelcl - SGI's Hwgraph Compatibility Layer. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* -** Very simple and dumb string table that supports only find/insert. -** In practice, if this table gets too large, we may need a more -** efficient data structure. Also note that currently there is no -** way to delete an item once it's added. Therefore, name collision -** will return an error. -*/ - -struct string_table label_string_table; - - - -/* - * string_table_init - Initialize the given string table. - */ -void -string_table_init(struct string_table *string_table) -{ - string_table->string_table_head = NULL; - string_table->string_table_generation = 0; - - /* - * We nedd to initialize locks here! - */ - - return; -} - - -/* - * string_table_destroy - Destroy the given string table. - */ -void -string_table_destroy(struct string_table *string_table) -{ - struct string_table_item *item, *next_item; - - item = string_table->string_table_head; - while (item) { - next_item = item->next; - - STRTBL_FREE(item); - item = next_item; - } - - /* - * We need to destroy whatever lock we have here - */ - - return; -} - - - -/* - * string_table_insert - Insert an entry in the string table .. duplicate - * names are not allowed. - */ -char * -string_table_insert(struct string_table *string_table, char *name) -{ - struct string_table_item *item, *new_item = NULL, *last_item = NULL; - -again: - /* - * Need to lock the table .. - */ - item = string_table->string_table_head; - last_item = NULL; - - while (item) { - if (!strcmp(item->string, name)) { - /* - * If we allocated space for the string and the found that - * someone else already entered it into the string table, - * free the space we just allocated. - */ - if (new_item) - STRTBL_FREE(new_item); - - - /* - * Search optimization: move the found item to the head - * of the list. - */ - if (last_item != NULL) { - last_item->next = item->next; - item->next = string_table->string_table_head; - string_table->string_table_head = item; - } - goto out; - } - last_item = item; - item=item->next; - } - - /* - * name was not found, so add it to the string table. - */ - if (new_item == NULL) { - long old_generation = string_table->string_table_generation; - - new_item = STRTBL_ALLOC(strlen(name)); - - strcpy(new_item->string, name); - - /* - * While we allocated memory for the new string, someone else - * changed the string table. - */ - if (old_generation != string_table->string_table_generation) { - goto again; - } - } else { - /* At this we only have the string table lock in access mode. - * Promote the access lock to an update lock for the string - * table insertion below. - */ - long old_generation = - string_table->string_table_generation; - - /* - * After we did the unlock and wer waiting for update - * lock someone could have potentially updated - * the string table. Check the generation number - * for this case. If it is the case we have to - * try all over again. - */ - if (old_generation != - string_table->string_table_generation) { - goto again; - } - } - - /* - * At this point, we're committed to adding new_item to the string table. - */ - new_item->next = string_table->string_table_head; - item = string_table->string_table_head = new_item; - string_table->string_table_generation++; - -out: - /* - * Need to unlock here. - */ - return(item->string); -} - -/* - * labelcl_info_create - Creates the data structure that will hold the - * device private information asscoiated with a devfs entry. - * The pointer to this structure is what gets stored in the devfs - * (void * info). - */ -labelcl_info_t * -labelcl_info_create() -{ - - labelcl_info_t *new = NULL; - - /* Initial allocation does not include any area for labels */ - if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL ) - return NULL; - - memset (new, 0, sizeof(labelcl_info_t)); - new->hwcl_magic = LABELCL_MAGIC; - return( new); - -} - -/* - * labelcl_info_destroy - Frees the data structure that holds the - * device private information asscoiated with a devfs entry. This - * data structure was created by device_info_create(). - * - * The caller is responsible for nulling the (void *info) in the - * corresponding devfs entry. - */ -int -labelcl_info_destroy(labelcl_info_t *labelcl_info) -{ - - if (labelcl_info == NULL) - return(0); - - /* Free the label list */ - if (labelcl_info->label_list) - kfree(labelcl_info->label_list); - - /* Now free the label info area */ - labelcl_info->hwcl_magic = 0; - kfree(labelcl_info); - - return(0); -} - -/* - * labelcl_info_add_LBL - Adds a new label entry in the labelcl info - * structure. - * - * Error is returned if we find another label with the same name. - */ -int -labelcl_info_add_LBL(devfs_handle_t de, - char *info_name, - arb_info_desc_t info_desc, - arbitrary_info_t info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - int new_label_list_size; - label_info_t *old_label_list, *new_label_list = NULL; - char *name; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = devfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if (info_name == NULL) - return(-1); - - if (strlen(info_name) >= LABEL_LENGTH_MAX) - return(-1); - - name = string_table_insert(&label_string_table, info_name); - - num_labels = labelcl_info->num_labels; - new_label_list_size = sizeof(label_info_t) * (num_labels+1); - - /* - * Create a new label info area. - */ - if (new_label_list_size != 0) { - new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); - - if (new_label_list == NULL) - return(-1); - } - - /* - * At this point, we are committed to adding the labelled info, - * if there isn't already information there with the same name. - */ - old_label_list = labelcl_info->label_list; - - /* - * Look for matching info name. - */ - for (i=0; inum_labels = num_labels+1; - labelcl_info->label_list = new_label_list; - - if (old_label_list != NULL) - kfree(old_label_list); - - return(0); -} - -/* - * labelcl_info_remove_LBL - Remove a label entry. - */ -int -labelcl_info_remove_LBL(devfs_handle_t de, - char *info_name, - arb_info_desc_t *info_desc, - arbitrary_info_t *info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - int new_label_list_size; - label_info_t *old_label_list, *new_label_list = NULL; - arb_info_desc_t label_desc_found; - arbitrary_info_t label_info_found; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = devfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - /* - * Create a new info area. - */ - new_label_list_size = sizeof(label_info_t) * (num_labels-1); - if (new_label_list_size) { - new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); - if (new_label_list == NULL) - return(-1); - } - - /* - * At this point, we are committed to removing the labelled info, - * if it still exists. - */ - old_label_list = labelcl_info->label_list; - - /* - * Find matching info name. - */ - for (i=0; inum_labels = num_labels+1; - labelcl_info->label_list = new_label_list; - - kfree(old_label_list); - - if (info != NULL) - *info = label_info_found; - - if (info_desc != NULL) - *info_desc = label_desc_found; - - return(0); -} - - -/* - * labelcl_info_replace_LBL - Replace an existing label entry with the - * given new information. - * - * Label entry must exist. - */ -int -labelcl_info_replace_LBL(devfs_handle_t de, - char *info_name, - arb_info_desc_t info_desc, - arbitrary_info_t info, - arb_info_desc_t *old_info_desc, - arbitrary_info_t *old_info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - label_info_t *label_list; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = devfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - if (info_name == NULL) - return(-1); - - label_list = labelcl_info->label_list; - - /* - * Verify that information under info_name already exists. - */ - for (i=0; ihwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - label_list = labelcl_info->label_list; - - /* - * Find information under info_name. - */ - for (i=0; ihwcl_magic != LABELCL_MAGIC) - return(-1); - - which_info = *placeptr; - - if (which_info >= labelcl_info->num_labels) { - return(-1); - } - - label_list = (label_info_t *) labelcl_info->label_list; - - if (buffer != NULL) - strcpy(buffer, label_list[which_info].name); - - if (infop) - *infop = label_list[which_info].info; - - if (info_descp) - *info_descp = label_list[which_info].desc; - - *placeptr = which_info + 1; - - return(0); -} - - -int -labelcl_info_replace_IDX(devfs_handle_t de, - int index, - arbitrary_info_t info, - arbitrary_info_t *old_info) -{ - arbitrary_info_t *info_list_IDX; - labelcl_info_t *labelcl_info = NULL; - - if (de == NULL) { - printk(KERN_ALERT "labelcl: NULL devfs handle given.\n"); - return(-1); - } - - labelcl_info = devfs_get_info(de); - if (labelcl_info == NULL) { - printk(KERN_ALERT "labelcl: Entry does not have info pointer.\n"); - return(-1); - } - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) - return(-1); - - /* - * Replace information at the appropriate index in this vertex with - * the new info. - */ - info_list_IDX = labelcl_info->IDX_list; - if (old_info != NULL) - *old_info = info_list_IDX[index]; - info_list_IDX[index] = info; - - return(0); - -} - -/* - * labelcl_info_connectpt_set - Sets the connectpt. - */ -int -labelcl_info_connectpt_set(struct devfs_entry *de, - struct devfs_entry *connect_de) -{ - arbitrary_info_t old_info; - int rv; - - rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, - (arbitrary_info_t) connect_de, &old_info); - - if (rv) { - return(rv); - } - - return(0); -} - - -/* - * labelcl_info_get_IDX - Returns the information pointed at by index. - * - */ -int -labelcl_info_get_IDX(devfs_handle_t de, - int index, - arbitrary_info_t *info) -{ - arbitrary_info_t *info_list_IDX; - labelcl_info_t *labelcl_info = NULL; - - if (de == NULL) - return(-1); - - labelcl_info = devfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) - return(-1); - - /* - * Return information at the appropriate index in this vertex. - */ - info_list_IDX = labelcl_info->IDX_list; - if (info != NULL) - *info = info_list_IDX[index]; - - return(0); -} - -/* - * labelcl_info_connectpt_get - Retrieve the connect point for a device entry. - */ -struct devfs_entry * -labelcl_info_connectpt_get(struct devfs_entry *de) -{ - int rv; - arbitrary_info_t info; - - rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); - if (rv) - return(NULL); - - return((struct devfs_entry *)info); -} diff -Nru a/arch/ia64/sn/io/machvec/Makefile b/arch/ia64/sn/io/machvec/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/machvec/Makefile Fri May 16 11:50:50 2003 @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += pci.o pci_dma.o pci_bus_cvlink.o iomv.o diff -Nru a/arch/ia64/sn/io/machvec/iomv.c b/arch/ia64/sn/io/machvec/iomv.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/machvec/iomv.c Fri May 16 04:18:18 2003 @@ -0,0 +1,71 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * sn_io_addr - convert an in/out port to an i/o address + * @port: port to convert + * + * Legacy in/out instructions are converted to ld/st instructions + * on IA64. This routine will convert a port number into a valid + * SN i/o address. Used by sn_in*() and sn_out*(). + */ +void * +sn_io_addr(unsigned long port) +{ + if (!IS_RUNNING_ON_SIMULATOR()) { + return( (void *) (port | __IA64_UNCACHED_OFFSET)); + } else { + unsigned long io_base; + unsigned long addr; + + /* + * word align port, but need more than 10 bits + * for accessing registers in bedrock local block + * (so we don't do port&0xfff) + */ + if ((port >= 0x1f0 && port <= 0x1f7) || + port == 0x3f6 || port == 0x3f7) { + io_base = (0xc000000fcc000000 | ((unsigned long)get_nasid() << 38)); + addr = io_base | ((port >> 2) << 12) | (port & 0xfff); + } else { + addr = __ia64_get_io_port_base() | ((port >> 2) << 2); + } + return(void *) addr; + } +} + +EXPORT_SYMBOL(sn_io_addr); + +/** + * sn_mmiob - I/O space memory barrier + * + * Acts as a memory mapped I/O barrier for platforms that queue writes to + * I/O space. This ensures that subsequent writes to I/O space arrive after + * all previous writes. For most ia64 platforms, this is a simple + * 'mf.a' instruction. For other platforms, mmiob() may have to read + * a chipset register to ensure ordering. + * + * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. + * See PV 871084 for details about the WAR about zero value. + * + */ +void +sn_mmiob (void) +{ + while ((((volatile unsigned long) (*pda->pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != + SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) + udelay(1); +} diff -Nru a/arch/ia64/sn/io/machvec/pci.c b/arch/ia64/sn/io/machvec/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/machvec/pci.c Fri May 23 03:54:40 2003 @@ -0,0 +1,135 @@ +/* + * + * SNI64 specific PCI support for SNI IO. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1997, 1998, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG_CONFIG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + + +#ifdef CONFIG_PCI + +extern vertex_hdl_t pci_bus_to_vertex(unsigned char); +extern vertex_hdl_t devfn_to_vertex(unsigned char bus, unsigned char devfn); + +int sn_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) +{ + unsigned long res = 0; + vertex_hdl_t device_vertex; + + device_vertex = devfn_to_vertex(bus->number, devfn); + res = pciio_config_get(device_vertex, (unsigned) where, size); + *val = (unsigned int) res; + return PCIBIOS_SUCCESSFUL; +} + +int sn_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) +{ + vertex_hdl_t device_vertex; + + device_vertex = devfn_to_vertex(bus->number, devfn); + pciio_config_set( device_vertex, (unsigned)where, size, (uint64_t) val); + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops sn_pci_ops = { + .read = sn_read_config, + .write = sn_write_config +}; + +/* + * sn_pci_find_bios - SNIA64 pci_find_bios() platform specific code. + */ +void __init +sn_pci_find_bios(void) +{ + extern struct pci_ops *pci_root_ops; + /* + * Go initialize our IO Infrastructure .. + */ + extern void sgi_master_io_infr_init(void); + + sgi_master_io_infr_init(); + + /* sn_io_infrastructure_init(); */ + pci_root_ops = &sn_pci_ops; +} + +void +pci_fixup_ioc3(struct pci_dev *d) +{ + int i; + unsigned int size; + + /* IOC3 only decodes 0x20 bytes of the config space, reading + * beyond that is relatively benign but writing beyond that + * (especially the base address registers) will shut down the + * pci bus...so avoid doing so. + * NOTE: this means we can't program the intr_pin into the device, + * currently we hack this with special code in + * sgi_pci_intr_support() + */ + DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); + + /* I happen to know from the spec that the ioc3 needs only 0xfffff + * The standard pci trick of writing ~0 to the baddr and seeing + * what comes back doesn't work with the ioc3 + */ + size = 0xfffff; + d->resource[0].end = (unsigned long) d->resource[0].start + (unsigned long) size; + + /* + * Zero out the resource structure .. because we did not go through + * the normal PCI Infrastructure Init, garbbage are left in these + * fileds. + */ + for (i = 1; i <= PCI_ROM_RESOURCE; i++) { + d->resource[i].start = 0UL; + d->resource[i].end = 0UL; + d->resource[i].flags = 0UL; + } + + d->subsystem_vendor = 0; + d->subsystem_device = 0; + +} + +#else +void sn_pci_find_bios(void) {} +void pci_fixup_ioc3(struct pci_dev *d) {} +struct list_head pci_root_buses; +struct list_head pci_root_buses; +struct list_head pci_devices; + +#endif /* CONFIG_PCI */ diff -Nru a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c Mon Jun 16 17:03:24 2003 @@ -0,0 +1,930 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int bridge_rev_b_data_check_disable; + +vertex_hdl_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; +nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; +void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; +unsigned char num_bridges; +static int done_probing; +extern irqpda_t *irqpdaindr; + +static int pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid); +vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); + +extern void register_pcibr_intr(int irq, pcibr_intr_t intr); + +void sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot); + + +/* + * For the given device, initialize whether it is a PIC device. + */ +static void +set_isPIC(struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + + device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);; +} + +/* + * pci_bus_cvlink_init() - To be called once during initialization before + * SGI IO Infrastructure init is called. + */ +void +pci_bus_cvlink_init(void) +{ + + extern void ioconfig_bus_init(void); + + memset(busnum_to_pcibr_vhdl, 0x0, sizeof(vertex_hdl_t) * MAX_PCI_XWIDGET); + memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); + + memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); + + num_bridges = 0; + + ioconfig_bus_init(); +} + +/* + * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated + * pci bus vertex from the SGI IO Infrastructure. + */ +vertex_hdl_t +pci_bus_to_vertex(unsigned char busnum) +{ + + vertex_hdl_t pci_bus = NULL; + + + /* + * First get the xwidget vertex. + */ + pci_bus = busnum_to_pcibr_vhdl[busnum]; + return(pci_bus); +} + +/* + * devfn_to_vertex() - returns the vertex of the device given the bus, slot, + * and function numbers. + */ +vertex_hdl_t +devfn_to_vertex(unsigned char busnum, unsigned int devfn) +{ + + int slot = 0; + int func = 0; + char name[16]; + vertex_hdl_t pci_bus = NULL; + vertex_hdl_t device_vertex = (vertex_hdl_t)NULL; + + /* + * Go get the pci bus vertex. + */ + pci_bus = pci_bus_to_vertex(busnum); + if (!pci_bus) { + /* + * During probing, the Linux pci code invents non-existent + * bus numbers and pci_dev structures and tries to access + * them to determine existence. Don't crib during probing. + */ + if (done_probing) + printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); + return(NULL); + } + + + /* + * Go get the slot&function vertex. + * Should call pciio_slot_func_to_name() when ready. + */ + slot = PCI_SLOT(devfn); + func = PCI_FUNC(devfn); + + /* + * For a NON Multi-function card the name of the device looks like: + * ../pci/1, ../pci/2 .. + */ + if (func == 0) { + sprintf(name, "%d", slot); + if (hwgraph_traverse(pci_bus, name, &device_vertex) == + GRAPH_SUCCESS) { + if (device_vertex) { + return(device_vertex); + } + } + } + + /* + * This maybe a multifunction card. It's names look like: + * ../pci/1a, ../pci/1b, etc. + */ + sprintf(name, "%d%c", slot, 'a'+func); + if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { + if (!device_vertex) { + return(NULL); + } + } + + return(device_vertex); +} + +/* + * For the given device, initialize the addresses for both the Device(x) Flush + * Write Buffer register and the Xbow Flush Register for the port the PCI bus + * is connected. + */ +static void +set_flush_addresses(struct pci_dev *device_dev, + struct sn_device_sysdata *device_sysdata) +{ + pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); + pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); + pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); + bridge_t *bridge = pcibr_soft->bs_base; + nasid_t nasid; + + /* + * Get the nasid from the bridge. + */ + nasid = NASID_GET(device_sysdata->dma_buf_sync); + if (IS_PIC_DEVICE(device_dev)) { + device_sysdata->dma_buf_sync = (volatile unsigned int *) + &bridge->b_wr_req_buf[pciio_slot].reg; + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(nasid, 0), + pcibr_soft->bs_xid); + } else { + /* + * Accessing Xbridge and Xbow register when SHUB swapoper is on!. + */ + device_sysdata->dma_buf_sync = (volatile unsigned int *) + ((uint64_t)&(bridge->b_wr_req_buf[pciio_slot].reg)^4); + device_sysdata->xbow_buf_sync = (volatile unsigned int *) + ((uint64_t)(XBOW_PRIO_LINKREGS_PTR( + NODE_SWIN_BASE(nasid, 0), pcibr_soft->bs_xid)) ^ 4); + } + +#ifdef DEBUG + printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", + device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); + +printk("set_flush_addresses: dma_buf_sync\n"); + while((volatile unsigned int )*device_sysdata->dma_buf_sync); +printk("set_flush_addresses: xbow_buf_sync\n"); + while((volatile unsigned int )*device_sysdata->xbow_buf_sync); +#endif + +} + +struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; + +// Initialize the data structures for flushing write buffers after a PIO read. +// The theory is: +// Take an unused int. pin and associate it with a pin that is in use. +// After a PIO read, force an interrupt on the unused pin, forcing a write buffer flush +// on the in use pin. This will prevent the race condition between PIO read responses and +// DMA writes. +void +sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot) { + nasid_t nasid; + unsigned long dnasid; + int wid_num; + int bus; + struct sn_flush_device_list *p; + bridge_t *b; + bridgereg_t dev_sel; + extern int isIO9(int); + int bwin; + int i; + + nasid = NASID_GET(start); + wid_num = SWIN_WIDGETNUM(start); + bus = (start >> 23) & 0x1; + bwin = BWIN_WINDOWNUM(start); + + if (flush_nasid_list[nasid].widget_p == NULL) { + flush_nasid_list[nasid].widget_p = (struct sn_flush_device_list **)kmalloc((HUB_WIDGET_ID_MAX+1) * + sizeof(struct sn_flush_device_list *), GFP_KERNEL); + memset(flush_nasid_list[nasid].widget_p, 0, (HUB_WIDGET_ID_MAX+1) * sizeof(struct sn_flush_device_list *)); + } + if (bwin > 0) { + bwin--; + switch (bwin) { + case 0: + flush_nasid_list[nasid].iio_itte1 = HUB_L(IIO_ITTE_GET(nasid, 0)); + wid_num = ((flush_nasid_list[nasid].iio_itte1) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte1 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 1: + flush_nasid_list[nasid].iio_itte2 = HUB_L(IIO_ITTE_GET(nasid, 1)); + wid_num = ((flush_nasid_list[nasid].iio_itte2) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte2 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 2: + flush_nasid_list[nasid].iio_itte3 = HUB_L(IIO_ITTE_GET(nasid, 2)); + wid_num = ((flush_nasid_list[nasid].iio_itte3) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte3 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 3: + flush_nasid_list[nasid].iio_itte4 = HUB_L(IIO_ITTE_GET(nasid, 3)); + wid_num = ((flush_nasid_list[nasid].iio_itte4) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte4 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 4: + flush_nasid_list[nasid].iio_itte5 = HUB_L(IIO_ITTE_GET(nasid, 4)); + wid_num = ((flush_nasid_list[nasid].iio_itte5) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte5 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 5: + flush_nasid_list[nasid].iio_itte6 = HUB_L(IIO_ITTE_GET(nasid, 5)); + wid_num = ((flush_nasid_list[nasid].iio_itte6) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte6 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + case 6: + flush_nasid_list[nasid].iio_itte7 = HUB_L(IIO_ITTE_GET(nasid, 6)); + wid_num = ((flush_nasid_list[nasid].iio_itte7) >> 8) & 0xf; + bus = flush_nasid_list[nasid].iio_itte7 & 0xf; + if (bus == 0x4 || bus == 0x8) + bus = 0; + else + bus = 1; + break; + } + } + + // if it's IO9, bus 1, we don't care about slots 1, 3, and 4. This is + // because these are the IOC4 slots and we don't flush them. + if (isIO9(nasid) && bus == 0 && (slot == 1 || slot == 4)) { + return; + } + if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) { + flush_nasid_list[nasid].widget_p[wid_num] = (struct sn_flush_device_list *)kmalloc( + DEV_PER_WIDGET * sizeof (struct sn_flush_device_list), GFP_KERNEL); + memset(flush_nasid_list[nasid].widget_p[wid_num], 0, + DEV_PER_WIDGET * sizeof (struct sn_flush_device_list)); + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + for (i=0; ibus = -1; + p->pin = -1; + p++; + } + } + + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + for (i=0;ipin == pin && p->bus == bus) break; + if (p->pin < 0) { + p->pin = pin; + p->bus = bus; + break; + } + p++; + } + + for (i=0; ibar_list[i].start == 0) { + p->bar_list[i].start = start; + p->bar_list[i].end = end; + break; + } + } + b = (bridge_t *)(NODE_SWIN_BASE(nasid, wid_num) | (bus << 23) ); + + // If it's IO9, then slot 2 maps to slot 7 and slot 6 maps to slot 8. + // To see this is non-trivial. By drawing pictures and reading manuals and talking + // to HW guys, we can see that on IO9 bus 1, slots 7 and 8 are always unused. + // Further, since we short-circuit slots 1, 3, and 4 above, we only have to worry + // about the case when there is a card in slot 2. A multifunction card will appear + // to be in slot 6 (from an interrupt point of view) also. That's the most we'll + // have to worry about. A four function card will overload the interrupt lines in + // slot 2 and 6. + // We also need to special case the 12160 device in slot 3. Fortunately, we have + // a spare intr. line for pin 4, so we'll use that for the 12160. + // All other buses have slot 3 and 4 and slots 7 and 8 unused. Since we can only + // see slots 1 and 2 and slots 5 and 6 coming through here for those buses (this + // is true only on Pxbricks with 2 physical slots per bus), we just need to add + // 2 to the slot number to find an unused slot. + // We have convinced ourselves that we will never see a case where two different cards + // in two different slots will ever share an interrupt line, so there is no need to + // special case this. + + if (isIO9(nasid) && wid_num == 0xc && bus == 0) { + if (slot == 2) { + p->force_int_addr = (unsigned long)&b->b_force_always[6].intr; + dev_sel = b->b_int_device; + dev_sel |= (1<<18); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[6] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } else if (slot == 3) { /* 12160 SCSI device in IO9 */ + p->force_int_addr = (unsigned long)&b->b_force_always[4].intr; + dev_sel = b->b_int_device; + dev_sel |= (2<<12); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[4] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } else { /* slot == 6 */ + p->force_int_addr = (unsigned long)&b->b_force_always[7].intr; + dev_sel = b->b_int_device; + dev_sel |= (5<<21); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[7] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } + } else { + p->force_int_addr = (unsigned long)&b->b_force_always[pin + 2].intr; + dev_sel = b->b_int_device; + dev_sel |= ((slot - 1) << ( pin * 3) ); + b->b_int_device = dev_sel; + dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); + b->p_int_addr_64[pin + 2] = (virt_to_phys(&p->flush_addr) & 0xfffffffff) | + (dnasid << 36) | (0xfUL << 48); + } +} + +/* + * Most drivers currently do not properly tell the arch specific pci dma + * interfaces whether they can handle A64. Here is where we privately + * keep track of this. + */ +static void __init +set_sn_pci64(struct pci_dev *dev) +{ + unsigned short vendor = dev->vendor; + unsigned short device = dev->device; + + if (vendor == PCI_VENDOR_ID_QLOGIC) { + if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || + (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { + SET_PCIA64(dev); + return; + } + } + + if (vendor == PCI_VENDOR_ID_SGI) { + if (device == PCI_DEVICE_ID_SGI_IOC3) { + SET_PCIA64(dev); + return; + } + } + +} + +/* + * sn_pci_fixup() - This routine is called when platform_pci_fixup() is + * invoked at the end of pcibios_init() to link the Linux pci + * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c + * + * Other platform specific fixup can also be done here. + */ +void +sn_pci_fixup(int arg) +{ + struct list_head *ln; + struct pci_bus *pci_bus = NULL; + struct pci_dev *device_dev = NULL; + struct sn_widget_sysdata *widget_sysdata; + struct sn_device_sysdata *device_sysdata; + pciio_intr_t intr_handle; + int cpuid, bit; + vertex_hdl_t device_vertex; + pciio_intr_line_t lines; + extern void sn_pci_find_bios(void); + extern int numnodes; + int cnode; + + if (arg == 0) { +#ifdef CONFIG_PROC_FS + extern void register_sn_procfs(void); +#endif + + sn_pci_find_bios(); + for (cnode = 0; cnode < numnodes; cnode++) { + extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); + intr_init_vecblk(NODEPDA(cnode), cnode, 0); + } +#ifdef CONFIG_PROC_FS + register_sn_procfs(); +#endif + return; + } + + + done_probing = 1; + + /* + * Initialize the pci bus vertex in the pci_bus struct. + */ + for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { + pci_bus = pci_bus_b(ln); + widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), + GFP_KERNEL); + widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); + pci_bus->sysdata = (void *)widget_sysdata; + } + + /* + * set the root start and end so that drivers calling check_region() + * won't see a conflict + */ + ioport_resource.start = 0xc000000000000000; + ioport_resource.end = 0xcfffffffffffffff; + + /* + * Set the root start and end for Mem Resource. + */ + iomem_resource.start = 0; + iomem_resource.end = 0xffffffffffffffff; + + /* + * Initialize the device vertex in the pci_dev struct. + */ + while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { + unsigned int irq; + int idx; + u16 cmd; + vertex_hdl_t vhdl; + unsigned long size; + extern int bit_pos_to_irq(int); + + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { + extern void pci_fixup_ioc3(struct pci_dev *d); + pci_fixup_ioc3(device_dev); + } + + /* Set the device vertex */ + + device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), + GFP_KERNEL); + device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); + device_sysdata->isa64 = 0; + /* + * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush + * register addresses. + */ + (void) set_flush_addresses(device_dev, device_sysdata); + + device_dev->sysdata = (void *) device_sysdata; + set_sn_pci64(device_dev); + set_isPIC(device_sysdata); + + pci_read_config_word(device_dev, PCI_COMMAND, &cmd); + + /* + * Set the resources address correctly. The assumption here + * is that the addresses in the resource structure has been + * read from the card and it was set in the card by our + * Infrastructure .. + */ + vhdl = device_sysdata->vhdl; + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + size = 0; + size = device_dev->resource[idx].end - + device_dev->resource[idx].start; + if (size) { + device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; + } + else + continue; + + device_dev->resource[idx].end = + device_dev->resource[idx].start + size; + + if (device_dev->resource[idx].flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + + if (device_dev->resource[idx].flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } +#if 0 + /* + * Software WAR for a Software BUG. + * This is only temporary. + * See PV 872791 + */ + + /* + * Now handle the ROM resource .. + */ + size = device_dev->resource[PCI_ROM_RESOURCE].end - + device_dev->resource[PCI_ROM_RESOURCE].start; + + if (size) { + device_dev->resource[PCI_ROM_RESOURCE].start = + (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, + size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); + device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; + device_dev->resource[PCI_ROM_RESOURCE].end = + device_dev->resource[PCI_ROM_RESOURCE].start + size; + } +#endif + + /* + * Update the Command Word on the Card. + */ + cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ + /* bit gets dropped .. no harm */ + pci_write_config_word(device_dev, PCI_COMMAND, cmd); + + pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); + if (device_dev->vendor == PCI_VENDOR_ID_SGI && + device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { + lines = 1; + } + + device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; + device_vertex = device_sysdata->vhdl; + + irqpdaindr->current = device_dev; + intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); + + irq = intr_handle->pi_irq; + irqpdaindr->device_dev[irq] = device_dev; + cpuid = intr_handle->pi_cpu; + pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0); + device_dev->irq = irq; + register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); + + for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { + int ibits = ((pcibr_intr_t)intr_handle)->bi_ibits; + int i; + + size = device_dev->resource[idx].end - + device_dev->resource[idx].start; + if (size == 0) continue; + + for (i=0; i<8; i++) { + if (ibits & (1 << i) ) { + sn_dma_flush_init(device_dev->resource[idx].start, + device_dev->resource[idx].end, + idx, + i, + PCI_SLOT(device_dev->devfn)); + } + } + } + + } +#ifdef ajmtestintr + { + int slot = PCI_SLOT(device_dev->devfn); + static int timer_set = 0; + pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; + pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; + extern void intr_test_handle_intr(int, void*, struct pt_regs *); + + if (!timer_set) { + intr_test_set_timer(); + timer_set = 1; + } + intr_test_register_irq(irq, pcibr_soft, slot); + request_irq(irq, intr_test_handle_intr,0,NULL, NULL); + } +#endif +} + +/* + * linux_bus_cvlink() Creates a link between the Linux PCI Bus number + * to the actual hardware component that it represents: + * /dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci + * + * The bus vertex, when called to devfs_generate_path() returns: + * hw/module/001c01/slab/0/Ibrick/xtalk/15/pci + * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/0 + * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/1 + */ +void +linux_bus_cvlink(void) +{ + char name[8]; + int index; + + for (index=0; index < MAX_PCI_XWIDGET; index++) { + if (!busnum_to_pcibr_vhdl[index]) + continue; + + sprintf(name, "%x", index); + (void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], + name); + } +} + +/* + * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. + * + * Linux PCI Bus numbers are assigned from lowest module_id numbers + * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to + * HUB_WIDGET_ID_MIN: + * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. + * + * Given 2 modules 001c01 and 001c02 we get the following mappings: + * 001c01, widgetnum 15 = Bus number 0 + * 001c01, widgetnum 14 = Bus number 1 + * 001c02, widgetnum 15 = Bus number 3 + * 001c02, widgetnum 14 = Bus number 4 + * etc. + * + * The rational for starting Bus Number 0 with Widget number 15 is because + * the system boot disks are always connected via Widget 15 Slot 0 of the + * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 + * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest + * module id(Master Cnode) of the system. + * + */ +static int +pci_bus_map_create(vertex_hdl_t xtalk, char * io_moduleid) +{ + + vertex_hdl_t master_node_vertex = NULL; + vertex_hdl_t xwidget = NULL; + vertex_hdl_t pci_bus = NULL; + hubinfo_t hubinfo = NULL; + xwidgetnum_t widgetnum; + char pathname[128]; + graph_error_t rv; + int bus; + int basebus_num; + extern void ioconfig_get_busnum(char *, int *); + + int bus_number; + + /* + * Loop throught this vertex and get the Xwidgets .. + */ + + + /* PCI devices */ + + for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { + sprintf(pathname, "%d", widgetnum); + xwidget = NULL; + + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device + */ + rv = hwgraph_traverse(xtalk, pathname, &xwidget); + if ( (rv != GRAPH_SUCCESS) ) { + if (!xwidget) { + continue; + } + } + + sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + pci_bus = NULL; + if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) + if (!pci_bus) { + continue; +} + + /* + * Assign the correct bus number and also the nasid of this + * pci Xwidget. + * + * Should not be any race here ... + */ + num_bridges++; + busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; + + /* + * Get the master node and from there get the NASID. + */ + master_node_vertex = device_master_get(xwidget); + if (!master_node_vertex) { + printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); + } + + hubinfo_get(master_node_vertex, &hubinfo); + if (!hubinfo) { + printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); + return(1); + } else { + busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; + } + + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); + if (!busnum_to_atedmamaps[num_bridges - 1]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); + + memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); + + } + + /* + * PCIX devices + * We number busses differently for PCI-X devices. + * We start from Lowest Widget on up .. + */ + + (void) ioconfig_get_busnum((char *)io_moduleid, &basebus_num); + + for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { + + /* Do both buses */ + for ( bus = 0; bus < 2; bus++ ) { + sprintf(pathname, "%d", widgetnum); + xwidget = NULL; + + /* + * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget + * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus + * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device + */ + rv = hwgraph_traverse(xtalk, pathname, &xwidget); + if ( (rv != GRAPH_SUCCESS) ) { + if (!xwidget) { + continue; + } + } + + if ( bus == 0 ) + sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); + else + sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); + pci_bus = NULL; + if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) + if (!pci_bus) { + continue; + } + + /* + * Assign the correct bus number and also the nasid of this + * pci Xwidget. + * + * Should not be any race here ... + */ + bus_number = basebus_num + bus + io_brick_map_widget(MODULE_PXBRICK, widgetnum); +#ifdef DEBUG + printk("bus_number %d basebus_num %d bus %d io %d\n", + bus_number, basebus_num, bus, + io_brick_map_widget(MODULE_PXBRICK, widgetnum)); +#endif + busnum_to_pcibr_vhdl[bus_number] = pci_bus; + + /* + * Pre assign DMA maps needed for 32 Bits Page Map DMA. + */ + busnum_to_atedmamaps[bus_number] = (void *) kmalloc( + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); + if (!busnum_to_atedmamaps[bus_number]) + printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); + + memset(busnum_to_atedmamaps[bus_number], 0x0, + sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); + } + } + + return(0); +} + +/* + * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure + * initialization has completed to set up the mappings between Xbridge + * and logical pci bus numbers. We also set up the NASID for each of these + * xbridges. + * + * Must be called before pci_init() is invoked. + */ +int +pci_bus_to_hcl_cvlink(void) +{ + + vertex_hdl_t devfs_hdl = NULL; + vertex_hdl_t xtalk = NULL; + int rv = 0; + char name[256]; + char tmp_name[256]; + int i, ii, j; + char *brick_name; + extern void ioconfig_bus_new_entries(void); + + /* + * Figure out which IO Brick is connected to the Compute Bricks. + */ + for (i = 0; i < nummodules; i++) { + extern int iomoduleid_get(nasid_t); + moduleid_t iobrick_id; + nasid_t nasid = -1; + int nodecnt; + int n = 0; + + nodecnt = modules[i]->nodecnt; + for ( n = 0; n < nodecnt; n++ ) { + nasid = cnodeid_to_nasid(modules[i]->nodes[n]); + iobrick_id = iomoduleid_get(nasid); + if ((int)iobrick_id > 0) { /* Valid module id */ + char name[12]; + memset(name, 0, 12); + format_module_id((char *)&(modules[i]->io[n].moduleid), iobrick_id, MODULE_FORMAT_BRIEF); + } + } + } + + devfs_hdl = hwgraph_path_to_vertex("hw/module"); + for (i = 0; i < nummodules ; i++) { + for ( j = 0; j < 3; j++ ) { + if ( j == 0 ) + brick_name = EDGE_LBL_PBRICK; + else if ( j == 1 ) + brick_name = EDGE_LBL_PXBRICK; + else + brick_name = EDGE_LBL_IXBRICK; + + for ( ii = 0; ii < 2 ; ii++ ) { + memset(name, 0, 256); + memset(tmp_name, 0, 256); + format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); + sprintf(tmp_name, "/slab/%d/%s/xtalk", geo_slab(modules[i]->geoid[ii]), brick_name); + strcat(name, tmp_name); + xtalk = NULL; + rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); + if ( rv == 0 ) + pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); + } + } + } + + /* + * Create the Linux PCI bus number vertex link. + */ + (void)linux_bus_cvlink(); + (void)ioconfig_bus_new_entries(); + + return(0); +} diff -Nru a/arch/ia64/sn/io/machvec/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/machvec/pci_dma.c Fri May 23 03:52:29 2003 @@ -0,0 +1,705 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. + * + * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for + * a description of how these routines should be used. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * For ATE allocations + */ +pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); +void free_pciio_dmamap(pcibr_dmamap_t); +static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); +void sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); + +/* + * Toplogy stuff + */ +extern vertex_hdl_t busnum_to_pcibr_vhdl[]; +extern nasid_t busnum_to_nid[]; +extern void * busnum_to_atedmamaps[]; + +/** + * get_free_pciio_dmamap - find and allocate an ATE + * @pci_bus: PCI bus to get an entry for + * + * Finds and allocates an ATE on the PCI bus specified + * by @pci_bus. + */ +pciio_dmamap_t +get_free_pciio_dmamap(vertex_hdl_t pci_bus) +{ + int i; + struct sn_dma_maps_s *sn_dma_map = NULL; + + /* + * Darn, we need to get the maps allocated for this bus. + */ + for (i = 0; i < MAX_PCI_XWIDGET; i++) { + if (busnum_to_pcibr_vhdl[i] == pci_bus) { + sn_dma_map = busnum_to_atedmamaps[i]; + } + } + + /* + * Now get a free dmamap entry from this list. + */ + for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { + if (!sn_dma_map->dma_addr) { + sn_dma_map->dma_addr = -1; + return( (pciio_dmamap_t) sn_dma_map ); + } + } + + return NULL; +} + +/** + * free_pciio_dmamap - free an ATE + * @dma_map: ATE to free + * + * Frees the ATE specified by @dma_map. + */ +void +free_pciio_dmamap(pcibr_dmamap_t dma_map) +{ + struct sn_dma_maps_s *sn_dma_map; + + sn_dma_map = (struct sn_dma_maps_s *) dma_map; + sn_dma_map->dma_addr = 0; +} + +/** + * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum + * @dma_addr: DMA address to look for + * @busnum: PCI bus to look on + * + * Finds the ATE associated with @dma_addr and @busnum. + */ +static struct sn_dma_maps_s * +find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) +{ + + struct sn_dma_maps_s *sn_dma_map = NULL; + int i; + + sn_dma_map = busnum_to_atedmamaps[busnum]; + + for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { + if (sn_dma_map->dma_addr == dma_addr) { + return sn_dma_map; + } + } + + return NULL; +} + +/** + * sn_pci_alloc_consistent - allocate memory for coherent DMA + * @hwdev: device to allocate for + * @size: size of the region + * @dma_handle: DMA (bus) address + * + * pci_alloc_consistent() returns a pointer to a memory region suitable for + * coherent DMA traffic to/from a PCI device. On SN platforms, this means + * that @dma_handle will have the %PCIIO_DMA_CMD flag set. + * + * This interface is usually used for "command" streams (e.g. the command + * queue for a SCSI controller). See Documentation/DMA-mapping.txt for + * more information. Note that this routine will always put a 32 bit + * DMA address into @dma_handle. This is because most devices + * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_ + * DMAs, and unfortunately this interface has to cater to the LCD. Oh well. + * + * Also known as platform_pci_alloc_consistent() by the IA64 machvec code. + */ +void * +sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +{ + void *cpuaddr; + vertex_hdl_t vhdl; + struct sn_device_sysdata *device_sysdata; + unsigned long phys_addr; + pciio_dmamap_t dma_map = 0; + struct sn_dma_maps_s *sn_dma_map; + + *dma_handle = 0; + + /* We can't easily support < 32 bit devices */ + if (IS_PCI32L(hwdev)) + return NULL; + + /* + * Get hwgraph vertex for the device + */ + device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; + vhdl = device_sysdata->vhdl; + + /* + * Allocate the memory. FIXME: if we're allocating for + * two devices on the same bus, we should at least try to + * allocate memory in the same 2 GB window to avoid using + * ATEs for the translation. See the comment above about the + * 32 bit requirement for this function. + */ + if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) + return NULL; + + memset(cpuaddr, 0, size); /* have to zero it out */ + + /* physical addr. of the memory we just got */ + phys_addr = __pa(cpuaddr); + + /* + * This will try to use a Direct Map register to do the + * 32 bit DMA mapping, but it may not succeed if another + * device on the same bus is already mapped with different + * attributes or to a different memory region. + */ + *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_CMD); + + /* + * It is a 32 bit card and we cannot do direct mapping, + * so we try to use an ATE. + */ + if (!(*dma_handle)) { + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_CMD); + if (!dma_map) { + printk(KERN_ERR "sn_pci_alloc_consistent: Unable to " + "allocate anymore 32 bit page map entries.\n"); + return 0; + } + *dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr, + size); + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = *dma_handle; + } + + return cpuaddr; +} + +/** + * sn_pci_free_consistent - free memory associated with coherent DMAable region + * @hwdev: device to free for + * @size: size to free + * @vaddr: kernel virtual address to free + * @dma_handle: DMA address associated with this region + * + * Frees the memory allocated by pci_alloc_consistent(). Also known + * as platform_pci_free_consistent() by the IA64 machvec code. + */ +void +sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +{ + struct sn_dma_maps_s *sn_dma_map = NULL; + + /* + * Get the sn_dma_map entry. + */ + if (IS_PCI32_MAPPED(dma_handle)) + sn_dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number); + + /* + * and free it if necessary... + */ + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; + } + free_pages((unsigned long) vaddr, get_order(size)); +} + +/** + * sn_pci_map_sg - map a scatter-gather list for DMA + * @hwdev: device to map for + * @sg: scatterlist to map + * @nents: number of entries + * @direction: direction of the DMA transaction + * + * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the + * IA64 machvec code. + */ +int +sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + + int i; + vertex_hdl_t vhdl; + unsigned long phys_addr; + struct sn_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map; + struct sn_dma_maps_s *sn_dma_map; + struct scatterlist *saved_sg = sg; + + /* can't go anywhere w/o a direction in life */ + if (direction == PCI_DMA_NONE) + BUG(); + + /* + * Get the hwgraph vertex for the device + */ + device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; + vhdl = device_sysdata->vhdl; + + /* + * Setup a DMA address for each entry in the + * scatterlist. + */ + for (i = 0; i < nents; i++, sg++) { + phys_addr = __pa(sg->dma_address ? sg->dma_address : + page_address(sg->page) + sg->offset); + + /* + * Handle the most common case: 64 bit cards. This + * call should always succeed. + */ + if (IS_PCIA64(hwdev)) { + sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA | + PCIIO_DMA_A64); + sg->dma_length = sg->length; + continue; + } + + /* + * Handle 32-63 bit cards via direct mapping + */ + if (IS_PCI32G(hwdev)) { + sg->dma_address = pciio_dmatrans_addr(vhdl, NULL, phys_addr, + sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); + sg->dma_length = sg->length; + /* + * See if we got a direct map entry + */ + if (sg->dma_address) { + continue; + } + + } + + /* + * It is a 32 bit card and we cannot do direct mapping, + * so we use an ATE. + */ + dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); + if (!dma_map) { + printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " + "anymore 32 bit page map entries.\n"); + /* + * We will need to free all previously allocated entries. + */ + if (i > 0) { + sn_pci_unmap_sg(hwdev, saved_sg, i, direction); + } + return (0); + } + + sg->dma_address = pciio_dmamap_addr(dma_map, phys_addr, sg->length); + sg->dma_length = sg->length; + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = sg->dma_address; + } + + return nents; + +} + +/** + * sn_pci_unmap_sg - unmap a scatter-gather list + * @hwdev: device to unmap + * @sg: scatterlist to unmap + * @nents: number of scatterlist entries + * @direction: DMA direction + * + * Unmap a set of streaming mode DMA translations. Again, cpu read rules + * concerning calls here are the same as for pci_unmap_single() below. Also + * known as sn_pci_unmap_sg() by the IA64 machvec code. + */ +void +sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + int i; + struct sn_dma_maps_s *sn_dma_map; + + /* can't go anywhere w/o a direction in life */ + if (direction == PCI_DMA_NONE) + BUG(); + + for (i = 0; i < nents; i++, sg++){ + + if (IS_PCI32_MAPPED(sg->dma_address)) { + sn_dma_map = NULL; + sn_dma_map = find_sn_dma_map(sg->dma_address, hwdev->bus->number); + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; + } + } + + sg->dma_address = (dma_addr_t)NULL; + sg->dma_length = 0; + } +} + +/** + * sn_pci_map_single - map a single region for DMA + * @hwdev: device to map for + * @ptr: kernel virtual address of the region to map + * @size: size of the region + * @direction: DMA direction + * + * Map the region pointed to by @ptr for DMA and return the + * DMA address. Also known as platform_pci_map_single() by + * the IA64 machvec code. + * + * We map this to the one step pciio_dmamap_trans interface rather than + * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have + * no way of saving the dmamap handle from the alloc to later free + * (which is pretty much unacceptable). + * + * TODO: simplify our interface; + * get rid of dev_desc and vhdl (seems redundant given a pci_dev); + * figure out how to save dmamap handle so can use two step. + */ +dma_addr_t +sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) +{ + vertex_hdl_t vhdl; + dma_addr_t dma_addr; + unsigned long phys_addr; + struct sn_device_sysdata *device_sysdata; + pciio_dmamap_t dma_map = NULL; + struct sn_dma_maps_s *sn_dma_map; + + if (direction == PCI_DMA_NONE) + BUG(); + + /* SN cannot support DMA addresses smaller than 32 bits. */ + if (IS_PCI32L(hwdev)) + return 0; + + /* + * find vertex for the device + */ + device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; + vhdl = device_sysdata->vhdl; + + /* + * Call our dmamap interface + */ + dma_addr = 0; + phys_addr = __pa(ptr); + + if (IS_PCIA64(hwdev)) { + /* This device supports 64 bit DMA addresses. */ + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA | + PCIIO_DMA_A64); + return dma_addr; + } + + /* + * Devices that support 32 bit to 63 bit DMA addresses get + * 32 bit DMA addresses. + * + * First try to get a 32 bit direct map register. + */ + if (IS_PCI32G(hwdev)) { + dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); + if (dma_addr) + return dma_addr; + } + + /* + * It's a 32 bit card and we cannot do direct mapping so + * let's use the PMU instead. + */ + dma_map = NULL; + dma_map = pciio_dmamap_alloc(vhdl, NULL, size, + ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | + PCIIO_DMA_DATA); + + if (!dma_map) { + printk(KERN_ERR "pci_map_single: Unable to allocate anymore " + "32 bit page map entries.\n"); + return 0; + } + + dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size); + sn_dma_map = (struct sn_dma_maps_s *)dma_map; + sn_dma_map->dma_addr = dma_addr; + + return ((dma_addr_t)dma_addr); +} + +/** + * sn_pci_unmap_single - unmap a region used for DMA + * @hwdev: device to unmap + * @dma_addr: DMA address to unmap + * @size: size of region + * @direction: DMA direction + * + * Unmaps the region pointed to by @dma_addr. Also known as + * platform_pci_unmap_single() by the IA64 machvec code. + */ +void +sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +{ + struct sn_dma_maps_s *sn_dma_map = NULL; + + if (direction == PCI_DMA_NONE) + BUG(); + + /* + * Get the sn_dma_map entry. + */ + if (IS_PCI32_MAPPED(dma_addr)) + sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number); + + /* + * and free it if necessary... + */ + if (sn_dma_map) { + pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); + pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); + sn_dma_map->dma_addr = (dma_addr_t)NULL; + } +} + +/** + * sn_pci_dma_sync_single - make sure all DMAs have completed + * @hwdev: device to sync + * @dma_handle: DMA address to sync + * @size: size of region + * @direction: DMA direction + * + * This routine is supposed to sync the DMA region specified + * by @dma_handle into the 'coherence domain'. We do not need to do + * anything on our platform. + */ +void +sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +{ + return; + +} + +/** + * sn_pci_dma_sync_sg - make sure all DMAs have completed + * @hwdev: device to sync + * @sg: scatterlist to sync + * @nents: number of entries in the scatterlist + * @direction: DMA direction + * + * This routine is supposed to sync the DMA regions specified + * by @sg into the 'coherence domain'. We do not need to do anything + * on our platform. + */ +void +sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + return; + +} + +/** + * sn_dma_supported - test a DMA mask + * @hwdev: device to test + * @mask: DMA mask to test + * + * Return whether the given PCI device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during PCI bus mastering, then you would pass 0x00ffffff as the mask to + * this function. Of course, SN only supports devices that have 32 or more + * address bits when using the PMU. We could theoretically support <32 bit + * cards using direct mapping, but we'll worry about that later--on the off + * chance that someone actually wants to use such a card. + */ +int +sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) +{ + if (mask < 0xffffffff) + return 0; + return 1; +} + +#ifdef CONFIG_PCI + +/* + * New generic DMA routines just wrap sn2 PCI routines until we + * support other bus types (if ever). + */ + +int +sn_dma_supported(struct device *dev, u64 mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_dma_supported(to_pci_dev(dev), mask); +} +EXPORT_SYMBOL(sn_dma_supported); + +int +sn_dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +} +EXPORT_SYMBOL(sn_dma_set_mask); + +void * +sn_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + int flag) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); +} +EXPORT_SYMBOL(sn_dma_alloc_coherent); + +void +sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); +} +EXPORT_SYMBOL(sn_dma_free_coherent); + +dma_addr_t +sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_single); + +void +sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_single); + +dma_addr_t +sn_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_page); + +void +sn_dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_page); + +int +sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); +} +EXPORT_SYMBOL(sn_dma_map_sg); + +void +sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); +} +EXPORT_SYMBOL(sn_dma_unmap_sg); + +void +sn_dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_single); + +void +sn_dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_sg); + +#endif /* CONFIG_PCI */ + +EXPORT_SYMBOL(sn_pci_unmap_single); +EXPORT_SYMBOL(sn_pci_map_single); +EXPORT_SYMBOL(sn_pci_dma_sync_single); +EXPORT_SYMBOL(sn_pci_map_sg); +EXPORT_SYMBOL(sn_pci_unmap_sg); +EXPORT_SYMBOL(sn_pci_alloc_consistent); +EXPORT_SYMBOL(sn_pci_free_consistent); +EXPORT_SYMBOL(sn_pci_dma_supported); + diff -Nru a/arch/ia64/sn/io/ml_SN_init.c b/arch/ia64/sn/io/ml_SN_init.c --- a/arch/ia64/sn/io/ml_SN_init.c Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,235 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int numcpus; -extern char arg_maxnodes[]; -extern cpuid_t master_procid; -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif - -extern int hasmetarouter; - -int maxcpus; -cpumask_t boot_cpumask; -hubreg_t region_mask = 0; - - -extern xwidgetnum_t hub_widget_id(nasid_t); - -extern int valid_icache_reasons; /* Reasons to flush the icache */ -extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern u_char miniroot; -extern volatile int need_utlbmiss_patch; -extern void iograph_early_init(void); - -nasid_t master_nasid = INVALID_NASID; - - -/* - * mlreset(int slave) - * very early machine reset - at this point NO interrupts have been - * enabled; nor is memory, tlb, p0, etc setup. - * - * slave is zero when mlreset is called for the master processor and - * is nonzero thereafter. - */ - - -void -mlreset(int slave) -{ - if (!slave) { - /* - * We are the master cpu and node. - */ - master_nasid = get_nasid(); - set_master_bridge_base(); - - /* We're the master processor */ - master_procid = smp_processor_id(); - master_nasid = cpuid_to_nasid(master_procid); - - /* - * master_nasid we get back better be same as one from - * get_nasid() - */ - ASSERT_ALWAYS(master_nasid == get_nasid()); - - /* early initialization of iograph */ - iograph_early_init(); - - /* Initialize Hub Pseudodriver Management */ - hubdev_init(); - - } else { /* slave != 0 */ - /* - * This code is performed ONLY by slave processors. - */ - - } -} - - -/* XXX - Move the meat of this to intr.c ? */ -/* - * Set up the platform-dependent fields in the nodepda. - */ -void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) -{ - hubinfo_t hubinfo; -#ifdef CONFIG_IA64_SGI_SN1 - int sn; -#endif - - extern void router_map_init(nodepda_t *); - extern void router_queue_init(nodepda_t *,cnodeid_t); - extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int); - - /* Allocate per-node platform-dependent data */ - hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); - - npda->pdinfo = (void *)hubinfo; - hubinfo->h_nodepda = npda; - hubinfo->h_cnodeid = node; - hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node); - - spin_lock_init(&hubinfo->h_crblock); - - hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); - npda->xbow_peer = INVALID_NASID; - - /* - * Initialize the linked list of - * router info pointers to the dependent routers - */ - npda->npda_rip_first = NULL; - - /* - * npda_rip_last always points to the place - * where the next element is to be inserted - * into the list - */ - npda->npda_rip_last = &npda->npda_rip_first; - npda->module_id = INVALID_MODULE; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Initialize the interrupts. - * On sn2, this is done at pci init time, - * because sn2 needs the cpus checked in - * when it initializes interrupts. This is - * so we don't see all the nodes as headless. - */ - for (sn=0; snxbow_sema); /* init it locked? */ - -#ifdef LATER - - /* Setup the (module,slot) --> nic mapping for all the routers - * in the system. This is useful during error handling when - * there is no shared memory. - */ - router_map_init(npda); - - /* Allocate memory for the per-node router traversal queue */ - router_queue_init(npda,node); - npda->sbe_info = alloc_bootmem_node(NODE_DATA(node), sizeof (sbe_info_t)); - ASSERT(npda->sbe_info); - -#endif /* LATER */ -} - -/* XXX - Move the interrupt stuff to intr.c ? */ -/* - * Set up the platform-dependent fields in the processor pda. - * Must be done _after_ init_platform_nodepda(). - * If we need a lock here, something else is wrong! - */ -void init_platform_pda(cpuid_t cpu) -{ -#if defined(CONFIG_IA64_SGI_SN1) - hub_intmasks_t *intmasks; - int i, subnode; - cnodeid_t cnode; - synergy_da_t *sda; - int which_synergy; - - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - intmasks = &sda->s_intmasks; - - /* Clear INT_PEND0 masks. */ - for (i = 0; i < N_INTPEND0_MASKS; i++) - intmasks->intpend0_masks[i] = 0; - - /* Set up pointer to the vector block in the nodepda. */ - /* (Cant use SUBNODEPDA - not working yet) */ - subnode = cpuid_to_subnode(cpu); - intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0; - intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1; - if (intmasks->dispatch0 != &SUBNODEPDA(cnode, subnode)->intr_dispatch0 || - intmasks->dispatch1 != &SUBNODEPDA(cnode, subnode)->intr_dispatch1) - panic("xxx"); - intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0; - intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1; - - /* Clear INT_PEND1 masks. */ - for (i = 0; i < N_INTPEND1_MASKS; i++) - intmasks->intpend1_masks[i] = 0; -#endif /* CONFIG_IA64_SGI_SN1 */ -} - -void -update_node_information(cnodeid_t cnodeid) -{ - nodepda_t *npda = NODEPDA(cnodeid); - nodepda_router_info_t *npda_rip; - - /* Go through the list of router info - * structures and copy some frequently - * accessed info from the info hanging - * off the corresponding router vertices - */ - npda_rip = npda->npda_rip_first; - while(npda_rip) { - if (npda_rip->router_infop) { - npda_rip->router_portmask = - npda_rip->router_infop->ri_portmask; - npda_rip->router_slot = - npda_rip->router_infop->ri_slotnum; - } else { - /* No router, no ports. */ - npda_rip->router_portmask = 0; - } - npda_rip = npda_rip->router_next; - } -} diff -Nru a/arch/ia64/sn/io/ml_iograph.c b/arch/ia64/sn/io/ml_iograph.c --- a/arch/ia64/sn/io/ml_iograph.c Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1570 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IOGRAPH_DEBUG */ -#ifdef IOGRAPH_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* IOGRAPH_DEBUG */ - -/* #define PROBE_TEST */ - -/* At most 2 hubs can be connected to an xswitch */ -#define NUM_XSWITCH_VOLUNTEER 2 - -/* - * Track which hubs have volunteered to manage devices hanging off of - * a Crosstalk Switch (e.g. xbow). This structure is allocated, - * initialized, and hung off the xswitch vertex early on when the - * xswitch vertex is created. - */ -typedef struct xswitch_vol_s { - mutex_t xswitch_volunteer_mutex; - int xswitch_volunteer_count; - devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; -} *xswitch_vol_t; - -void -xswitch_vertex_init(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - mutex_init(&xvolinfo->xswitch_volunteer_mutex); - xvolinfo->xswitch_volunteer_count = 0; - rc = hwgraph_info_add_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t)xvolinfo); - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -} - - -/* - * When assignment of hubs to widgets is complete, we no longer need the - * xswitch volunteer structure hanging around. Destroy it. - */ -static void -xswitch_volunteer_delete(devfs_handle_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - rc = hwgraph_info_remove_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); -#ifdef LATER - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -#endif - - kfree(xvolinfo); -} -/* - * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. - */ -/* ARGSUSED */ -static void -volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) -{ - xswitch_vol_t xvolinfo = NULL; - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(master)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "volunteer for widgets: vertex %v has no info label", - xswitch); -#else - printk(KERN_WARNING "volunteer for widgets: vertex 0x%x has no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - mutex_lock(&xvolinfo->xswitch_volunteer_mutex); - ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); - xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; - xvolinfo->xswitch_volunteer_count++; - mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); -} - -extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); - -/* - * Assign all the xwidgets hanging off the specified xswitch to the - * Crosstalk masters that have volunteered for xswitch duty. - */ -/* ARGSUSED */ -static void -assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) -{ - int curr_volunteer, num_volunteer; - xwidgetnum_t widgetnum; - xswitch_info_t xswitch_info; - xswitch_vol_t xvolinfo = NULL; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - xswitch_info = xswitch_info_get(xswitch); - ASSERT(xswitch_info != NULL); - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { -#ifdef LATER - if (!is_headless_node_vertex(hubv)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has " - " no info label", - xswitch); -#else - printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has " - " no info label", - xswitch); -#endif - } -#endif /* LATER */ - return; - } - - num_volunteer = xvolinfo->xswitch_volunteer_count; - ASSERT(num_volunteer > 0); - curr_volunteer = 0; - - /* Assign master hub for xswitch itself. */ - if (HUB_WIDGET_ID_MIN > 0) { - hubv = xvolinfo->xswitch_volunteer[0]; - xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); - } - - /* - * TBD: Use administrative information to alter assignment of - * widgets to hubs. - */ - for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - - /* - * Ignore disabled/empty ports. - */ - if (!xbow_port_io_enabled(nasid, widgetnum)) - continue; - - /* - * If this is the master IO board, assign it to the same - * hub that owned it in the prom. - */ - if (is_master_nasid_widget(nasid, widgetnum)) { - int i; - - for (i=0; ixswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (nasid == get_console_nasid()) - goto do_assignment; - } -#ifdef LATER - PRINT_PANIC("Nasid == %d, console nasid == %d", - nasid, get_console_nasid()); -#endif - } - - - /* - * Do a round-robin assignment among the volunteer nodes. - */ - hubv = xvolinfo->xswitch_volunteer[curr_volunteer]; - curr_volunteer = (curr_volunteer + 1) % num_volunteer; - /* fall through */ - -do_assignment: - /* - * At this point, we want to make hubv the master of widgetnum. - */ - xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); - } - - xswitch_volunteer_delete(xswitch); -} - -/* - * Early iograph initialization. Called by master CPU in mlreset(). - * Useful for including iograph.o in kernel.o. - */ -void -iograph_early_init(void) -{ -/* - * Need new way to get this information .. - */ - cnodeid_t cnode; - nasid_t nasid; - lboard_t *board; - - /* - * Init. the board-to-hwgraph link early, so FRU analyzer - * doesn't trip on leftover values if we panic early on. - */ - for(cnode = 0; cnode < numnodes; cnode++) { - nasid = COMPACT_TO_NASID_NODEID(cnode); - board = (lboard_t *)KL_CONFIG_INFO(nasid); - DBG("iograph_early_init: Found board 0x%p\n", board); - - /* Check out all the board info stored on a node */ - while(board) { - board->brd_graph_link = GRAPH_VERTEX_NONE; - board = KLCF_NEXT(board); - DBG("iograph_early_init: Found board 0x%p\n", board); - - - } - } - - hubio_init(); -} - -#ifdef LINUX_KERNEL_THREADS -static struct semaphore io_init_sema; -#endif - -/* - * Let boot processor know that we're done initializing our node's IO - * and then exit. - */ -/* ARGSUSED */ -static void -io_init_done(cnodeid_t cnodeid,cpu_cookie_t c) -{ - /* Let boot processor know that we're done. */ -#ifdef LINUX_KERNEL_THREADS - up(&io_init_sema); -#endif -#ifdef LATER - /* This is for the setnoderun done when the io_init thread - * started - */ - restorenoderun(c); - sthread_exit(); -#endif -} - -/* - * Probe to see if this hub's xtalk link is active. If so, - * return the Crosstalk Identification of the widget that we talk to. - * This is called before any of the Crosstalk infrastructure for - * this hub is set up. It's usually called on the node that we're - * probing, but not always. - * - * TBD: Prom code should actually do this work, and pass through - * hwid for our use. - */ -static void -early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) -{ - hubreg_t llp_csr_reg; - nasid_t nasid; - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - /* - * If link is up, read the widget's part number. - * A direct connect widget must respond to widgetnum=0. - */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { - /* TBD: Put hub into "indirect" mode */ - /* - * We're able to read from a widget because our hub's - * WIDGET_ID was set up earlier. - */ - widgetreg_t widget_id = *(volatile widgetreg_t *) - (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); - - DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, - (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); - - hwid->part_num = XWIDGET_PART_NUM(widget_id); - hwid->rev_num = XWIDGET_REV_NUM(widget_id); - hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); - - /* TBD: link reset */ - } else { - - hwid->part_num = XWIDGET_PART_NUM_NONE; - hwid->rev_num = XWIDGET_REV_NUM_NONE; - hwid->mfg_num = XWIDGET_MFG_NUM_NONE; - } - -} - -/* Add inventory information to the widget vertex - * Right now (module,slot,revision) is being - * added as inventory information. - */ -static void -xwidget_inventory_add(devfs_handle_t widgetv, - lboard_t *board, - struct xwidget_hwid_s hwid) -{ - if (!board) - return; - /* Donot add inventory information for the baseio - * on a speedo with an xbox. It has already been - * taken care of in SN00_vmc. - * Speedo with xbox's baseio comes in at slot io1 (widget 9) - */ - device_inventory_add(widgetv,INV_IOBD,board->brd_type, - board->brd_module, - SLOTNUM_GETSLOT(board->brd_slot), - hwid.rev_num); -} - -/* - * io_xswitch_widget_init - * - */ - -/* defined in include/linux/ctype.h */ -/* #define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) */ - -void -io_xswitch_widget_init(devfs_handle_t xswitchv, - devfs_handle_t hubv, - xwidgetnum_t widgetnum, - async_attach_t aa) -{ - xswitch_info_t xswitch_info; - xwidgetnum_t hub_widgetid; - devfs_handle_t widgetv; - cnodeid_t cnode; - widgetreg_t widget_id; - nasid_t nasid, peer_nasid; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - /*REFERENCED*/ - int rc; - char slotname[SLOTNUM_MAXLENGTH]; - char pathname[128]; - char new_name[64]; - moduleid_t module; - slotid_t slot; - lboard_t *board = NULL; - char buffer[16]; - slotid_t get_widget_slotnum(int xbow, int widget); - - DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); - /* - * Verify that xswitchv is indeed an attached xswitch. - */ - xswitch_info = xswitch_info_get(xswitchv); - ASSERT(xswitch_info != NULL); - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - cnode = NASID_TO_COMPACT_NODEID(nasid); - hub_widgetid = hubinfo->h_widgetid; - - - /* Who's the other guy on out crossbow (if anyone) */ - peer_nasid = NODEPDA(cnode)->xbow_peer; - if (peer_nasid == INVALID_NASID) - /* If I don't have a peer, use myself. */ - peer_nasid = nasid; - - - /* Check my xbow structure and my peer's */ - if (!xbow_port_io_enabled(nasid, widgetnum) && - !xbow_port_io_enabled(peer_nasid, widgetnum)) { - return; - } - - if (xswitch_info_link_ok(xswitch_info, widgetnum)) { - char name[4]; - /* - * If the current hub is not supposed to be the master - * for this widgetnum, then skip this widget. - */ - if (xswitch_info_master_assignment_get(xswitch_info, - widgetnum) != hubv) { - return; - } - - module = NODEPDA(cnode)->module_id; -#ifdef XBRIDGE_REGS_SIM - /* hardwire for now...could do this with something like: - * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl); - * xbow_t xbow = soft->base; - * xbowreg_t xwidget_id = xbow->xb_wid_id; - * but I don't feel like figuring out vhdl right now.. - * and I know for a fact the answer is 0x2d000049 - */ - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module_class( - (lboard_t *)KL_CONFIG_INFO(nasid), - module, - KLTYPE_IOBRICK); - -DBG("io_xswitch_widget_init: Board 0x%p\n", board); -{ - lboard_t dummy; - - - if (board) { - DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); - } else { - DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); - board = &dummy; - } - -} - - /* - * Make sure we really want to say xbrick, pbrick, - * etc. rather than XIO, graphics, etc. - */ - -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - "%cbrick" "/%s/%d", - NODEPDA(cnode)->module_id, - -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - "%cbrick" "/%s/%d", - buffer, -#endif - - (board->brd_type == KLTYPE_IBRICK) ? 'I' : - (board->brd_type == KLTYPE_PBRICK) ? 'P' : - (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', - EDGE_LBL_XTALK, widgetnum); - } - - DBG("io_xswitch_widget_init: path= %s\n", pathname); - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - - ASSERT(rc == GRAPH_SUCCESS); - - /* This is needed to let the user programs to map the - * module,slot numbers to the corresponding widget numbers - * on the crossbow. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - /* If we are looking at the global master io6 - * then add information about the version of - * the io6prom as a part of "detailed inventory" - * information. - */ - if (is_master_baseio(nasid, - NODEPDA(cnode)->module_id, - get_widget_slotnum(0,widgetnum))) { - extern void klhwg_baseio_inventory_add(devfs_handle_t, - cnodeid_t); - module = NODEPDA(cnode)->module_id; - -#ifdef XBRIDGE_REGS_SIM - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); - if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) { -#else - if (nasid_has_xbridge(nasid)) { -#endif /* XBRIDGE_REGS_SIM */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(nasid), - module); - /* - * Change iobrick to correct i/o brick - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" -#else - sprintf(pathname, EDGE_LBL_MODULE "/%x/" -#endif - "iobrick" "/%s/%d", - NODEPDA(cnode)->module_id, - EDGE_LBL_XTALK, widgetnum); - } else { - slot = get_widget_slotnum(0, widgetnum); - board = get_board_name(nasid, module, slot, - new_name); - /* - * Create the vertex for the widget, - * using the decimal - * widgetnum as the name of the primary edge. - */ -#ifdef SUPPORT_PRINTING_M_FORMAT - sprintf(pathname, EDGE_LBL_MODULE "/%M/" - EDGE_LBL_SLOT "/%s/%s", - NODEPDA(cnode)->module_id, - slotname, new_name); -#else - memset(buffer, 0, 16); - format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" - EDGE_LBL_SLOT "/%s/%s", - buffer, - slotname, new_name); -#endif - } - - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); - /* - * This is a weird ass code needed for error injection - * purposes. - */ - rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); - - klhwg_baseio_inventory_add(widgetv,cnode); - } - sprintf(name, "%d", widgetnum); - DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); - rc = hwgraph_edge_add(xswitchv, widgetv, name); - - /* - * crosstalk switch code tracks which - * widget is attached to each link. - */ - xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); - - /* - * Peek at the widget to get its crosstalk part and - * mfgr numbers, then present it to the generic xtalk - * bus provider to have its driver attach routine - * called (or not). - */ -#ifdef XBRIDGE_REGS_SIM - widget_id = 0x2d000049; - DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); -#else - widget_id = XWIDGET_ID_READ(nasid, widgetnum); -#endif /* XBRIDGE_REGS_SIM */ - hwid.part_num = XWIDGET_PART_NUM(widget_id); - hwid.rev_num = XWIDGET_REV_NUM(widget_id); - hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); - /* Store some inventory information about - * the xwidget in the hardware graph. - */ - xwidget_inventory_add(widgetv,board,hwid); - - (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid, - aa); - -#ifdef SN0_USE_BTE - bte_bpush_war(cnode, (void *)board); -#endif - } - -} - - -static void -io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) -{ - xwidgetnum_t widgetnum; - async_attach_t aa; - - aa = async_attach_new(); - - DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum, aa); - } - /* - * Wait for parallel attach threads, if any, to complete. - */ - async_attach_waitall(aa); - async_attach_free(aa); -} - -/* - * For each PCI bridge connected to the xswitch, add a link from the - * board's klconfig info to the bridge's hwgraph vertex. This lets - * the FRU analyzer find the bridge without traversing the hardware - * graph and risking hangs. - */ -static void -io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) -{ - xwidgetnum_t widgetnum; - char pathname[128]; - devfs_handle_t vhdl; - nasid_t nasid, peer_nasid; - lboard_t *board; - - - - /* And its connected hub's nasids */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - peer_nasid = NODEPDA(cnodeid)->xbow_peer; - - /* - * Look for paths matching "/pci" under xswitchv. - * For every widget, init. its lboard's hwgraph link. If the - * board has a PCI bridge, point the link to it. - */ - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - sprintf(pathname, "%d", widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) != - GRAPH_SUCCESS) - continue; - - board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), - NODEPDA(cnodeid)->module_id); - if (board == NULL && peer_nasid != INVALID_NASID) { - /* - * Try to find the board on our peer - */ - board = find_lboard_module( - (lboard_t *)KL_CONFIG_INFO(peer_nasid), - NODEPDA(cnodeid)->module_id); - } - if (board == NULL) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "Could not find PROM info for vertex %v, " - "FRU analyzer may fail", - vhdl); -#else - printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, " - "FRU analyzer may fail", - (void *)vhdl); -#endif - return; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == - GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else - board->brd_graph_link = GRAPH_VERTEX_NONE; - } -} - -/* - * Initialize all I/O on the specified node. - */ -static void -io_init_node(cnodeid_t cnodeid) -{ - /*REFERENCED*/ - devfs_handle_t hubv, switchv, widgetv; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - int is_xswitch; - nodepda_t *npdap; - struct semaphore *peer_sema = 0; - uint32_t widget_partnum; - nodepda_router_info_t *npda_rip; - cpu_cookie_t c = 0; - extern int hubdev_docallouts(devfs_handle_t); - -#ifdef LATER - /* Try to execute on the node that we're initializing. */ - c = setnoderun(cnodeid); -#endif - npdap = NODEPDA(cnodeid); - - /* - * Get the "top" vertex for this node's hardware - * graph; it will carry the per-hub hub-specific - * data, and act as the crosstalk provider master. - * It's canonical path is probably something of the - * form /hw/module/%M/slot/%d/node - */ - hubv = cnodeid_to_vertex(cnodeid); - DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); - - ASSERT(hubv != GRAPH_VERTEX_NONE); - - hubdev_docallouts(hubv); - - /* - * Set up the dependent routers if we have any. - */ - npda_rip = npdap->npda_rip_first; - - while(npda_rip) { - /* If the router info has not been initialized - * then we need to do the router initialization - */ - if (!npda_rip->router_infop) { - router_init(cnodeid,0,npda_rip); - } - npda_rip = npda_rip->router_next; - } - - /* - * Read mfg info on this hub - */ -#ifdef LATER - printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n"); - HUB_VERTEX_MFG_INFO(hubv); -#endif /* LATER */ - - /* - * If nothing connected to this hub's xtalk port, we're done. - */ - early_probe_for_widget(hubv, &hwid); - if (hwid.part_num == XWIDGET_PART_NUM_NONE) { -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 600; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - - DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - return; - /* NOTREACHED */ - } - - /* - * attach our hub_provider information to hubv, - * so we can use it as a crosstalk provider "master" - * vertex. - */ - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); - - /* - * Create a vertex to represent the crosstalk bus - * attached to this hub, and a vertex to be used - * as the connect point for whatever is out there - * on the other side of our crosstalk connection. - * - * Crosstalk Switch drivers "climb up" from their - * connection point to try and take over the switch - * point. - * - * Of course, the edges and verticies may already - * exist, in which case our net effect is just to - * associate the "xtalk_" driver with the connection - * point for the device. - */ - - (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - - DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); - - ASSERT(switchv != GRAPH_VERTEX_NONE); - - (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - - DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); - - /* - * We need to find the widget id and update the basew_id field - * accordingly. In particular, SN00 has direct connected bridge, - * and hence widget id is Not 0. - */ - - widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - - if (widget_partnum == BRIDGE_WIDGET_PART_NUM || - widget_partnum == XBRIDGE_WIDGET_PART_NUM){ - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); - - } else if (widget_partnum == XBOW_WIDGET_PART_NUM || - widget_partnum == XXBOW_WIDGET_PART_NUM) { - /* - * Xbow control register does not have the widget ID field. - * So, hard code the widget ID to be zero. - */ - DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); - npdap->basew_id = 0; - - } else if (widget_partnum == XG_WIDGET_PART_NUM) { - /* - * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock??? - * So, hard code the widget ID to be zero? - */ - npdap->basew_id = 0; - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - } else { - npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); - - panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); - - /*NOTREACHED*/ - } - { - char widname[10]; - sprintf(widname, "%x", npdap->basew_id); - (void)hwgraph_path_add(switchv, widname, &widgetv); - DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); - ASSERT(widgetv != GRAPH_VERTEX_NONE); - } - - nodepda->basew_xc = widgetv; - - is_xswitch = xwidget_hwid_is_xswitch(&hwid); - - /* - * Try to become the master of the widget. If this is an xswitch - * with multiple hubs connected, only one will succeed. Mastership - * of an xswitch is used only when touching registers on that xswitch. - * The slave xwidgets connected to the xswitch can be owned by various - * masters. - */ - if (device_master_set(widgetv, hubv) == 0) { - - /* Only one hub (thread) per Crosstalk device or switch makes - * it to here. - */ - - /* - * Initialize whatever xwidget is hanging off our hub. - * Whatever it is, it's accessible through widgetnum 0. - */ - hubinfo_get(hubv, &hubinfo); - - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); - - if (!is_xswitch) { - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - /* NOTREACHED */ - } - - /* - * Special handling for Crosstalk Switches (e.g. xbow). - * We need to do things in roughly the following order: - * 1) Initialize xswitch hardware (done above) - * 2) Determine which hubs are available to be widget masters - * 3) Discover which links are active from the xswitch - * 4) Assign xwidgets hanging off the xswitch to hubs - * 5) Initialize all xwidgets on the xswitch - */ - - volunteer_for_widgets(switchv, hubv); - - /* If there's someone else on this crossbow, recognize him */ - if (npdap->xbow_peer != INVALID_NASID) { - nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); - peer_sema = &peer_npdap->xbow_sema; - volunteer_for_widgets(switchv, peer_npdap->node_vertex); - } - - assign_widgets_to_volunteers(switchv, hubv); - - /* Signal that we're done */ - if (peer_sema) { - mutex_unlock(peer_sema); - } - - } - else { - /* Wait 'til master is done assigning widgets. */ - mutex_lock(&npdap->xbow_sema); - } - -#ifdef PROBE_TEST - if ((cnodeid == 1) || (cnodeid == 2)) { - int index; - - for (index = 0; index < 500; index++) - DBG("Interfering with device probing!!!\n"); - } -#endif - /* Now both nodes can safely inititialize widgets */ - io_init_xswitch_widgets(switchv, cnodeid); - io_link_xswitch_widgets(switchv, cnodeid); - - /* io_init_done takes cpu cookie as 2nd argument - * to do a restorenoderun for the setnoderun done - * at the start of this thread - */ - io_init_done(cnodeid,c); - - DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); -} - - -#define IOINIT_STKSZ (16 * 1024) - -#define __DEVSTR1 "/../.master/" -#define __DEVSTR2 "/target/" -#define __DEVSTR3 "/lun/0/disk/partition/" -#define __DEVSTR4 "/../ef" - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * Currently, we need to allow for 5 IBrick slots with 1 FC each - * plus an internal 1394. - * - * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR. - */ -#define NUM_BASE_IO_SCSI_CTLR 6 -#else -#define NUM_BASE_IO_SCSI_CTLR 6 -#endif -/* - * This tells ioconfig where it can start numbering scsi controllers. - * Below this base number, platform-specific handles the numbering. - * XXX Irix legacy..controller numbering should be part of devfsd's job - */ -int num_base_io_scsi_ctlr = 2; /* used by syssgi */ -devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; -static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; - -/* - * Put the logical controller number information in the - * scsi controller vertices for each scsi controller that - * is in a "fixed position". - */ -static void -scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) -{ - { - int i; - - num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; - - /* Initialize base_io_scsi_ctlr_vhdl array */ - for (i=0; i -devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; - -/* Define the system critical vertices and connect them through - * a canonical parent-child relationships for easy traversal - * during io error handling. - */ -static void -sys_critical_graph_init(void) -{ - devfs_handle_t bridge_vhdl,master_node_vhdl; - devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; - extern devfs_handle_t hwgraph_root; - devfs_handle_t pci_slot_conn; - int slot; - devfs_handle_t baseio_console_conn; - - DBG("sys_critical_graph_init: FIXME.\n"); - baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); - - if (baseio_console_conn == NULL) { - return; - } - - /* Get the vertex handle for the baseio bridge */ - bridge_vhdl = device_master_get(baseio_console_conn); - - /* Get the master node of the baseio card */ - master_node_vhdl = cnodeid_to_vertex( - master_node_get(baseio_console_vhdl)); - - /* Add the "root->node" part of the system critical graph */ - - sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); - - /* Check if we have a crossbow */ - if (hwgraph_traverse(master_node_vhdl, - EDGE_LBL_XTALK"/0", - &xbow_vhdl) == GRAPH_SUCCESS) { - /* We have a crossbow.Add "node->xbow" part of the system - * critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); - - /* Add "xbow->baseio bridge" of the system critical graph */ - sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); - - hwgraph_vertex_unref(xbow_vhdl); - } else - /* We donot have a crossbow. Add "node->baseio_bridge" - * part of the system critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); - - /* Add all the populated PCI slot vertices to the system critical - * graph with the bridge vertex as the parent. - */ - for (slot = 0 ; slot < 8; slot++) { - char slot_edge[10]; - - sprintf(slot_edge,"%d",slot); - if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) - != GRAPH_SUCCESS) - continue; - sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); - hwgraph_vertex_unref(pci_slot_conn); - } - - hwgraph_vertex_unref(bridge_vhdl); - - /* Add the "ioc3 pci connection point -> console ioc3" part - * of the system critical graph - */ - - if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_console_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "ethernet pci connection point -> base ethernet" part of - * the system critical graph - */ - if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_enet_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "scsi controller pci connection point -> base scsi - * controller" part of the system critical graph - */ - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[0]); - hwgraph_vertex_unref(pci_slot_conn); - } - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[1]); - hwgraph_vertex_unref(pci_slot_conn); - } - hwgraph_vertex_unref(baseio_console_conn); - -} - -static void -baseio_ctlr_num_set(void) -{ - char name[MAXDEVNAME]; - devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - devfs_handle_t ioc3_console_vhdl_get(void); - - - DBG("baseio_ctlr_num_set; FIXME\n"); - console_vhdl = ioc3_console_vhdl_get(); - if (console_vhdl == GRAPH_VERTEX_NONE) - return; - /* Useful for setting up the system critical graph */ - baseio_console_vhdl = console_vhdl; - - vertex_to_name(console_vhdl,name,MAXDEVNAME); - - strcat(name,__DEVSTR1); - pci_vhdl = hwgraph_path_to_vertex(name); - scsi_ctlr_nums_add(pci_vhdl); - /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(pci_vhdl); - - vertex_to_name(console_vhdl, name, MAXDEVNAME); - strcat(name, __DEVSTR4); - enet_vhdl = hwgraph_path_to_vertex(name); - - /* Useful for setting up the system critical graph */ - baseio_enet_vhdl = enet_vhdl; - - device_controller_num_set(enet_vhdl, 0); - /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(enet_vhdl); -} -/* #endif */ - -void -sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list) -{ - /* REFERENCED */ - int rtn_val; - - /* - ** sn00 population: errb orrb - ** 0- ql 3+? - ** 1- ql 2 - ** 2- ioc3 ethernet 2+? - ** 3- ioc3 secondary 1 - ** 4- 0 - ** 5- PCI slot - ** 6- PCI slot - ** 7- PCI slot - */ - - /* The following code implements this heuristic for getting - * maximum usage out of the rrbs - * - * constraints: - * 8 bit ql1 needs 1+1 - * ql0 or ql5,6,7 wants 1+2 - * ethernet wants 2 or more - * - * rules for even rrbs: - * if nothing in slot 6 - * 4 rrbs to 0 and 2 (0xc8889999) - * else - * 3 2 3 to slots 0 2 6 (0xc8899bbb) - * - * rules for odd rrbs - * if nothing in slot 5 or 7 (0xc8889999) - * 4 rrbs to 1 and 3 - * else if 1 thing in 5 or 7 (0xc8899aaa) or (0xc8899bbb) - * 3 2 3 to slots 1 3 5|7 - * else - * 2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this - * (0xc89aaabb) may short what it wants therefore the - * rule should be to plug pci slots in order) - */ - - - if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) { - /* something in slot 6 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0); - } - else { - rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); - - if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && - (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) { - /* soemthing in slot 5 and 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0); - } - else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 5 but not 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0); - } - else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) { - /* soemthing in slot 7 but not 5 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0); - } - else { - /* nothing in slot 5 or 7 */ - rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0); - } - if (rtn_val) - printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed"); -} - - -/* - * Initialize all I/O devices. Starting closest to nodes, probe and - * initialize outward. - */ -void -init_all_devices(void) -{ - /* Governor on init threads..bump up when safe - * (beware many devfs races) - */ -#ifdef LATER - int io_init_node_threads = 2; -#endif - cnodeid_t cnodeid, active; - -#ifdef LINUX_KERNEL_THREADS - sema_init(&io_init_sema, 0); -#endif - - active = 0; - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { -#ifdef LINUX_KERNEL_THREADS - char thread_name[16]; - extern int io_init_pri; - - /* - * Spawn a service thread for each node to initialize all - * I/O on that node. Each thread attempts to bind itself - * to the node whose I/O it's initializing. - */ - sprintf(thread_name, "IO_init[%d]", cnodeid); - - (void)sthread_create(thread_name, 0, IOINIT_STKSZ, 0, - io_init_pri, KT_PS, (st_func_t *)io_init_node, - (void *)(long)cnodeid, 0, 0, 0); -#else - DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); - io_init_node(cnodeid); - - DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - -#endif /* LINUX_KERNEL_THREADS */ - -#ifdef LINUX_KERNEL_THREADS - /* Limit how many nodes go at once, to not overload hwgraph */ - /* TBD: Should timeout */ - DBG("started thread for cnode %d\n", cnodeid); - active++; - if (io_init_node_threads && - active >= io_init_node_threads) { - down(&io_init_sema); - active--; - } -#endif /* LINUX_KERNEL_THREADS */ - } - -#ifdef LINUX_KERNEL_THREADS - /* Wait until all IO_init threads are done */ - - while (active > 0) { -#ifdef AA_DEBUG - DBG("waiting, %d still active\n", active); -#endif - down(&io_init_sema); - active--; - } - -#endif /* LINUX_KERNEL_THREADS */ - - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) - /* - * Update information generated by IO init. - */ - update_node_information(cnodeid); - - baseio_ctlr_num_set(); - /* Setup the system critical graph (which is a subgraph of the - * main hwgraph). This information is useful during io error - * handling. - */ - sys_critical_graph_init(); - -#if HWG_PRINT - hwgraph_print(); -#endif - -} - -#define toint(x) ((int)(x) - (int)('0')) - -void -devnamefromarcs(char *devnm) -{ - int val; - char tmpnm[MAXDEVNAME]; - char *tmp1, *tmp2; - - val = strncmp(devnm, "dks", 3); - if (val != 0) - return; - tmp1 = devnm + 3; - if (!isdigit(*tmp1)) - return; - - val = 0; - while (isdigit(*tmp1)) { - val = 10*val+toint(*tmp1); - tmp1++; - } - - if(*tmp1 != 'd') - return; - else - tmp1++; - - if ((val < 0) || (val >= NUM_BASE_IO_SCSI_CTLR)) { - int i; - int viable_found = 0; - - DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1); - DBG("prom \"root\" variables of the form dksXdXsX.\n"); - DBG("To use another disk you must use the full hardware graph path\n\n"); - DBG("Possible controller numbers for use in 'dksXdXsX' on this system: "); - for (i=0; i XBOW_PORT_F) - return 0; - - /* Find "brick" in the path name */ - bp = strstr(hw_path_name, "brick"); - if (bp == NULL) - return 0; - - /* Find preceding slash */ - sp = bp; - while (sp > hw_path_name) { - sp--; - if (*sp == '/') - break; - } - - /* Invalid if no preceding slash */ - if (!sp) - return 0; - - /* Bump slash pointer to "brick" prefix */ - sp++; - /* - * Verify "brick" prefix length; valid exaples: - * 'I' from "/Ibrick" - * 'P' from "/Pbrick" - * 'X' from "/Xbrick" - */ - if ((bp - sp) != 1) - return 0; - - return (io_brick_map_widget(*sp, widget_num)); - -} diff -Nru a/arch/ia64/sn/io/module.c b/arch/ia64/sn/io/module.c --- a/arch/ia64/sn/io/module.c Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,312 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* #define LDEBUG 1 */ - -#ifdef LDEBUG -#define DPRINTF printk -#define printf printk -#else -#define DPRINTF(x...) -#endif - -module_t *modules[MODULE_MAX]; -int nummodules; - -#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 -#define SN0_SERIAL_FUDGE 0x6e - -void -encode_int_serial(uint64_t src,uint64_t *dest) -{ - uint64_t val; - int i; - - val = src + SN00_SERIAL_FUDGE; - - - for (i = 0; i < sizeof(long long); i++) { - ((char*)dest)[i] = - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; - } -} - - -void -decode_int_serial(uint64_t src, uint64_t *dest) -{ - uint64_t val; - int i; - - for (i = 0; i < sizeof(long long); i++) { - ((char*)&val)[sizeof(long long)/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = - ((char*)&src)[i]; - } - - *dest = val - SN00_SERIAL_FUDGE; -} - - -void -encode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - - dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + - SN0_SERIAL_FUDGE; - } -} - -void -decode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - dest[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - - SN0_SERIAL_FUDGE; - } -} - - -module_t *module_lookup(moduleid_t id) -{ - int i; - - for (i = 0; i < nummodules; i++) - if (modules[i]->id == id) { - DPRINTF("module_lookup: found m=0x%p\n", modules[i]); - return modules[i]; - } - - return NULL; -} - -/* - * module_add_node - * - * The first time a new module number is seen, a module structure is - * inserted into the module list in order sorted by module number - * and the structure is initialized. - * - * The node number is added to the list of nodes in the module. - */ - -module_t *module_add_node(moduleid_t id, cnodeid_t n) -{ - module_t *m; - int i; - char buffer[16]; - -#ifdef __ia64 - memset(buffer, 0, 16); - format_module_id(buffer, id, MODULE_FORMAT_BRIEF); - DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); -#endif - - if ((m = module_lookup(id)) == 0) { -#ifdef LATER - m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); -#else - m = kmalloc(sizeof (module_t), GFP_KERNEL); - memset(m, 0 , sizeof(module_t)); -#endif - ASSERT_ALWAYS(m); - - m->id = id; - spin_lock_init(&m->lock); - - mutex_init_locked(&m->thdcnt); - -// set_elsc(&m->elsc); - elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); - spin_lock_init(&m->elsclock); - - /* Insert in sorted order by module number */ - - for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--) - modules[i] = modules[i - 1]; - - modules[i] = m; - nummodules++; - } - - m->nodes[m->nodecnt++] = n; - - DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); - - return m; -} - -int module_probe_snum(module_t *m, nasid_t nasid) -{ - lboard_t *board; - klmod_serial_num_t *comp; - char * bcopy(const char * src, char * dest, int count); - char serial_number[16]; - - /* - * record brick serial number - */ - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - { -#if LDEBUG - printf ("module_probe_snum: no IP35 board found!\n"); -#endif - return 0; - } - - board_serial_number_get( board, serial_number ); - if( serial_number[0] != '\0' ) { - encode_str_serial( serial_number, m->snum.snum_str ); - m->snum_valid = 1; - } -#if LDEBUG - else { - printf("module_probe_snum: brick serial number is null!\n"); - } - printf("module_probe_snum: brick serial number == %s\n", serial_number); -#endif /* DEBUG */ - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), - KLTYPE_IOBRICK_XBOW); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - return 0; - - comp = GET_SNUM_COMP(board); - - if (comp) { -#if LDEBUG - int i; - - printf("********found module with id %x and string", m->id); - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) - printf(" %x ", comp->snum.snum_str[i]); - - printf("\n"); /* Fudged string is not ASCII */ -#endif - - if (comp->snum.snum_str[0] != '\0') { - bcopy(comp->snum.snum_str, - m->sys_snum, - MAX_SERIAL_NUM_SIZE); - m->sys_snum_valid = 1; - } - } - - if (m->sys_snum_valid) - return 1; - else { - DPRINTF("Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); - return 0; - } -} - -void -io_module_init(void) -{ - cnodeid_t node; - lboard_t *board; - nasid_t nasid; - int nserial; - module_t *m; - - DPRINTF("*******module_init\n"); - - nserial = 0; - - for (node = 0; node < numnodes; node++) { - nasid = COMPACT_TO_NASID_NODEID(node); - - board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(board); - - m = module_add_node(board->brd_module, node); - - if (! m->snum_valid && module_probe_snum(m, nasid)) - nserial++; - } - - DPRINTF("********found total of %d serial numbers in the system\n", - nserial); - - if (nserial == 0) - printk(KERN_WARNING "io_module_init: No serial number found.\n"); -} - -elsc_t *get_elsc(void) -{ - return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; -} - -int -get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) -{ - int i; - - if (cmod < 0 || cmod >= nummodules) - return EINVAL; - - if (! modules[cmod]->snum_valid) - return ENXIO; - - mod_info->mod_num = modules[cmod]->id; - { - char temp[MAX_SERIAL_NUM_SIZE]; - - decode_str_serial(modules[cmod]->snum.snum_str, temp); - - /* if this is an invalid serial number return an error */ - if (temp[0] != 'K') - return ENXIO; - - mod_info->serial_num = 0; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) { - mod_info->serial_num <<= 4; - mod_info->serial_num |= (temp[i] & 0xf); - - mod_info->serial_str[i] = temp[i]; - } - - mod_info->serial_str[i] = '\0'; - } - - return 0; -} diff -Nru a/arch/ia64/sn/io/pci.c b/arch/ia64/sn/io/pci.c --- a/arch/ia64/sn/io/pci.c Tue Dec 3 10:07:24 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,294 +0,0 @@ -/* - * - * SNI64 specific PCI support for SNI IO. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 1997, 1998, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG_CONFIG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - - - -#ifdef CONFIG_PCI - -extern devfs_handle_t pci_bus_to_vertex(unsigned char); -extern devfs_handle_t devfn_to_vertex(unsigned char bus, unsigned char devfn); - -/* - * snia64_read_config_byte - Read a byte from the config area of the device. - */ -static int snia64_read_config_byte (struct pci_dev *dev, - int where, unsigned char *val) -{ - unsigned long res = 0; - unsigned size = 1; - devfs_handle_t device_vertex; - - if ( (dev == (struct pci_dev *)0) || (val == (unsigned char *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned char) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_read_config_word - Read 2 bytes from the config area of the device. - */ -static int snia64_read_config_word (struct pci_dev *dev, - int where, unsigned short *val) -{ - unsigned long res = 0; - unsigned size = 2; /* 2 bytes */ - devfs_handle_t device_vertex; - - if ( (dev == (struct pci_dev *)0) || (val == (unsigned short *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned short) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_read_config_dword - Read 4 bytes from the config area of the device. - */ -static int snia64_read_config_dword (struct pci_dev *dev, - int where, unsigned int *val) -{ - unsigned long res = 0; - unsigned size = 4; /* 4 bytes */ - devfs_handle_t device_vertex; - - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( (dev == (struct pci_dev *)0) || (val == (unsigned int *)0) ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - res = pciio_config_get(device_vertex, (unsigned) where, size); - *val = (unsigned int) res; - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_byte - Writes 1 byte to the config area of the device. - */ -static int snia64_write_config_byte (struct pci_dev *dev, - int where, unsigned char val) -{ - devfs_handle_t device_vertex; - - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3 ) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 1, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_word - Writes 2 bytes to the config area of the device. - */ -static int snia64_write_config_word (struct pci_dev *dev, - int where, unsigned short val) -{ - devfs_handle_t device_vertex = NULL; - - if (where & 1) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 2, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -/* - * snia64_write_config_dword - Writes 4 bytes to the config area of the device. - */ -static int snia64_write_config_dword (struct pci_dev *dev, - int where, unsigned int val) -{ - devfs_handle_t device_vertex; - - if (where & 3) { - return PCIBIOS_BAD_REGISTER_NUMBER; - } - if ( dev == (struct pci_dev *)0 ) { - return PCIBIOS_DEVICE_NOT_FOUND; - } - /* - * if it's an IOC3 then we bail out, we special - * case them with pci_fixup_ioc3 - */ - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - return PCIBIOS_SUCCESSFUL; - - device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); - if (!device_vertex) { - DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", - __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - return(-1); - } - pciio_config_set( device_vertex, (unsigned)where, 4, (uint64_t) val); - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops snia64_pci_ops = { - snia64_read_config_byte, - snia64_read_config_word, - snia64_read_config_dword, - snia64_write_config_byte, - snia64_write_config_word, - snia64_write_config_dword -}; - -/* - * snia64_pci_find_bios - SNIA64 pci_find_bios() platform specific code. - */ -void __init -sn_pci_find_bios(void) -{ - extern struct pci_ops *pci_root_ops; - /* - * Go initialize our IO Infrastructure .. - */ - extern void sgi_master_io_infr_init(void); - - sgi_master_io_infr_init(); - - /* sn_io_infrastructure_init(); */ - pci_root_ops = &snia64_pci_ops; -} - -void -pci_fixup_ioc3(struct pci_dev *d) -{ - int i; - unsigned int size; - - /* IOC3 only decodes 0x20 bytes of the config space, reading - * beyond that is relatively benign but writing beyond that - * (especially the base address registers) will shut down the - * pci bus...so avoid doing so. - * NOTE: this means we can't program the intr_pin into the device, - * currently we hack this with special code in - * sgi_pci_intr_support() - */ - DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); - - /* I happen to know from the spec that the ioc3 needs only 0xfffff - * The standard pci trick of writing ~0 to the baddr and seeing - * what comes back doesn't work with the ioc3 - */ - size = 0xfffff; - d->resource[0].end = (unsigned long) d->resource[0].start + (unsigned long) size; - - /* - * Zero out the resource structure .. because we did not go through - * the normal PCI Infrastructure Init, garbbage are left in these - * fileds. - */ - for (i = 1; i <= PCI_ROM_RESOURCE; i++) { - d->resource[i].start = 0UL; - d->resource[i].end = 0UL; - d->resource[i].flags = 0UL; - } - -#ifdef CONFIG_IA64_SGI_SN1 - *(volatile u32 *)0xc0000a000f000220 |= 0x90000; -#endif - d->subsystem_vendor = 0; - d->subsystem_device = 0; - -} - -#else -void sn_pci_find_bios(void) {} -void pci_fixup_ioc3(struct pci_dev *d) {} -struct list_head pci_root_buses; -struct list_head pci_root_buses; -struct list_head pci_devices; - -#endif /* CONFIG_PCI */ diff -Nru a/arch/ia64/sn/io/pci_bus_cvlink.c b/arch/ia64/sn/io/pci_bus_cvlink.c --- a/arch/ia64/sn/io/pci_bus_cvlink.c Wed Jun 4 07:34:28 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,737 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int bridge_rev_b_data_check_disable; - -devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; -nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; -void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; -unsigned char num_bridges; -static int done_probing = 0; - -static int pci_bus_map_create(devfs_handle_t xtalk); -devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -#define SN1_IOPORTS_UNIT 256 -#define MAX_IOPORTS 0xffff -#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN1_IOPORTS_UNIT) -struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS]; -unsigned long sn1_allocate_ioports(unsigned long pci_address); - -extern void sn1_init_irq_desc(void); - - - -/* - * pci_bus_cvlink_init() - To be called once during initialization before - * SGI IO Infrastructure init is called. - */ -void -pci_bus_cvlink_init(void) -{ - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); - memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); - - memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); - - memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs)); - - num_bridges = 0; -} - -/* - * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated - * pci bus vertex from the SGI IO Infrastructure. - */ -devfs_handle_t -pci_bus_to_vertex(unsigned char busnum) -{ - - devfs_handle_t pci_bus = NULL; - - - /* - * First get the xwidget vertex. - */ - pci_bus = busnum_to_pcibr_vhdl[busnum]; - return(pci_bus); -} - -/* - * devfn_to_vertex() - returns the vertex of the device given the bus, slot, - * and function numbers. - */ -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn) -{ - - int slot = 0; - int func = 0; - char name[16]; - devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = (devfs_handle_t)NULL; - - /* - * Go get the pci bus vertex. - */ - pci_bus = pci_bus_to_vertex(busnum); - if (!pci_bus) { - /* - * During probing, the Linux pci code invents non-existent - * bus numbers and pci_dev structures and tries to access - * them to determine existence. Don't crib during probing. - */ - if (done_probing) - printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); - return(NULL); - } - - - /* - * Go get the slot&function vertex. - * Should call pciio_slot_func_to_name() when ready. - */ - slot = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); - - /* - * For a NON Multi-function card the name of the device looks like: - * ../pci/1, ../pci/2 .. - */ - if (func == 0) { - sprintf(name, "%d", slot); - if (hwgraph_traverse(pci_bus, name, &device_vertex) == - GRAPH_SUCCESS) { - if (device_vertex) { - return(device_vertex); - } - } - } - - /* - * This maybe a multifunction card. It's names look like: - * ../pci/1a, ../pci/1b, etc. - */ - sprintf(name, "%d%c", slot, 'a'+func); - if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { - if (!device_vertex) { - return(NULL); - } - } - - return(device_vertex); -} - -/* - * For the given device, initialize the addresses for both the Device(x) Flush - * Write Buffer register and the Xbow Flush Register for the port the PCI bus - * is connected. - */ -static void -set_flush_addresses(struct pci_dev *device_dev, - struct sn1_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - device_sysdata->dma_buf_sync = (volatile unsigned int *) - &(bridge->b_wr_req_buf[pciio_slot].reg); - device_sysdata->xbow_buf_sync = (volatile unsigned int *) - XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), - pcibr_soft->bs_xid); -#ifdef DEBUG - - printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", - device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); - - while((volatile unsigned int )*device_sysdata->dma_buf_sync); - while((volatile unsigned int )*device_sysdata->xbow_buf_sync); -#endif - -} - -/* - * Most drivers currently do not properly tell the arch specific pci dma - * interfaces whether they can handle A64. Here is where we privately - * keep track of this. - */ -static void __init -set_sn1_pci64(struct pci_dev *dev) -{ - unsigned short vendor = dev->vendor; - unsigned short device = dev->device; - - if (vendor == PCI_VENDOR_ID_QLOGIC) { - if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || - (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { - SET_PCIA64(dev); - return; - } - } - - if (vendor == PCI_VENDOR_ID_SGI) { - if (device == PCI_DEVICE_ID_SGI_IOC3) { - SET_PCIA64(dev); - return; - } - } - -} - -/* - * sn1_allocate_ioports() - This routine provides the allocation and - * mappings between Linux style IOPORTs management. - * - * For simplicity sake, SN1 will allocate IOPORTs in chunks of - * 256bytes .. irrespective of what the card desires. This may - * have to change when we understand how to deal with legacy ioports - * which are hardcoded in some drivers e.g. SVGA. - * - * Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers. - * It will remain so. The IO Infrastructure will continue to map - * IO Resource just like IRIX. When this is done, we map IOPORT - * chunks to these resources. The Linux drivers will see and use real - * IOPORT numbers. The various IOPORT access macros e.g. inb/outb etc. - * does the munging of these IOPORT numbers to make a Uncache Virtual - * Address. This address via the tlb entries generates the PCI Address - * allocated by the SN1 IO Infrastructure Layer. - */ -static unsigned long sn1_ioport_num = 0x1000; /* Reserve room for Legacy stuff */ -unsigned long -sn1_allocate_ioports(unsigned long pci_address) -{ - - unsigned long ioport_index; - - /* - * Just some idiot checking .. - */ - if ( sn1_ioport_num > 0xffff ) { - printk("sn1_allocate_ioports: No more IO PORTS available\n"); - return(-1); - } - - /* - * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's - * Manual for details. - */ - ioport_index = sn1_ioport_num / SN1_IOPORTS_UNIT; - - ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */ - ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */ - ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/ - ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/ - ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */ - ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/ - ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/ - ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */ - ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */ - ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */ - - /* printk("sn1_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */ - - sn1_ioport_num += SN1_IOPORTS_UNIT; - - return(sn1_ioport_num - SN1_IOPORTS_UNIT); -} - -/* - * sn1_pci_fixup() - This routine is called when platform_pci_fixup() is - * invoked at the end of pcibios_init() to link the Linux pci - * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c - * - * Other platform specific fixup can also be done here. - */ -void -sn1_pci_fixup(int arg) -{ - struct list_head *ln; - struct pci_bus *pci_bus = NULL; - struct pci_dev *device_dev = NULL; - struct sn1_widget_sysdata *widget_sysdata; - struct sn1_device_sysdata *device_sysdata; -#ifdef SN1_IOPORTS - unsigned long ioport; -#endif - pciio_intr_t intr_handle; - int cpuid, bit; - devfs_handle_t device_vertex; - pciio_intr_line_t lines; - extern void sn1_pci_find_bios(void); -#ifdef CONFIG_IA64_SGI_SN2 - extern int numnodes; - int cnode; -#endif /* CONFIG_IA64_SGI_SN2 */ - - - if (arg == 0) { - sn1_init_irq_desc(); - sn1_pci_find_bios(); -#ifdef CONFIG_IA64_SGI_SN2 - for (cnode = 0; cnode < numnodes; cnode++) { - extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); - intr_init_vecblk(NODEPDA(cnode), cnode, 0); - } -#endif /* CONFIG_IA64_SGI_SN2 */ - return; - } - -#if 0 -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} -#endif - done_probing = 1; - - /* - * Initialize the pci bus vertex in the pci_bus struct. - */ - for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - pci_bus = pci_bus_b(ln); - widget_sysdata = kmalloc(sizeof(struct sn1_widget_sysdata), - GFP_KERNEL); - widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); - pci_bus->sysdata = (void *)widget_sysdata; - } - - /* - * set the root start and end so that drivers calling check_region() - * won't see a conflict - */ -#ifdef SN1_IOPORTS - ioport_resource.start = sn1_ioport_num; - ioport_resource.end = 0xffff; -#else -#if defined(CONFIG_IA64_SGI_SN1) - if ( IS_RUNNING_ON_SIMULATOR() ) { - /* - * IDE legacy IO PORTs are supported in Medusa. - * Just open up IO PORTs from 0 .. ioport_resource.end. - */ - ioport_resource.start = 0; - } else { - /* - * We do not support Legacy IO PORT numbers. - */ - ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET; - } - ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET; -#else - // Need something here for sn2.... ZXZXZX -#endif -#endif - - /* - * Initialize the device vertex in the pci_dev struct. - */ - while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { - unsigned int irq; - int idx; - u16 cmd; - devfs_handle_t vhdl; - unsigned long size; - extern int bit_pos_to_irq(int); - - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { - extern void pci_fixup_ioc3(struct pci_dev *d); - pci_fixup_ioc3(device_dev); - } - - /* Set the device vertex */ - - device_sysdata = kmalloc(sizeof(struct sn1_device_sysdata), - GFP_KERNEL); - device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); - device_sysdata->isa64 = 0; - /* - * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush - * register addresses. - */ - (void) set_flush_addresses(device_dev, device_sysdata); - - device_dev->sysdata = (void *) device_sysdata; - set_sn1_pci64(device_dev); - pci_read_config_word(device_dev, PCI_COMMAND, &cmd); - - /* - * Set the resources address correctly. The assumption here - * is that the addresses in the resource structure has been - * read from the card and it was set in the card by our - * Infrastructure .. - */ - vhdl = device_sysdata->vhdl; - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - size = 0; - size = device_dev->resource[idx].end - - device_dev->resource[idx].start; - if (size) { - device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; - } - else - continue; - - device_dev->resource[idx].end = - device_dev->resource[idx].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Adjust the addresses to go to the SWIZZLE .. - */ - device_dev->resource[idx].start = - device_dev->resource[idx].start & 0xfffff7ffffffffff; - device_dev->resource[idx].end = - device_dev->resource[idx].end & 0xfffff7ffffffffff; -#endif - - if (device_dev->resource[idx].flags & IORESOURCE_IO) { - cmd |= PCI_COMMAND_IO; -#ifdef SN1_IOPORTS - ioport = sn1_allocate_ioports(device_dev->resource[idx].start); - if (ioport < 0) { - printk("sn1_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number); - continue; - } - pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff))); - -printk("sn1_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff))); - - device_dev->resource[idx].start = ioport; - device_dev->resource[idx].end = ioport + SN1_IOPORTS_UNIT; -#endif - } - if (device_dev->resource[idx].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - /* - * Now handle the ROM resource .. - */ - size = device_dev->resource[PCI_ROM_RESOURCE].end - - device_dev->resource[PCI_ROM_RESOURCE].start; - - if (size) { - device_dev->resource[PCI_ROM_RESOURCE].start = - (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, - size, 0, PCIIO_BYTE_STREAM); - device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; - device_dev->resource[PCI_ROM_RESOURCE].end = - device_dev->resource[PCI_ROM_RESOURCE].start + size; - -#ifdef CONFIG_IA64_SGI_SN1 - /* - * go through synergy swizzled space - */ - device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL; - device_dev->resource[PCI_ROM_RESOURCE].end &= 0xfffff7ffffffffffUL; -#endif - - } - - /* - * Update the Command Word on the Card. - */ - cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ - /* bit gets dropped .. no harm */ - pci_write_config_word(device_dev, PCI_COMMAND, cmd); - - pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { - lines = 1; - } - - device_sysdata = (struct sn1_device_sysdata *)device_dev->sysdata; - device_vertex = device_sysdata->vhdl; - - intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); - - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; -#ifdef CONFIG_IA64_SGI_SN1 - irq = bit_pos_to_irq(bit); -#else /* SN2 */ - irq = bit; -#endif - irq = irq + (cpuid << 8); - pciio_intr_connect(intr_handle); - device_dev->irq = irq; -#ifdef ajmtestintr - { - int slot = PCI_SLOT(device_dev->devfn); - static int timer_set = 0; - pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - extern void intr_test_handle_intr(int, void*, struct pt_regs *); - - if (!timer_set) { - intr_test_set_timer(); - timer_set = 1; - } - intr_test_register_irq(irq, pcibr_soft, slot); - request_irq(irq, intr_test_handle_intr,0,NULL, NULL); - } -#endif - - } - -#if 0 - -{ - devfs_handle_t bridge_vhdl = pci_bus_to_vertex(0); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) hwgraph_fastinfo_get(bridge_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - printk("pci_fixup_ioc3: Before devreg fixup\n"); - printk("pci_fixup_ioc3: Devreg 0 0x%x\n", bridge->b_device[0].reg); - printk("pci_fixup_ioc3: Devreg 1 0x%x\n", bridge->b_device[1].reg); - printk("pci_fixup_ioc3: Devreg 2 0x%x\n", bridge->b_device[2].reg); - printk("pci_fixup_ioc3: Devreg 3 0x%x\n", bridge->b_device[3].reg); - printk("pci_fixup_ioc3: Devreg 4 0x%x\n", bridge->b_device[4].reg); - printk("pci_fixup_ioc3: Devreg 5 0x%x\n", bridge->b_device[5].reg); - printk("pci_fixup_ioc3: Devreg 6 0x%x\n", bridge->b_device[6].reg); - printk("pci_fixup_ioc3: Devreg 7 0x%x\n", bridge->b_device[7].reg); -} - -printk("testing Big Window: 0xC0000200c0000000 %p\n", *( (volatile uint64_t *)0xc0000200a0000000)); -printk("testing Big Window: 0xC0000200c0000008 %p\n", *( (volatile uint64_t *)0xc0000200a0000008)); - -#endif - -} - -/* - * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. - * - * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to - * HUB_WIDGET_ID_MIN: - * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. - * - * Given 2 modules 001c01 and 001c02 we get the following mappings: - * 001c01, widgetnum 15 = Bus number 0 - * 001c01, widgetnum 14 = Bus number 1 - * 001c02, widgetnum 15 = Bus number 3 - * 001c02, widgetnum 14 = Bus number 4 - * etc. - * - * The rational for starting Bus Number 0 with Widget number 15 is because - * the system boot disks are always connected via Widget 15 Slot 0 of the - * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 - * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest - * module id(Master Cnode) of the system. - * - */ -static int -pci_bus_map_create(devfs_handle_t xtalk) -{ - - devfs_handle_t master_node_vertex = NULL; - devfs_handle_t xwidget = NULL; - devfs_handle_t pci_bus = NULL; - hubinfo_t hubinfo = NULL; - xwidgetnum_t widgetnum; - char pathname[128]; - graph_error_t rv; - - /* - * Loop throught this vertex and get the Xwidgets .. - */ - for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { -#if 0 - { - int pos; - char dname[256]; - pos = devfs_generate_path(xtalk, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) - continue; - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) - continue; - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - num_bridges++; - busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; - - /* - * Get the master node and from there get the NASID. - */ - master_node_vertex = device_master_get(xwidget); - if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); - } - - hubinfo_get(master_node_vertex, &hubinfo); - if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); - return(1); - } else { - busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; - } - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct sn1_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct sn1_dma_maps_s) * MAX_ATE_MAPS); - - } - - return(0); -} - -/* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between Xbridge - * and logical pci bus numbers. We also set up the NASID for each of these - * xbridges. - * - * Must be called before pci_init() is invoked. - */ -int -pci_bus_to_hcl_cvlink(void) -{ - - devfs_handle_t devfs_hdl = NULL; - devfs_handle_t xtalk = NULL; - int rv = 0; - char name[256]; - int master_iobrick; - int i; - - /* - * Iterate throught each xtalk links in the system .. - * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 - * - * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15 - * - * What if it is not pci? - */ - devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); - - /* - * To provide consistent(not persistent) device naming, we need to start - * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 - * with an attached I-Brick. Find the master_iobrick. - */ - master_iobrick = -1; - for (i = 0; i < nummodules; i++) { - moduleid_t iobrick_id; - iobrick_id = iobrick_module_get(&modules[i]->elsc); - if (iobrick_id > 0) { /* Valid module id */ - if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) { - master_iobrick = i; - break; - } - } - } - - /* - * The master_iobrick gets bus 0 and 1. - */ - if (master_iobrick >= 0) { - memset(name, 0, 256); - format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - /* - * Now go do the rest of the modules, starting from the C-Brick with the lowest - * module id, remembering to skip the master_iobrick, which was done above. - */ - for (i = 0; i < nummodules; i++) { - if (i == master_iobrick) { - continue; /* Did the master_iobrick already. */ - } - - memset(name, 0, 256); - format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - strcat(name, "/node/xtalk"); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk); - } - - return(0); -} diff -Nru a/arch/ia64/sn/io/pci_dma.c b/arch/ia64/sn/io/pci_dma.c --- a/arch/ia64/sn/io/pci_dma.c Tue Dec 3 10:07:24 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,700 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000,2002 Silicon Graphics, Inc. All rights reserved. - * - * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for - * a description of how these routines should be used. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * For ATE allocations - */ -pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); -void free_pciio_dmamap(pcibr_dmamap_t); -static struct sn_dma_maps_s *find_sn_dma_map(dma_addr_t, unsigned char); - -/* - * Toplogy stuff - */ -extern devfs_handle_t busnum_to_pcibr_vhdl[]; -extern nasid_t busnum_to_nid[]; -extern void * busnum_to_atedmamaps[]; - -/** - * get_free_pciio_dmamap - find and allocate an ATE - * @pci_bus: PCI bus to get an entry for - * - * Finds and allocates an ATE on the PCI bus specified - * by @pci_bus. - */ -pciio_dmamap_t -get_free_pciio_dmamap(devfs_handle_t pci_bus) -{ - int i; - struct sn_dma_maps_s *sn_dma_map = NULL; - - /* - * Darn, we need to get the maps allocated for this bus. - */ - for (i = 0; i < MAX_PCI_XWIDGET; i++) { - if (busnum_to_pcibr_vhdl[i] == pci_bus) { - sn_dma_map = busnum_to_atedmamaps[i]; - } - } - - /* - * Now get a free dmamap entry from this list. - */ - for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { - if (!sn_dma_map->dma_addr) { - sn_dma_map->dma_addr = -1; - return( (pciio_dmamap_t) sn_dma_map ); - } - } - - return NULL; -} - -/** - * free_pciio_dmamap - free an ATE - * @dma_map: ATE to free - * - * Frees the ATE specified by @dma_map. - */ -void -free_pciio_dmamap(pcibr_dmamap_t dma_map) -{ - struct sn_dma_maps_s *sn_dma_map; - - sn_dma_map = (struct sn_dma_maps_s *) dma_map; - sn_dma_map->dma_addr = 0; -} - -/** - * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum - * @dma_addr: DMA address to look for - * @busnum: PCI bus to look on - * - * Finds the ATE associated with @dma_addr and @busnum. - */ -static struct sn_dma_maps_s * -find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) -{ - - struct sn_dma_maps_s *sn_dma_map = NULL; - int i; - - sn_dma_map = busnum_to_atedmamaps[busnum]; - - for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { - if (sn_dma_map->dma_addr == dma_addr) { - return sn_dma_map; - } - } - - return NULL; -} - -/** - * sn_dma_sync - try to flush DMA buffers into the coherence domain - * @hwdev: device to flush - * - * This routine flushes all DMA buffers for the device into the II of - * the destination hub. - * - * NOTE!: this does not mean that the data is in the "coherence domain", - * but it is very close. In other words, this routine *does not work* - * as advertised due to hardware bugs. That said, it should be good enough for - * most situations. - */ -void -sn_dma_sync(struct pci_dev *hwdev) -{ - -#ifdef SN_DMA_SYNC - - struct sn_device_sysdata *device_sysdata; - volatile unsigned long dummy; - - /* - * A DMA sync is supposed to ensure that - * all the DMA from a particular device - * is complete and coherent. We - * try to do this by - * 1. flushing the write wuffers from Bridge - * 2. flushing the Xbow port. - * Unfortunately, this only gets the DMA transactions 'very close' to - * the coherence domain, but not quite in it. - */ - device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; - dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync; - - /* - * For the Xbow port flush, we may be denied the request because - * someone else may be flushing the port .. try again. - */ - while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) { - udelay(2); - } -#endif -} - -/** - * sn_pci_alloc_consistent - allocate memory for coherent DMA - * @hwdev: device to allocate for - * @size: size of the region - * @dma_handle: DMA (bus) address - * - * pci_alloc_consistent() returns a pointer to a memory region suitable for - * coherent DMA traffic to/from a PCI device. On SN platforms, this means - * that @dma_handle will have the %PCIIO_DMA_CMD flag set. - * - * This interface is usually used for "command" streams (e.g. the command - * queue for a SCSI controller). See Documentation/DMA-mapping.txt for - * more information. Note that this routine will always put a 32 bit - * DMA address into @dma_handle. This is because most devices - * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_ - * DMAs, and unfortunately this interface has to cater to the LCD. Oh well. - * - * Also known as platform_pci_alloc_consistent() by the IA64 machvec code. - */ -void * -sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) -{ - void *cpuaddr; - devfs_handle_t vhdl; - struct sn_device_sysdata *device_sysdata; - unsigned long phys_addr; - pciio_dmamap_t dma_map = 0; - struct sn_dma_maps_s *sn_dma_map; - - *dma_handle = 0; - - /* We can't easily support < 32 bit devices */ - if (IS_PCI32L(hwdev)) - return NULL; - - /* - * Get hwgraph vertex for the device - */ - device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; - vhdl = device_sysdata->vhdl; - - /* - * Allocate the memory. FIXME: if we're allocating for - * two devices on the same bus, we should at least try to - * allocate memory in the same 2 GB window to avoid using - * ATEs for the translation. See the comment above about the - * 32 bit requirement for this function. - */ - if(!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) - return NULL; - - memset(cpuaddr, 0, size); /* have to zero it out */ - - /* physical addr. of the memory we just got */ - phys_addr = __pa(cpuaddr); - - /* - * This will try to use a Direct Map register to do the - * 32 bit DMA mapping, but it may not succeed if another - * device on the same bus is already mapped with different - * attributes or to a different memory region. - */ -#ifdef CONFIG_IA64_SGI_SN1 - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); -#elif defined(CONFIG_IA64_SGI_SN2) - *dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_CMD); -#else -#error unsupported platform -#endif - - /* - * It is a 32 bit card and we cannot do direct mapping, - * so we try to use an ATE. - */ - if (!(*dma_handle)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_CMD); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_CMD); -#else -#error unsupported platform -#endif - if (!dma_map) { - printk(KERN_ERR "sn_pci_alloc_consistent: Unable to " - "allocate anymore 32 bit page map entries.\n"); - BUG(); - } - *dma_handle = (dma_addr_t) pciio_dmamap_addr(dma_map,phys_addr, - size); - sn_dma_map = (struct sn_dma_maps_s *)dma_map; - sn_dma_map->dma_addr = *dma_handle; - } - - return cpuaddr; -} - -/** - * sn_pci_free_consistent - free memory associated with coherent DMAable region - * @hwdev: device to free for - * @size: size to free - * @vaddr: kernel virtual address to free - * @dma_handle: DMA address associated with this region - * - * Frees the memory allocated by pci_alloc_consistent(). Also known - * as platform_pci_free_consistent() by the IA64 machvec code. - */ -void -sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) -{ - struct sn_dma_maps_s *sn_dma_map = NULL; - - /* - * Get the sn_dma_map entry. - */ - if (IS_PCI32_MAPPED(dma_handle)) - sn_dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number); - - /* - * and free it if necessary... - */ - if (sn_dma_map) { - pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); - sn_dma_map->dma_addr = (dma_addr_t)NULL; - } - free_pages((unsigned long) vaddr, get_order(size)); -} - -/** - * sn_pci_map_sg - map a scatter-gather list for DMA - * @hwdev: device to map for - * @sg: scatterlist to map - * @nents: number of entries - * @direction: direction of the DMA transaction - * - * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the - * IA64 machvec code. - */ -int -sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - - int i; - devfs_handle_t vhdl; - dma_addr_t dma_addr; - unsigned long phys_addr; - struct sn_device_sysdata *device_sysdata; - pciio_dmamap_t dma_map; - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - /* - * Get the hwgraph vertex for the device - */ - device_sysdata = (struct sn_device_sysdata *) hwdev->sysdata; - vhdl = device_sysdata->vhdl; - - /* - * Setup a DMA address for each entry in the - * scatterlist. - */ - for (i = 0; i < nents; i++, sg++) { - /* this catches incorrectly written drivers that - attempt to map scatterlists that they have - previously mapped. we print a warning and - continue, but the driver should be fixed */ - switch (((u64)sg->dma_address) >> 60) { - case 0xa: - case 0xb: -#ifdef DEBUG -/* This needs to be cleaned up at some point. */ - NAG("A PCI driver (for device at%8s) has attempted to " - "map a scatterlist that was previously mapped at " - "%p - this is currently being worked around.\n", - hwdev->slot_name, (void *)sg->dma_address); - phys_addr = (u64)sg->dma_address & TO_PHYS_MASK; - break; -#endif - default: /* not previously mapped, get the phys. addr */ - phys_addr = __pa(sg->dma_address); - break; - } - sg->page = NULL; - dma_addr = 0; - - /* - * Handle the most common case: 64 bit cards. This - * call should always succeed. - */ - if (IS_PCIA64(hwdev)) { - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA | - PCIIO_DMA_A64); - sg->dma_address = (char *)dma_addr; - continue; - } - - /* - * Handle 32-63 bit cards via direct mapping - */ - if (IS_PCI32G(hwdev)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif - /* - * See if we got a direct map entry - */ - if (dma_addr) { - sg->dma_address = (char *)dma_addr; - continue; - } - - } - - /* - * It is a 32 bit card and we cannot do direct mapping, - * so we use an ATE. - */ - dma_map = 0; -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif - if (!dma_map) { - printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " - "anymore 32 bit page map entries.\n"); - BUG(); - } - dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length); - sg->dma_address = (char *)dma_addr; - sg->page = (struct page *)dma_map; - - } - - return nents; - -} - -/** - * sn_pci_unmap_sg - unmap a scatter-gather list - * @hwdev: device to unmap - * @sg: scatterlist to unmap - * @nents: number of scatterlist entries - * @direction: DMA direction - * - * Unmap a set of streaming mode DMA translations. Again, cpu read rules - * concerning calls here are the same as for pci_unmap_single() below. Also - * known as sn_pci_unmap_sg() by the IA64 machvec code. - */ -void -sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - int i; - struct sn_dma_maps_s *sn_dma_map; - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - for (i = 0; i < nents; i++, sg++) - if (sg->page) { - /* - * We maintain the DMA Map pointer in sg->page if - * it is ever allocated. - */ - sg->dma_address = 0; - sn_dma_map = (struct sn_dma_maps_s *)sg->page; - pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); - sn_dma_map->dma_addr = 0; - sg->page = 0; - } - -} - -/** - * sn_pci_map_single - map a single region for DMA - * @hwdev: device to map for - * @ptr: kernel virtual address of the region to map - * @size: size of the region - * @direction: DMA direction - * - * Map the region pointed to by @ptr for DMA and return the - * DMA address. Also known as platform_pci_map_single() by - * the IA64 machvec code. - * - * We map this to the one step pciio_dmamap_trans interface rather than - * the two step pciio_dmamap_alloc/pciio_dmamap_addr because we have - * no way of saving the dmamap handle from the alloc to later free - * (which is pretty much unacceptable). - * - * TODO: simplify our interface; - * get rid of dev_desc and vhdl (seems redundant given a pci_dev); - * figure out how to save dmamap handle so can use two step. - */ -dma_addr_t -sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - devfs_handle_t vhdl; - dma_addr_t dma_addr; - unsigned long phys_addr; - struct sn_device_sysdata *device_sysdata; - pciio_dmamap_t dma_map = NULL; - struct sn_dma_maps_s *sn_dma_map; - - if (direction == PCI_DMA_NONE) - BUG(); - - /* SN cannot support DMA addresses smaller than 32 bits. */ - if (IS_PCI32L(hwdev)) - return 0; - - /* - * find vertex for the device - */ - device_sysdata = (struct sn_device_sysdata *)hwdev->sysdata; - vhdl = device_sysdata->vhdl; - - /* - * Call our dmamap interface - */ - dma_addr = 0; - phys_addr = __pa(ptr); - - if (IS_PCIA64(hwdev)) { - /* This device supports 64 bit DMA addresses. */ - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA | - PCIIO_DMA_A64); - return dma_addr; - } - - /* - * Devices that support 32 bit to 63 bit DMA addresses get - * 32 bit DMA addresses. - * - * First try to get a 32 bit direct map register. - */ - if (IS_PCI32G(hwdev)) { -#ifdef CONFIG_IA64_SGI_SN1 - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif - if (dma_addr) - return dma_addr; - } - - /* - * It's a 32 bit card and we cannot do direct mapping so - * let's use the PMU instead. - */ - dma_map = NULL; -#ifdef CONFIG_IA64_SGI_SN1 - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM | - PCIIO_DMA_DATA); -#elif defined(CONFIG_IA64_SGI_SN2) - dma_map = pciio_dmamap_alloc(vhdl, NULL, size, - ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) | - PCIIO_DMA_DATA); -#else -#error unsupported platform -#endif - - if (!dma_map) { - printk(KERN_ERR "pci_map_single: Unable to allocate anymore " - "32 bit page map entries.\n"); - BUG(); - } - - dma_addr = (dma_addr_t) pciio_dmamap_addr(dma_map, phys_addr, size); - sn_dma_map = (struct sn_dma_maps_s *)dma_map; - sn_dma_map->dma_addr = dma_addr; - - return ((dma_addr_t)dma_addr); -} - -/** - * sn_pci_unmap_single - unmap a region used for DMA - * @hwdev: device to unmap - * @dma_addr: DMA address to unmap - * @size: size of region - * @direction: DMA direction - * - * Unmaps the region pointed to by @dma_addr. Also known as - * platform_pci_unmap_single() by the IA64 machvec code. - */ -void -sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) -{ - struct sn_dma_maps_s *sn_dma_map = NULL; - - if (direction == PCI_DMA_NONE) - BUG(); - - /* - * Get the sn_dma_map entry. - */ - if (IS_PCI32_MAPPED(dma_addr)) - sn_dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number); - - /* - * and free it if necessary... - */ - if (sn_dma_map) { - pciio_dmamap_done((pciio_dmamap_t)sn_dma_map); - pciio_dmamap_free((pciio_dmamap_t)sn_dma_map); - sn_dma_map->dma_addr = (dma_addr_t)NULL; - } -} - -/** - * sn_pci_dma_sync_single - make sure all DMAs have completed - * @hwdev: device to sync - * @dma_handle: DMA address to sync - * @size: size of region - * @direction: DMA direction - * - * This routine is supposed to sync the DMA region specified - * by @dma_handle into the 'coherence domain'. See sn_dma_sync() - * above for more information. Also known as - * platform_pci_dma_sync_single() by the IA64 machvec code. - */ -void -sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - - sn_dma_sync(hwdev); -} - -/** - * sn_pci_dma_sync_sg - make sure all DMAs have completed - * @hwdev: device to sync - * @sg: scatterlist to sync - * @nents: number of entries in the scatterlist - * @direction: DMA direction - * - * This routine is supposed to sync the DMA regions specified - * by @sg into the 'coherence domain'. See sn_dma_sync() - * above for more information. Also known as - * platform_pci_dma_sync_sg() by the IA64 machvec code. - */ -void -sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - if (direction == PCI_DMA_NONE) - BUG(); - - sn_dma_sync(hwdev); -} - -/** - * sn_dma_address - get the DMA address for the first entry of a scatterlist - * @sg: sg to look at - * - * Gets the DMA address for the scatterlist @sg. Also known as - * platform_dma_address() by the IA64 machvec code. - */ -unsigned long -sn_dma_address(struct scatterlist *sg) -{ - return ((unsigned long)sg->dma_address); -} - -/** - * sn_dma_supported - test a DMA mask - * @hwdev: device to test - * @mask: DMA mask to test - * - * Return whether the given PCI device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask to - * this function. Of course, SN only supports devices that have 32 or more - * address bits when using the PMU. We could theoretically support <32 bit - * cards using direct mapping, but we'll worry about that later--on the off - * chance that someone actually wants to use such a card. - */ -int -sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) -{ - if (mask < 0xffffffff) - return 0; - return 1; -} - -EXPORT_SYMBOL(sn_pci_unmap_single); -EXPORT_SYMBOL(sn_pci_map_single); -EXPORT_SYMBOL(sn_pci_dma_sync_single); -EXPORT_SYMBOL(sn_pci_map_sg); -EXPORT_SYMBOL(sn_pci_unmap_sg); -EXPORT_SYMBOL(sn_pci_alloc_consistent); -EXPORT_SYMBOL(sn_pci_free_consistent); -EXPORT_SYMBOL(sn_dma_address); -EXPORT_SYMBOL(sn_pci_dma_supported); - diff -Nru a/arch/ia64/sn/io/pciba.c b/arch/ia64/sn/io/pciba.c --- a/arch/ia64/sn/io/pciba.c Wed Jun 4 07:34:29 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,950 +0,0 @@ -/* - * arch/ia64/sn/io/pciba.c - * - * IRIX PCIBA-inspired user mode PCI interface - * - * requires: devfs - * - * device nodes show up in /dev/pci/BB/SS.F (where BB is the bus the - * device is on, SS is the slot the device is in, and F is the - * device's function on a multi-function card). - * - * when compiled into the kernel, it will only be initialized by the - * sgi sn1 specific initialization code. in this case, device nodes - * are under /dev/hw/..../ - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of - * this archive for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * 03262001 - Initial version by Chad Talbott - */ - - -/* jesse's beefs: - - register_pci_device should be documented - - grossness with do_swap should be documented - - big, gross union'ized node_data should be replaced with independent - structures - - replace global list of nodes with global lists of resources. could - use object oriented approach of allocating and cleaning up - resources. - -*/ - - -#include -#ifndef CONFIG_DEVFS_FS -# error PCIBA requires devfs -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - - -MODULE_DESCRIPTION("User mode PCI interface"); -MODULE_AUTHOR("Chad Talbott"); - - -#undef DEBUG_PCIBA -/* #define DEBUG_PCIBA */ - -#undef TRACE_PCIBA -/* #define TRACE_PCIBA */ - -#if defined(DEBUG_PCIBA) -# define DPRINTF(x...) printk(KERN_DEBUG x) -#else -# define DPRINTF(x...) -#endif - -#if defined(TRACE_PCIBA) -# if defined(__GNUC__) -# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ - __FILE__, __LINE__, __FUNCTION__) -# else -# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) -# endif -#else -# define TRACE() -#endif - - -typedef enum { failure, success } status; -typedef enum { false, true } boolean; - - -/* major data structures: - - struct node_data - - - one for each file registered with devfs. contains everything - that any file's fops would need to know about. - - struct dma_allocation - - - a single DMA allocation. only the 'dma' nodes care about - these. they are there primarily to allow the driver to look - up the kernel virtual address of dma buffers allocated by - pci_alloc_consistent, as the application is only given the - physical address (to program the device's dma, presumably) and - cannot supply the kernel virtual address when freeing the - buffer. - - it's also useful to maintain a list of buffers allocated - through a specific node to allow some sanity checking by this - driver. this prevents (for example) a broken application from - freeing buffers that it didn't allocate, or buffers allocated - on another node. - - global_node_list - - - a list of all nodes allocated. this allows the driver to free - all the memory it has 'kmalloc'd in case of an error, or on - module removal. - - global_dma_list - - - a list of all dma buffers allocated by this driver. this - allows the driver to 'pci_free_consistent' all buffers on - module removal or error. - -*/ - - -struct node_data { - /* flat list of all the device nodes. makes it easy to free - them all when we're unregistered */ - struct list_head global_node_list; - devfs_handle_t devfs_handle; - - void (* cleanup)(struct node_data *); - - union { - struct { - struct pci_dev * dev; - struct list_head dma_allocs; - boolean mmapped; - } dma; - struct { - struct pci_dev * dev; - u32 saved_rom_base_reg; - boolean mmapped; - } rom; - struct { - struct resource * res; - } base; - struct { - struct pci_dev * dev; - } config; - } u; -}; - -struct dma_allocation { - struct list_head list; - - dma_addr_t handle; - void * va; - size_t size; -}; - - -static LIST_HEAD(global_node_list); -static LIST_HEAD(global_dma_list); - - -/* module entry points */ -int __init pciba_init(void); -void __exit pciba_exit(void); - -static status __init register_with_devfs(void); -static void __exit unregister_with_devfs(void); - -static status __init register_pci_device(devfs_handle_t device_dir_handle, - struct pci_dev * dev); - -/* file operations */ -static int generic_open(struct inode * inode, struct file * file); -static int rom_mmap(struct file * file, struct vm_area_struct * vma); -static int rom_release(struct inode * inode, struct file * file); -static int base_mmap(struct file * file, struct vm_area_struct * vma); -static int config_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg); -static int dma_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg); -static int dma_mmap(struct file * file, struct vm_area_struct * vma); - -/* support routines */ -static int mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va); -static int mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va); - -#ifdef DEBUG_PCIBA -static void dump_nodes(struct list_head * nodes); -static void dump_allocations(struct list_head * dalp); -#endif - -/* file operations for each type of node */ -static struct file_operations rom_fops = { - owner: THIS_MODULE, - mmap: rom_mmap, - open: generic_open, - release: rom_release -}; - - -static struct file_operations base_fops = { - owner: THIS_MODULE, - mmap: base_mmap, - open: generic_open -}; - - -static struct file_operations config_fops = { - owner: THIS_MODULE, - ioctl: config_ioctl, - open: generic_open -}; - -static struct file_operations dma_fops = { - owner: THIS_MODULE, - ioctl: dma_ioctl, - mmap: dma_mmap, - open: generic_open -}; - - -module_init(pciba_init); -module_exit(pciba_exit); - - -int __init -pciba_init(void) -{ - TRACE(); - - if (register_with_devfs() == failure) - return 1; /* failure */ - - printk("PCIBA (a user mode PCI interface) initialized.\n"); - - return 0; /* success */ -} - - -void __exit -pciba_exit(void) -{ - TRACE(); - - /* FIXME: should also free all that memory that we allocated - ;) */ - unregister_with_devfs(); -} - - -# if 0 -static void __exit -free_nodes(void) -{ - struct node_data * nd; - - TRACE(); - - list_for_each(nd, &node_list) { - kfree(list_entry(nd, struct nd, node_list)); - } -} -#endif - -#if !defined(CONFIG_IA64_SGI_SN1) - -static status __init -register_with_devfs(void) -{ - struct pci_dev * dev = NULL; - devfs_handle_t device_dir_handle; - char devfs_path[40]; - - TRACE(); - - if (!devfs_mk_dir(NULL, "pci", NULL)) - return failure; - - /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ - - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - sprintf(devfs_path, "pci/%02x/%02x.%x", - dev->bus->number, - PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - - device_dir_handle = - devfs_mk_dir(NULL, devfs_path, NULL); - if (device_dir_handle == NULL) - return failure; - - if (register_pci_device(device_dir_handle, dev) == failure) { - devfs_remove("pci"); - return failure; - } - } - - return success; -} - -#else - -extern devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -static status __init -register_with_devfs(void) -{ - struct pci_dev * dev = NULL; - devfs_handle_t device_dir_handle; - - TRACE(); - - /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */ - - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - device_dir_handle = devfn_to_vertex(dev->bus->number, - dev->devfn); - if (device_dir_handle == NULL) - return failure; - - if (register_pci_device(device_dir_handle, dev) == failure) { - devfs_remove("pci"); - return failure; - } - } - - return success; -} - -static void __exit -unregister_with_devfs(void) -{ - struct list_head * lhp; - struct node_data * nd; - - TRACE(); - - list_for_each(lhp, &global_node_list) { - nd = list_entry(lhp, struct node_data, global_node_list); - devfs_unregister(nd->devfs_handle); - } - -} - - -struct node_data * new_node(void) -{ - struct node_data * node; - - TRACE(); - - node = kmalloc(sizeof(struct node_data), GFP_KERNEL); - if (node == NULL) - return NULL; - list_add(&node->global_node_list, &global_node_list); - return node; -} - - -void dma_cleanup(struct node_data * dma_node) -{ - TRACE(); - - /* FIXME: should free these allocations */ -#ifdef DEBUG_PCIBA - dump_allocations(&dma_node->u.dma.dma_allocs); -#endif - devfs_unregister(dma_node->devfs_handle); -} - - -void init_dma_node(struct node_data * node, - struct pci_dev * dev, devfs_handle_t dh) -{ - TRACE(); - - node->devfs_handle = dh; - node->u.dma.dev = dev; - node->cleanup = dma_cleanup; - INIT_LIST_HEAD(&node->u.dma.dma_allocs); -} - - -void rom_cleanup(struct node_data * rom_node) -{ - TRACE(); - - if (rom_node->u.rom.mmapped) - pci_write_config_dword(rom_node->u.rom.dev, - PCI_ROM_ADDRESS, - rom_node->u.rom.saved_rom_base_reg); - devfs_unregister(rom_node->devfs_handle); -} - - -void init_rom_node(struct node_data * node, - struct pci_dev * dev, devfs_handle_t dh) -{ - TRACE(); - - node->devfs_handle = dh; - node->u.rom.dev = dev; - node->cleanup = rom_cleanup; - node->u.rom.mmapped = false; -} - - -static status __init -register_pci_device(devfs_handle_t device_dir_handle, struct pci_dev * dev) -{ - struct node_data * nd; - char devfs_path[20]; - devfs_handle_t node_devfs_handle; - int ri; - - TRACE(); - - - /* register nodes for all the device's base address registers */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (pci_resource_len(dev, ri) != 0) { - sprintf(devfs_path, "base/%d", ri); - if (devfs_register(device_dir_handle, devfs_path, - DEVFS_FL_NONE, - 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - } - } - - /* register a node corresponding to the first MEM resource on - the device */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (dev->resource[ri].flags & IORESOURCE_MEM && - pci_resource_len(dev, ri) != 0) { - if (devfs_register(device_dir_handle, "mem", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - break; - } - } - - /* also register a node corresponding to the first IO resource - on the device */ - for (ri = 0; ri < PCI_ROM_RESOURCE; ri++) { - if (dev->resource[ri].flags & IORESOURCE_IO && - pci_resource_len(dev, ri) != 0) { - if (devfs_register(device_dir_handle, "io", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR | S_IWUSR, - &base_fops, - &dev->resource[ri]) == NULL) - return failure; - break; - } - } - - /* register a node corresponding to the device's ROM resource, - if present */ - if (pci_resource_len(dev, PCI_ROM_RESOURCE) != 0) { - nd = new_node(); - if (nd == NULL) - return failure; - node_devfs_handle = devfs_register(device_dir_handle, "rom", - DEVFS_FL_NONE, 0, 0, - S_IFREG | S_IRUSR, - &rom_fops, nd); - if (node_devfs_handle == NULL) - return failure; - init_rom_node(nd, dev, node_devfs_handle); - } - - /* register a node that allows ioctl's to read and write to - the device's config space */ - if (devfs_register(device_dir_handle, "config", DEVFS_FL_NONE, - 0, 0, S_IFREG | S_IRUSR | S_IWUSR, - &config_fops, dev) == NULL) - return failure; - - - /* finally, register a node that allows ioctl's to allocate - and free DMA buffers, as well as memory map those - buffers. */ - nd = new_node(); - if (nd == NULL) - return failure; - node_devfs_handle = - devfs_register(device_dir_handle, "dma", DEVFS_FL_NONE, - 0, 0, S_IFREG | S_IRUSR | S_IWUSR, - &dma_fops, nd); - if (node_devfs_handle == NULL) - return failure; - init_dma_node(nd, dev, node_devfs_handle); - -#ifdef DEBUG_PCIBA - dump_nodes(&global_node_list); -#endif - - return success; -} - - -static int -generic_open(struct inode * inode, struct file * file) -{ - TRACE(); - - /* FIXME: should check that they're not trying to open the ROM - writable */ - - return 0; /* success */ -} - - -static int -rom_mmap(struct file * file, struct vm_area_struct * vma) -{ - unsigned long pci_pa; - struct node_data * nd; - - TRACE(); - - nd = (struct node_data * )file->private_data; - - pci_pa = pci_resource_start(nd->u.rom.dev, PCI_ROM_RESOURCE); - - if (!nd->u.rom.mmapped) { - nd->u.rom.mmapped = true; - DPRINTF("Enabling ROM address decoder.\n"); - DPRINTF( -"rom_mmap: FIXME: some cards do not allow both ROM and memory addresses to\n" -"rom_mmap: FIXME: be enabled simultaneously, as they share a decoder.\n"); - pci_read_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - &nd->u.rom.saved_rom_base_reg); - DPRINTF("ROM base address contains %x\n", - nd->u.rom.saved_rom_base_reg); - pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - nd->u.rom.saved_rom_base_reg | - PCI_ROM_ADDRESS_ENABLE); - } - - return mmap_pci_address(vma, pci_pa); -} - - -static int -rom_release(struct inode * inode, struct file * file) -{ - struct node_data * nd; - - TRACE(); - - nd = (struct node_data * )file->private_data; - - if (nd->u.rom.mmapped) { - nd->u.rom.mmapped = false; - DPRINTF("Disabling ROM address decoder.\n"); - pci_write_config_dword(nd->u.rom.dev, PCI_ROM_ADDRESS, - nd->u.rom.saved_rom_base_reg); - } - return 0; /* indicate success */ -} - - -static int -base_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct resource * resource; - - TRACE(); - - resource = (struct resource *)file->private_data; - - return mmap_pci_address(vma, resource->start); -} - - -static int -config_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct pci_dev * dev; - - union cfg_data { - uint8_t byte; - uint16_t word; - uint32_t dword; - } read_data, write_data; - - int dir, size, offset; - - TRACE(); - - DPRINTF("cmd = %x (DIR = %x, TYPE = %x, NR = %x, SIZE = %x)\n", - cmd, - _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); - DPRINTF("arg = %lx\n", arg); - - dev = (struct pci_dev *)file->private_data; - - /* PCIIOCCFG{RD,WR}: read and/or write PCI configuration - space. If both, the read happens first (this becomes a swap - operation, atomic with respect to other updates through - this path). */ - - dir = _IOC_DIR(cmd); - -#define do_swap(suffix, type) \ - do { \ - if (dir & _IOC_READ) { \ - pci_read_config_##suffix(dev, _IOC_NR(cmd), \ - &read_data.suffix); \ - } \ - if (dir & _IOC_WRITE) { \ - get_user(write_data.suffix, (type)arg); \ - pci_write_config_##suffix(dev, _IOC_NR(cmd), \ - write_data.suffix); \ - } \ - if (dir & _IOC_READ) { \ - put_user(read_data.suffix, (type)arg); \ - } \ - } while (0) - - size = _IOC_SIZE(cmd); - offset = _IOC_NR(cmd); - - DPRINTF("sanity check\n"); - if (((size > 0) || (size <= 4)) && - ((offset + size) <= 256) && - (dir & (_IOC_READ | _IOC_WRITE))) { - - switch (size) - { - case 1: - do_swap(byte, uint8_t *); - break; - case 2: - do_swap(word, uint16_t *); - break; - case 4: - do_swap(dword, uint32_t *); - break; - default: - DPRINTF("invalid ioctl\n"); - return -EINVAL; - } - } else - return -EINVAL; - - return 0; -} - - -#ifdef DEBUG_PCIBA -static void -dump_allocations(struct list_head * dalp) -{ - struct dma_allocation * dap; - struct list_head * p; - - printk("{\n"); - list_for_each(p, dalp) { - dap = list_entry(p, struct dma_allocation, - list); - printk(" handle = %lx, va = %p\n", - dap->handle, dap->va); - } - printk("}\n"); -} - -static void -dump_nodes(struct list_head * nodes) -{ - struct node_data * ndp; - struct list_head * p; - - printk("{\n"); - list_for_each(p, nodes) { - ndp = list_entry(p, struct node_data, - global_node_list); - printk(" %p\n", (void *)ndp); - } - printk("}\n"); -} - - -#if 0 -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) - -static void -test_list(void) -{ - u64 i; - LIST_HEAD(the_list); - - for (i = 0; i < 5; i++) { - struct dma_allocation * new_alloc; - NEW(new_alloc); - new_alloc->va = (void *)i; - new_alloc->handle = 5*i; - printk("%d - the_list->next = %lx\n", i, the_list.next); - list_add(&new_alloc->list, &the_list); - } - dump_allocations(&the_list); -} -#endif -#endif - - -static LIST_HEAD(dma_buffer_list); - - -static int -dma_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, - unsigned long arg) -{ - struct node_data * nd; - uint64_t argv; - int result; - struct dma_allocation * dma_alloc; - struct list_head * iterp; - - TRACE(); - - DPRINTF("cmd = %x\n", cmd); - DPRINTF("arg = %lx\n", arg); - - nd = (struct node_data *)file->private_data; - -#ifdef DEBUG_PCIBA - DPRINTF("at dma_ioctl entry\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - - switch (cmd) { - case PCIIOCDMAALLOC: - /* PCIIOCDMAALLOC: allocate a chunk of physical memory - and set it up for DMA. Return the PCI address that - gets to it. */ - DPRINTF("case PCIIOCDMAALLOC (%lx)\n", PCIIOCDMAALLOC); - - if ( (result = get_user(argv, (uint64_t *)arg)) ) - return result; - DPRINTF("argv (size of buffer) = %lx\n", argv); - - dma_alloc = (struct dma_allocation *) - kmalloc(sizeof(struct dma_allocation), GFP_KERNEL); - if (dma_alloc == NULL) - return -ENOMEM; - - dma_alloc->size = (size_t)argv; - dma_alloc->va = pci_alloc_consistent(nd->u.dma.dev, - dma_alloc->size, - &dma_alloc->handle); - DPRINTF("dma_alloc->va = %p, dma_alloc->handle = %lx\n", - dma_alloc->va, dma_alloc->handle); - if (dma_alloc->va == NULL) { - kfree(dma_alloc); - return -ENOMEM; - } - - list_add(&dma_alloc->list, &nd->u.dma.dma_allocs); - if ( (result = put_user((uint64_t)dma_alloc->handle, - (uint64_t *)arg)) ) { - DPRINTF("put_user failed\n"); - pci_free_consistent(nd->u.dma.dev, (size_t)argv, - dma_alloc->va, dma_alloc->handle); - kfree(dma_alloc); - return result; - } - -#ifdef DEBUG_PCIBA - DPRINTF("after insertion\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - break; - - case PCIIOCDMAFREE: - DPRINTF("case PCIIOCDMAFREE (%lx)\n", PCIIOCDMAFREE); - - if ( (result = get_user(argv, (uint64_t *)arg)) ) { - DPRINTF("get_user failed\n"); - return result; - } - - DPRINTF("argv (physical address of DMA buffer) = %lx\n", argv); - list_for_each(iterp, &nd->u.dma.dma_allocs) { - struct dma_allocation * da = - list_entry(iterp, struct dma_allocation, list); - if (da->handle == argv) { - pci_free_consistent(nd->u.dma.dev, da->size, - da->va, da->handle); - list_del(&da->list); - kfree(da); -#ifdef DEBUG_PCIBA - DPRINTF("after deletion\n"); - dump_allocations(&nd->u.dma.dma_allocs); -#endif - return 0; /* success */ - } - } - /* previously allocated dma buffer wasn't found */ - DPRINTF("attempt to free invalid dma handle\n"); - return -EINVAL; - - default: - DPRINTF("undefined ioctl\n"); - return -EINVAL; - } - - DPRINTF("success\n"); - return 0; -} - - -static int -dma_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct node_data * nd; - struct list_head * iterp; - int result; - - TRACE(); - - nd = (struct node_data *)file->private_data; - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - DPRINTF("offset = %lx\n", vma->vm_pgoff); - - /* get kernel virtual address for the dma buffer (necessary - * for the mmap). */ - list_for_each(iterp, &nd->u.dma.dma_allocs) { - struct dma_allocation * da = - list_entry(iterp, struct dma_allocation, list); - /* why does mmap shift its offset argument? */ - if (da->handle == vma->vm_pgoff << PAGE_SHIFT) { - DPRINTF("found dma handle\n"); - if ( (result = mmap_kernel_address(vma, - da->va)) ) { - return result; /* failure */ - } else { - /* it seems like at least one of these - should show up in user land.... - I'm missing something */ - *(char *)da->va = 0xaa; - strncpy(da->va, " Toastie!", da->size); - if (put_user(0x18badbeeful, - (u64 *)vma->vm_start)) - DPRINTF("put_user failed?!\n"); - return 0; /* success */ - } - - } - } - DPRINTF("attempt to mmap an invalid dma handle\n"); - return -EINVAL; -} - - -static int -mmap_pci_address(struct vm_area_struct * vma, unsigned long pci_va) -{ - unsigned long pci_pa; - - TRACE(); - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - - /* the size of the vma doesn't necessarily correspond to the - size specified in the mmap call. So we can't really do any - kind of sanity check here. This is a dangerous driver, and - it's very easy for a user process to kill the machine. */ - - DPRINTF("PCI base at virtual address %lx\n", pci_va); - /* the __pa macro is intended for region 7 on IA64, so it - doesn't work for region 6 */ - /* pci_pa = __pa(pci_va); */ - /* should be replaced by __tpa or equivalent (preferably a - generic equivalent) */ - pci_pa = pci_va & ~0xe000000000000000ul; - DPRINTF("PCI base at physical address %lx\n", pci_pa); - - /* there are various arch-specific versions of this function - defined in linux/drivers/char/mem.c, but it would be nice - if all architectures put it in pgtable.h. it's defined - there for ia64.... */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - - return io_remap_page_range(vma->vm_start, pci_pa, - vma->vm_end-vma->vm_start, - vma->vm_page_prot); -} - - -static int -mmap_kernel_address(struct vm_area_struct * vma, void * kernel_va) -{ - unsigned long kernel_pa; - - TRACE(); - - DPRINTF("vma->vm_start is %lx\n", vma->vm_start); - DPRINTF("vma->vm_end is %lx\n", vma->vm_end); - - /* the size of the vma doesn't necessarily correspond to the - size specified in the mmap call. So we can't really do any - kind of sanity check here. This is a dangerous driver, and - it's very easy for a user process to kill the machine. */ - - DPRINTF("mapping virtual address %p\n", kernel_va); - kernel_pa = __pa(kernel_va); - DPRINTF("mapping physical address %lx\n", kernel_pa); - - vma->vm_flags |= VM_NONCACHED | VM_RESERVED | VM_IO; - - return remap_page_range(vma->vm_start, kernel_pa, - vma->vm_end-vma->vm_start, - vma->vm_page_prot); -} diff -Nru a/arch/ia64/sn/io/pciio.c b/arch/ia64/sn/io/pciio.c --- a/arch/ia64/sn/io/pciio.c Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1507 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#define USRPCI 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Must be before iograph.h to get MAX_PORT_NUM */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_PCIIO -#undef DEBUG_PCIIO /* turn this on for yet more console output */ - - -#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DO_DEL(ptr) (kfree(ptr)) - -char pciio_info_fingerprint[] = "pciio_info"; - -cdl_p pciio_registry = NULL; - -int -badaddr_val(volatile void *addr, int len, volatile void *ptr) -{ - int ret = 0; - volatile void *new_addr; - - switch (len) { - case 4: - new_addr = (void *)(((u64) addr)^4); - ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr); - break; - default: - printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len); - } - - if (ret < 0) - panic("badaddr_val: unexpected status (%d) in probing", ret); - return(ret); - -} - - -nasid_t -get_console_nasid(void) -{ - extern nasid_t console_nasid; - if (console_nasid < 0) { - console_nasid = ia64_sn_get_console_nasid(); - if (console_nasid < 0) { -// ZZZ What do we do if we don't get a console nasid on the hardware???? - if (IS_RUNNING_ON_SIMULATOR() ) - console_nasid = master_nasid; - } - } - return console_nasid; -} - -int -hub_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return(0); -} - -int -hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) -{ - return(0); -} - -void -ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror) -{ -} - -/****** - ****** end hack defines ...... - ******/ - - - - -/* ===================================================================== - * PCI Generic Bus Provider - * Implement PCI provider operations. The pciio* layer provides a - * platform-independent interface for PCI devices. This layer - * switches among the possible implementations of a PCI adapter. - */ - -/* ===================================================================== - * Provider Function Location SHORTCUT - * - * On platforms with only one possible PCI provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#if defined(CONFIG_IA64_SGI_SN1) -/* - * For the moment, we will assume that IP27 - * only use Bridge ASICs to provide PCI support. - */ -#include -#define DEV_FUNC(dev,func) pcibr_##func -#define CAST_PIOMAP(x) ((pcibr_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pcibr_dmamap_t)(x)) -#define CAST_INTR(x) ((pcibr_intr_t)(x)) -#endif /* CONFIG_IA64_SGI_SN1 */ - -/* ===================================================================== - * Function Table of Contents - */ - -#if !defined(DEV_FUNC) -static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); -#endif - -pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pciio_piomap_free(pciio_piomap_t); -caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); - -void pciio_piomap_done(pciio_piomap_t); -caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); - -iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); -void pciio_dmamap_done(pciio_dmamap_t); -iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pciio_dmamap_drain(pciio_dmamap_t); -void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pciio_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); - -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pciio_intr_free(pciio_intr_t); -int pciio_intr_connect(pciio_intr_t); -void pciio_intr_disconnect(pciio_intr_t); -devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); - -void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); - -void pciio_provider_startup(devfs_handle_t); -void pciio_provider_shutdown(devfs_handle_t); - -pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); -devfs_handle_t pciio_intr_dev_get(pciio_intr_t); - -devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); -pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); -pciio_space_t pciio_pio_space_get(pciio_piomap_t); -iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); -ulong pciio_pio_mapsz_get(pciio_piomap_t); -caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); - -devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); -pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); - -pciio_info_t pciio_info_chk(devfs_handle_t); -pciio_info_t pciio_info_get(devfs_handle_t); -void pciio_info_set(devfs_handle_t, pciio_info_t); -devfs_handle_t pciio_info_dev_get(pciio_info_t); -pciio_slot_t pciio_info_slot_get(pciio_info_t); -pciio_function_t pciio_info_function_get(pciio_info_t); -pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); -pciio_device_id_t pciio_info_device_id_get(pciio_info_t); -devfs_handle_t pciio_info_master_get(pciio_info_t); -arbitrary_info_t pciio_info_mfast_get(pciio_info_t); -pciio_provider_t *pciio_info_pops_get(pciio_info_t); -error_handler_f *pciio_info_efunc_get(pciio_info_t); -error_handler_arg_t *pciio_info_einfo_get(pciio_info_t); -pciio_space_t pciio_info_bar_space_get(pciio_info_t, int); -iopaddr_t pciio_info_bar_base_get(pciio_info_t, int); -size_t pciio_info_bar_size_get(pciio_info_t, int); -iopaddr_t pciio_info_rom_base_get(pciio_info_t); -size_t pciio_info_rom_size_get(pciio_info_t); - -void pciio_init(void); -int pciio_attach(devfs_handle_t); - -void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); -void pciio_provider_unregister(devfs_handle_t); -pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); - -int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); -void pciio_driver_unregister(char *driver_prefix); - -devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); - -void pciio_device_unregister(devfs_handle_t); -pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -void pciio_device_info_free(pciio_info_t); -devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); -void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t, int); -int pciio_device_detach(devfs_handle_t, int); -void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); - -int pciio_reset(devfs_handle_t); -int pciio_write_gather_flush(devfs_handle_t); -int pciio_slot_inuse(devfs_handle_t); - -/* ===================================================================== - * Provider Function Location - * - * If there is more than one possible provider for - * this platform, we need to examine the master - * vertex of the current vertex for a provider - * function structure, and indirect through the - * appropriately named member. - */ - -#if !defined(DEV_FUNC) - -static pciio_provider_t * -pciio_to_provider_fns(devfs_handle_t dev) -{ - pciio_info_t card_info; - pciio_provider_t *provider_fns; - - /* - * We're called with two types of vertices, one is - * the bridge vertex (ends with "pci") and the other is the - * pci slot vertex (ends with "pci/[0-8]"). For the first type - * we need to get the provider from the PFUNCS label. For - * the second we get it from fastinfo/c_pops. - */ - provider_fns = pciio_provider_fns_get(dev); - if (provider_fns == NULL) { - card_info = pciio_info_get(dev); - if (card_info != NULL) { - provider_fns = pciio_info_pops_get(card_info); - } - } - - if (provider_fns == NULL) -#if defined(SUPPORT_PRINTING_V_FORMAT) - PRINT_PANIC("%v: provider_fns == NULL", dev); -#else - PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev); -#endif - - return provider_fns; - -} - -#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) -#define CAST_INTR(x) ((pciio_intr_t)(x)) -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) -#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * pciio space on a specified card - */ - -pciio_piomap_t -pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* lowest address (or offset in window) */ - size_t byte_count, /* size of region containing our mappings */ - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); -} - -void -pciio_piomap_free(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_free) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ - iopaddr_t pciio_addr, /* map for this pciio address */ - size_t byte_count) -{ /* map this many bytes */ - pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) - (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); - - return pciio_piomap->pp_kvaddr; -} - -void -pciio_piomap_done(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_done) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, space, addr, byte_count, flags); -} - -caddr_t -pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - pciio_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - pciio_piomap_t map = 0; - int errfree = 0; - caddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_piotrans_addr - (dev, dev_desc, space, addr, byte_count, flags); - if (res) - return res; /* pciio_piotrans worked */ - - if (!map) { - map = pciio_piomap_alloc - (dev, dev_desc, space, addr, byte_count, byte_count, flags); - if (!map) - return res; /* pciio_piomap_alloc failed */ - errfree = 1; - } - - res = pciio_piomap_addr - (map, addr, byte_count); - if (!res) { - if (errfree) - pciio_piomap_free(map); - return res; /* pciio_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_piomap_addr succeeded */ -} - -iopaddr_t -pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ - device_desc_t dev_desc, /* Device descriptor */ - pciio_space_t space, /* MEM32/MEM64/IO */ - size_t byte_count, /* Size of mapping */ - size_t align) -{ /* Alignment needed */ - if (align < NBPP) - align = NBPP; - return DEV_FUNC(dev, piospace_alloc) - (dev, dev_desc, space, byte_count, align); -} - -void -pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ - pciio_space_t space, /* Type of space */ - iopaddr_t pciaddr, /* starting address */ - size_t byte_count) -{ /* Range of address */ - DEV_FUNC(dev, piospace_free) - (dev, space, pciaddr, byte_count); -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from pci space to system - * physical space. - */ - -pciio_dmamap_t -pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -alenlist_t -pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(pciio_dmamap, dmamap_list) - (CAST_DMAMAP(pciio_dmamap), alenlist, flags); -} - -void -pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -alenlist_t -pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -iopaddr_t -pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - pciio_dmamap_t *mapp, /* map to use, then map we used */ - unsigned flags) -{ /* PIO flags */ - pciio_dmamap_t map = 0; - int errfree = 0; - iopaddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_dmatrans_addr - (dev, dev_desc, paddr, byte_count, flags); - if (res) - return res; /* pciio_dmatrans worked */ - - if (!map) { - map = pciio_dmamap_alloc - (dev, dev_desc, byte_count, flags); - if (!map) - return res; /* pciio_dmamap_alloc failed */ - errfree = 1; - } - - res = pciio_dmamap_addr - (map, paddr, byte_count); - if (!res) { - if (errfree) - pciio_dmamap_free(map); - return res; /* pciio_dmamap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_dmamap_addr succeeded */ -} - -void -pciio_dmamap_drain(pciio_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -pciio_intr_t -pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_intr_line_t lines, /* INTR line(s) to attach */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, lines, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -pciio_intr_free(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - -/* - * Associate resources allocated with a previous pciio_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -pciio_intr_connect(pciio_intr_t intr_hdl) /* pciio intr resource handle */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl)); -} - -/* - * Disassociate handler with the specified interrupt. - */ -void -pciio_intr_disconnect(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -pciio_intr_cpu_get(pciio_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - -void -pciio_slot_func_to_name(char *name, - pciio_slot_t slot, - pciio_function_t func) -{ - /* - * standard connection points: - * - * PCIIO_SLOT_NONE: .../pci/direct - * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 - * multifunction: .../pci/ ie. .../pci/3c - */ - - if (slot == PCIIO_SLOT_NONE) - sprintf(name, "direct"); - else if (func == PCIIO_FUNC_NONE) - sprintf(name, "%d", slot); - else - sprintf(name, "%d%c", slot, 'a'+func); -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -pciio_provider_startup(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_startup) - (pciio_provider); -} - -/* - * Shutdown a crosstalk provider - */ -void -pciio_provider_shutdown(devfs_handle_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_shutdown) - (pciio_provider); -} - -/* - * Specify endianness constraints. The driver tells us what the device - * does and how it would like to see things in memory. We reply with - * how things will actually appear in memory. - */ -pciio_endian_t -pciio_endian_set(devfs_handle_t dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE)); - ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE)); - -#if DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_ALERT "%v: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#else - printk(KERN_ALERT "0x%x: pciio_endian_set is going away.\n" - "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n" - "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n", - dev); -#endif -#endif - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -/* - * Specify PCI arbitration priority. - */ -pciio_priority_t -pciio_priority_set(devfs_handle_t dev, - pciio_priority_t device_prio) -{ - ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); - - return DEV_FUNC(dev, priority_set) - (dev, device_prio); -} - -/* - * Read value of configuration register - */ -uint64_t -pciio_config_get(devfs_handle_t dev, - unsigned reg, - unsigned size) -{ - uint64_t value = 0; - unsigned shift = 0; - - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - value |= DEV_FUNC(dev, config_get) - (dev, reg, biw) << shift; - - shift += 8*biw; - reg += biw; - size -= biw; - } - return value; -} - -/* - * Change value of configuration register - */ -void -pciio_config_set(devfs_handle_t dev, - unsigned reg, - unsigned size, - uint64_t value) -{ - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - DEV_FUNC(dev, config_set) - (dev, reg, biw, value); - reg += biw; - size -= biw; - value >>= biw * 8; - } -} - -/* ===================================================================== - * GENERIC PCI SUPPORT FUNCTIONS - */ - -/* - * Issue a hardware reset to a card. - */ -int -pciio_reset(devfs_handle_t dev) -{ - return DEV_FUNC(dev, reset) (dev); -} - -/* - * flush write gather buffers - */ -int -pciio_write_gather_flush(devfs_handle_t dev) -{ - return DEV_FUNC(dev, write_gather_flush) (dev); -} - -devfs_handle_t -pciio_intr_dev_get(pciio_intr_t pciio_intr) -{ - return (pciio_intr->pi_dev); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -pciio_pio_dev_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_dev); -} - -pciio_slot_t -pciio_pio_slot_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_slot); -} - -pciio_space_t -pciio_pio_space_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_space); -} - -iopaddr_t -pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_pciaddr); -} - -ulong -pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_mapsz); -} - -caddr_t -pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap) -{ - return (pciio_piomap->pp_kvaddr); -} - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_dev); -} - -pciio_slot_t -pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap) -{ - return (pciio_dmamap->pd_slot); -} - -/****** Generic pci slot information interfaces ******/ - -pciio_info_t -pciio_info_chk(devfs_handle_t pciio) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); - return (pciio_info_t) ainfo; -} - -pciio_info_t -pciio_info_get(devfs_handle_t pciio) -{ - pciio_info_t pciio_info; - - pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); - -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pciio, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { - - return((pciio_info_t)-1); /* Should panic .. */ - } - - - return pciio_info; -} - -void -pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) -{ - if (pciio_info != NULL) - pciio_info->c_fingerprint = pciio_info_fingerprint; - hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); - - /* Also, mark this vertex as a PCI slot - * and use the pciio_info, so pciio_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, - (arbitrary_info_t) pciio_info); -} - -devfs_handle_t -pciio_info_dev_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vertex); -} - -/*ARGSUSED*/ -pciio_bus_t -pciio_info_bus_get(pciio_info_t pciio_info) -{ - /* XXX for now O2 always gets back bus 0 */ - return (pciio_bus_t)0; -} - -pciio_slot_t -pciio_info_slot_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_slot); -} - -pciio_function_t -pciio_info_function_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_func); -} - -pciio_vendor_id_t -pciio_info_vendor_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vendor); -} - -pciio_device_id_t -pciio_info_device_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_device); -} - -devfs_handle_t -pciio_info_master_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_master); -} - -arbitrary_info_t -pciio_info_mfast_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_mfast); -} - -pciio_provider_t * -pciio_info_pops_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_pops); -} - -error_handler_f * -pciio_info_efunc_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_efunc); -} - -error_handler_arg_t * -pciio_info_einfo_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_einfo); -} - -pciio_space_t -pciio_info_bar_space_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_space; -} - -iopaddr_t -pciio_info_bar_base_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_base; -} - -size_t -pciio_info_bar_size_get(pciio_info_t info, int win) -{ - return info->c_window[win].w_size; -} - -iopaddr_t -pciio_info_rom_base_get(pciio_info_t info) -{ - return info->c_rbase; -} - -size_t -pciio_info_rom_size_get(pciio_info_t info) -{ - return info->c_rsize; -} - - -/* ===================================================================== - * GENERIC PCI INITIALIZATION FUNCTIONS - */ - -/* - * pciioinit: called once during device driver - * initializtion if this driver is configured into - * the system. - */ -void -pciio_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("pciio_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (pciio_registry == NULL) { - cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); - if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(pciio_registry != NULL); -} - -/* - * pciioattach: called for each vertex in the graph - * that is a PCI provider. - */ -/*ARGSUSED */ -int -pciio_attach(devfs_handle_t pciio) -{ -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("%v: pciio_attach\n", pciio); -#else - printk("0x%x: pciio_attach\n", pciio); -#endif -#endif - return 0; -} - -/* - * Associate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) -{ - hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); -} - -/* - * Disassociate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_unregister(devfs_handle_t provider) -{ - arbitrary_info_t ainfo; - - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -} - -/* - * Obtain a pointer to the pciio_provider functions for a specified Crosstalk - * provider. - */ -pciio_provider_t * -pciio_provider_fns_get(devfs_handle_t provider) -{ - arbitrary_info_t ainfo = 0; - - (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); - return (pciio_provider_t *) ainfo; -} - -/*ARGSUSED4 */ -int -pciio_driver_register( - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine might call - * pciio_driver_register before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - return cdl_add_driver(pciio_registry, - vendor_id, device_id, - driver_prefix, flags, NULL); -} - -/* - * Remove an initialization function. - */ -void -pciio_driver_unregister( - char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called register; so - * we can assume we have a registry here. - */ - ASSERT(pciio_registry != NULL); - - cdl_del_driver(pciio_registry, driver_prefix, NULL); -} - -/* - * Set the slot status for a device supported by the - * driver being registered. - */ -void -pciio_driver_reg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Set the slot status for a device supported by the - * driver being unregistered. - */ -void -pciio_driver_unreg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -pciio_iterate(char *driver_prefix, - pciio_iter_f * func) -{ - /* a driver's init routine might call - * pciio_iterate before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - ASSERT(pciio_registry != NULL); - - cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); -} - -devfs_handle_t -pciio_device_register( - devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ - devfs_handle_t master, /* card's master ASIC (PCI provider) */ - pciio_slot_t slot, /* card's slot */ - pciio_function_t func, /* card's func */ - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - return pciio_device_info_register - (connectpt, pciio_device_info_new (NULL, master, slot, func, - vendor_id, device_id)); -} - -void -pciio_device_unregister(devfs_handle_t pconn) -{ - DEV_FUNC(pconn,device_unregister)(pconn); -} - -pciio_info_t -pciio_device_info_new( - pciio_info_t pciio_info, - devfs_handle_t master, - pciio_slot_t slot, - pciio_function_t func, - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - if (!pciio_info) - GET_NEW(pciio_info); - ASSERT(pciio_info != NULL); - - pciio_info->c_slot = slot; - pciio_info->c_func = func; - pciio_info->c_vendor = vendor_id; - pciio_info->c_device = device_id; - pciio_info->c_master = master; - pciio_info->c_mfast = hwgraph_fastinfo_get(master); - pciio_info->c_pops = pciio_provider_fns_get(master); - pciio_info->c_efunc = 0; - pciio_info->c_einfo = 0; - - return pciio_info; -} - -void -pciio_device_info_free(pciio_info_t pciio_info) -{ - /* NOTE : pciio_info is a structure within the pcibr_info - * and not a pointer to memory allocated on the heap !! - */ - BZERO((char *)pciio_info,sizeof(pciio_info)); -} - -devfs_handle_t -pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ - pciio_info_t pciio_info) /* details about the connectpt */ -{ - char name[32]; - devfs_handle_t pconn; - int device_master_set(devfs_handle_t, devfs_handle_t); - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - if (GRAPH_SUCCESS != - hwgraph_path_add(connectpt, name, &pconn)) - return pconn; - - pciio_info->c_vertex = pconn; - pciio_info_set(pconn, pciio_info); -#ifdef DEBUG_PCIIO - { - int pos; - char dname[256]; - pos = devfs_generate_path(pconn, dname, 256); - printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif /* DEBUG_PCIIO */ - - /* - * create link to our pci provider - */ - - device_master_set(pconn, pciio_info->c_master); - -#if USRPCI - /* - * Call into usrpci provider to let it initialize for - * the given slot. - */ - if (pciio_info->c_slot != PCIIO_SLOT_NONE) - usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); -#endif - - return pconn; -} - -void -pciio_device_info_unregister(devfs_handle_t connectpt, - pciio_info_t pciio_info) -{ - char name[32]; - devfs_handle_t pconn; - - if (!pciio_info) - return; - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - hwgraph_edge_remove(connectpt,name,&pconn); - pciio_info_set(pconn,0); - - /* Remove the link to our pci provider */ - hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL); - - - hwgraph_vertex_unref(pconn); - hwgraph_vertex_destroy(pconn); - -} -/* Add the pci card inventory information to the hwgraph - */ -static void -pciio_device_inventory_add(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - - /* Donot add inventory for non-existent devices */ - if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE) || - (pciio_info->c_device == PCIIO_DEVICE_ID_NONE)) - return; - device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP, - pciio_info->c_vendor,pciio_info->c_device, - pciio_info->c_slot); -} - -static void -pciio_device_inventory_remove(devfs_handle_t pconn_vhdl) -{ -#ifdef LATER - hwgraph_inventory_remove(pconn_vhdl,-1,-1,-1,-1,-1); -#endif -} - -/*ARGSUSED */ -int -pciio_device_attach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - - pciio_device_inventory_add(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); -} - -int -pciio_device_detach(devfs_handle_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - pciio_device_inventory_remove(pconn); - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_del_connpt(pciio_registry, vendor_id, device_id, - pconn, drv_flags)); - -} - -/* - * pciio_error_register: - * arrange for a function to be called with - * a specified first parameter plus other - * information when an error is encountered - * and traced to the pci slot corresponding - * to the connection point pconn. - * - * may also be called with a null function - * pointer to "unregister" the error handler. - * - * NOTE: subsequent calls silently overwrite - * previous data for this vertex. We assume that - * cooperating drivers, well, cooperate ... - */ -void -pciio_error_register(devfs_handle_t pconn, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - pciio_info_t pciio_info; - - pciio_info = pciio_info_get(pconn); - ASSERT(pciio_info != NULL); - pciio_info->c_efunc = efunc; - pciio_info->c_einfo = einfo; -} - -/* - * Check if any device has been found in this slot, and return - * true or false - * vhdl is the vertex for the slot - */ -int -pciio_slot_inuse(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - if (pciio_info->c_vendor) { - /* - * Non-zero value for vendor indicate - * a board being found in this slot. - */ - return 1; - } - return 0; -} - -int -pciio_dma_enabled(devfs_handle_t pconn_vhdl) -{ - return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); -} - -/* - * These are complementary Linux interfaces that takes in a pci_dev * as the - * first arguement instead of devfs_handle_t. - */ -iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); -pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); -void snia_pciio_dmamap_free(pciio_dmamap_t); -iopaddr_t snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -void snia_pciio_dmamap_done(pciio_dmamap_t); -pciio_endian_t snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end, - pciio_endian_t desired_end); - -#include -EXPORT_SYMBOL(snia_pciio_dmatrans_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_alloc); -EXPORT_SYMBOL(snia_pciio_dmamap_free); -EXPORT_SYMBOL(snia_pciio_dmamap_addr); -EXPORT_SYMBOL(snia_pciio_dmamap_done); -EXPORT_SYMBOL(snia_pciio_endian_set); - -pciio_endian_t -snia_pciio_endian_set(struct pci_dev *pci_dev, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, endian_set) - (dev, device_end, desired_end); -} - -iopaddr_t -snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -pciio_dmamap_t -snia_pciio_dmamap_alloc(struct pci_dev *pci_dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); - - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -void -snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - diff -Nru a/arch/ia64/sn/io/platform_init/Makefile b/arch/ia64/sn/io/platform_init/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/platform_init/Makefile Fri May 16 11:50:50 2003 @@ -0,0 +1,12 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# Makefile for the sn2 io routines. + +EXTRA_CFLAGS := -DLITTLE_ENDIAN + +obj-y += sgi_io_init.o irix_io_init.o diff -Nru a/arch/ia64/sn/io/platform_init/irix_io_init.c b/arch/ia64/sn/io/platform_init/irix_io_init.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/platform_init/irix_io_init.c Fri May 23 03:37:31 2003 @@ -0,0 +1,88 @@ +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void init_all_devices(void); +extern void klhwg_add_all_modules(vertex_hdl_t); +extern void klhwg_add_all_nodes(vertex_hdl_t); + +extern vertex_hdl_t hwgraph_root; +extern void io_module_init(void); +extern int pci_bus_to_hcl_cvlink(void); +extern void mlreset(void); + +/* #define DEBUG_IO_INIT 1 */ +#ifdef DEBUG_IO_INIT +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif /* DEBUG_IO_INIT */ + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +irix_io_init(void) +{ + cnodeid_t cnode; + + /* + * This is the Master CPU. Emulate mlsetup and main.c in Irix. + */ + mlreset(); + + /* + * Initialize platform-dependent vertices in the hwgraph: + * module + * node + * cpu + * memory + * slot + * hub + * router + * xbow + */ + + io_module_init(); /* Use to be called module_init() .. */ + klhwg_add_all_modules(hwgraph_root); + klhwg_add_all_nodes(hwgraph_root); + + for (cnode = 0; cnode < numnodes; cnode++) { + extern void per_hub_init(cnodeid_t); + per_hub_init(cnode); + } + + /* We can do headless hub cnodes here .. */ + + /* + * + * Our IO Infrastructure drivers are in place .. + * Initialize the whole IO Infrastructure .. xwidget/device probes. + * + */ + init_all_devices(); + pci_bus_to_hcl_cvlink(); +} diff -Nru a/arch/ia64/sn/io/platform_init/sgi_io_init.c b/arch/ia64/sn/io/platform_init/sgi_io_init.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/platform_init/sgi_io_init.c Fri May 16 04:18:17 2003 @@ -0,0 +1,109 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int init_hcl(void); + +/* + * per_hub_init + * + * This code is executed once for each Hub chip. + */ +void +per_hub_init(cnodeid_t cnode) +{ + nasid_t nasid; + nodepda_t *npdap; + ii_icmr_u_t ii_icmr; + ii_ibcr_u_t ii_ibcr; + ii_ilcsr_u_t ii_ilcsr; + + nasid = COMPACT_TO_NASID_NODEID(cnode); + + ASSERT(nasid != INVALID_NASID); + ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); + + npdap = NODEPDA(cnode); + + /* Disable the request and reply errors. */ + REMOTE_HUB_S(nasid, IIO_IWEIM, 0xC000); + + /* + * Set the total number of CRBs that can be used. + */ + ii_icmr.ii_icmr_regval= 0x0; + ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; + if (enable_shub_wars_1_1() ) { + // Set bit one of ICMR to prevent II from sending interrupt for II bug. + ii_icmr.ii_icmr_regval |= 0x1; + } + REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); + + /* + * Set the number of CRBs that both of the BTEs combined + * can use minus 1. + */ + ii_ibcr.ii_ibcr_regval= 0x0; + ii_ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(nasid, IIO_LLP_CSR); + if (ii_ilcsr.ii_ilcsr_fld_s.i_llp_stat & LNK_STAT_WORKING) { + ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; + } else { + /* + * if the LLP is down, there is no attached I/O, so + * give BTE all the CRBs. + */ + ii_ibcr.ii_ibcr_fld_s.i_count = 0x14; + } + REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); + + /* + * Set CRB timeout to be 10ms. + */ + REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff ); + REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); + + /* Initialize error interrupts for this hub. */ + hub_error_init(cnode); +} + +/* + * This routine is responsible for the setup of all the IRIX hwgraph style + * stuff that's been pulled into linux. It's called by sn_pci_find_bios which + * is called just before the generic Linux PCI layer does its probing (by + * platform_pci_fixup aka sn_pci_fixup). + * + * It is very IMPORTANT that this call is only made by the Master CPU! + * + */ + +void +sgi_master_io_infr_init(void) +{ + extern void irix_io_init(void); + + init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ + irix_io_init(); /* Do IRIX Compatibility IO Init */ + +#ifdef CONFIG_KDB + { + extern void kdba_io_init(void); + kdba_io_init(); + } +#endif + +} diff -Nru a/arch/ia64/sn/io/sgi_if.c b/arch/ia64/sn/io/sgi_if.c --- a/arch/ia64/sn/io/sgi_if.c Wed Dec 4 07:05:14 2002 +++ b/arch/ia64/sn/io/sgi_if.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -20,8 +20,6 @@ #include #include -unsigned char Is_pic_on_this_nasid[512]; /* non-0 when this is a pic shub */ - void * snia_kmem_zalloc(size_t size, int flag) { @@ -37,13 +35,6 @@ kfree(ptr); } -int -nic_vertex_info_match(devfs_handle_t v, char *s) -{ - /* we don't support this */ - return(0); -} - /* * the alloc/free_node routines do a simple kmalloc for now .. */ @@ -102,34 +93,6 @@ } } return (neg ? n : -n); -} - -char * -strtok_r(char *string, const char *sepset, char **lasts) -{ - register char *q, *r; - - /*first or subsequent call*/ - if (string == NULL) - string = *lasts; - - if(string == 0) /* return if no tokens remaining */ - return(NULL); - - q = string + strspn(string, sepset); /* skip leading separators */ - - if(*q == '\0') { /* return if no tokens remaining */ - *lasts = 0; /* indicate this is last token */ - return(NULL); - } - - if((r = strpbrk(q, sepset)) == NULL) /* move past token */ - *lasts = 0; /* indicate this is last token */ - else { - *r = '\0'; - *lasts = r+1; - } - return(q); } /* diff -Nru a/arch/ia64/sn/io/sgi_io_init.c b/arch/ia64/sn/io/sgi_io_init.c --- a/arch/ia64/sn/io/sgi_io_init.c Wed May 8 11:00:13 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,308 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void mlreset(int ); -extern int init_hcl(void); -extern void klgraph_hack_init(void); -extern void hubspc_init(void); -extern void pciio_init(void); -extern void pcibr_init(void); -extern void xtalk_init(void); -extern void xbow_init(void); -extern void xbmon_init(void); -extern void pciiox_init(void); -extern void usrpci_init(void); -extern void ioc3_init(void); -extern void initialize_io(void); -#if defined(CONFIG_IA64_SGI_SN1) -extern void intr_clear_all(nasid_t); -#endif -extern void klhwg_add_all_modules(devfs_handle_t); -extern void klhwg_add_all_nodes(devfs_handle_t); - -void sn_mp_setup(void); -extern devfs_handle_t hwgraph_root; -extern void io_module_init(void); -extern void pci_bus_cvlink_init(void); -extern void temp_hack(void); - -extern int pci_bus_to_hcl_cvlink(void); - -/* #define DEBUG_IO_INIT */ -#ifdef DEBUG_IO_INIT -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_IO_INIT */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - npdap = NODEPDA(cnode); - -#if defined(CONFIG_IA64_SGI_SN1) - /* initialize per-node synergy perf instrumentation */ - npdap->synergy_perf_enabled = 0; /* off by default */ - npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED; - npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT; - npdap->synergy_inactive_intervals = 0; - npdap->synergy_active_intervals = 0; - npdap->synergy_perf_data = NULL; - npdap->synergy_perf_first = NULL; -#endif /* CONFIG_IA64_SGI_SN1 */ - - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - - -#if defined(CONFIG_IA64_SGI_SN1) - /* Reserve all of the hardwired interrupt levels. */ - intr_reserve_hardwired(cnode); -#endif - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn1_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn1_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void -sgi_master_io_infr_init(void) -{ - int cnode; - - /* - * Do any early init stuff .. einit_tbl[] etc. - */ - DBG("--> sgi_master_io_infr_init: calling init_hcl().\n"); - init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ - - /* - * initialize the Linux PCI to xwidget vertexes .. - */ - DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n"); - pci_bus_cvlink_init(); - -#ifdef BRINGUP -#ifdef CONFIG_IA64_SGI_SN1 - /* - * Hack to provide statically initialzed klgraph entries. - */ - DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); - klgraph_hack_init(); -#endif /* CONFIG_IA64_SGI_SN1 */ -#endif /* BRINGUP */ - - /* - * This is the Master CPU. Emulate mlsetup and main.c in Irix. - */ - DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n"); - mlreset(0); /* Master .. */ - - /* - * allowboot() is called by kern/os/main.c in main() - * Emulate allowboot() ... - * per_cpu_init() - only need per_hub_init() - * cpu_io_setup() - Nothing to do. - * - */ - DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n"); - sn_mp_setup(); - - DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n"); - for (cnode = 0; cnode < numnodes; cnode++) { - per_hub_init(cnode); - } - - /* We can do headless hub cnodes here .. */ - - /* - * io_init[] stuff. - * - * Get SGI IO Infrastructure drivers to init and register with - * each other etc. - */ - - DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n"); - hubspc_init(); - - DBG("--> sgi_master_io_infr_init: calling pciio_init()\n"); - pciio_init(); - - DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n"); - pcibr_init(); - - DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n"); - xtalk_init(); - - DBG("--> sgi_master_io_infr_init: calling xbow_init()\n"); - xbow_init(); - - DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n"); - xbmon_init(); - - DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n"); - pciiox_init(); - - DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n"); - usrpci_init(); - - DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n"); - ioc3_init(); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n"); - initialize_io(); - - DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n"); - pci_bus_to_hcl_cvlink(); - -#ifdef CONFIG_PCIBA - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); - pciba_init(); -#endif - - DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n"); -} - -/* - * sgi_slave_io_infr_init - This routine must be called on all cpus except - * the Master CPU. - */ -void -sgi_slave_io_infr_init(void) -{ - /* Emulate cboot() .. */ - mlreset(1); /* This is a slave cpu */ - - // per_hub_init(0); /* Need to get and send in actual cnode number */ - - /* Done */ -} - -/* - * One-time setup for MP SN. - * Allocate per-node data, slurp prom klconfig information and - * convert it to hwgraph information. - */ -void -sn_mp_setup(void) -{ - cnodeid_t cnode; - cpuid_t cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - DBG("sn_mp_io_setup: calling io_module_init()\n"); - io_module_init(); /* Use to be called module_init() .. */ - - DBG("sn_mp_setup: calling klhwg_add_all_modules()\n"); - klhwg_add_all_modules(hwgraph_root); - DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n"); - klhwg_add_all_nodes(hwgraph_root); - - - for (cnode = 0; cnode < numnodes; cnode++) { - - /* - * This routine clears the Hub's Interrupt registers. - */ - /* - * We need to move this intr_clear_all() routine - * from SN/intr.c to a more appropriate file. - * Talk to Al Mayer. - */ -#if defined(CONFIG_IA64_SGI_SN1) - intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); -#endif - /* now init the hub */ - // per_hub_init(cnode); - - } - -#if defined(CONFIG_IA64_SGI_SN1) - synergy_perf_init(); -#endif - -} diff -Nru a/arch/ia64/sn/io/sgi_io_sim.c b/arch/ia64/sn/io/sgi_io_sim.c --- a/arch/ia64/sn/io/sgi_io_sim.c Wed Dec 4 07:05:29 2002 +++ b/arch/ia64/sn/io/sgi_io_sim.c Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -15,18 +15,11 @@ #include #include #include -#include #include -cpuid_t master_procid = 0; +cpuid_t master_procid; char arg_maxnodes[4]; -extern void init_all_devices(void); - -#if defined(CONFIG_IA64_SGI_SN1) -synergy_da_t *Synergy_da_indr[MAX_COMPACT_NODES * 2]; -#endif - /* * Return non-zero if the given variable was specified */ @@ -36,44 +29,12 @@ return (strlen(s) != 0); } -void xbmon_init(void) -{ - FIXME("xbmon_init : no-op\n"); - -} - -void pciiox_init(void) -{ - FIXME("pciiox_init : no-op\n"); - -} - -void usrpci_init(void) -{ - FIXME("usrpci_init : no-op\n"); - -} - -void ioc3_init(void) -{ - FIXME("ioc3_init : no-op\n"); - -} - -void initialize_io(void) -{ - - init_all_devices(); -} - /* * Routines provided by ml/SN/promif.c. */ -static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL; +static __psunsigned_t master_bridge_base; nasid_t console_nasid = (nasid_t)-1; -#if !defined(CONFIG_IA64_SGI_SN1) char master_baseio_wid; -#endif static char console_wid; static char console_pcislot; @@ -95,27 +56,6 @@ return 0; } -#if defined(CONFIG_IA64_SGI_SN1) -int -is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) -{ - - /* - * If the widget numbers are different, we're not the master. - */ - if (test_wid != (xwidgetnum_t)console_wid) - return 0; - - /* - * If the NASIDs are the same or equivalent, we're the master. - */ - if (check_nasid_equiv(test_nasid, console_nasid)) { - return 1; - } else { - return 0; - } -} -#else int is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) { @@ -136,15 +76,4 @@ } else { return 0; } -} -#endif /* CONFIG_IA64_SGI_SN1 */ - -/* - * Routines provided by ml/SN/nvram.c - */ -void -nvram_baseinit(void) -{ - FIXME("nvram_baseinit : no-op\n"); - } diff -Nru a/arch/ia64/sn/io/sn1/hub_intr.c b/arch/ia64/sn/io/sn1/hub_intr.c --- a/arch/ia64/sn/io/sn1/hub_intr.c Tue Dec 3 10:07:25 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,307 +0,0 @@ -/* $Id: hub_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern xtalk_provider_t hub_provider; - -/* ARGSUSED */ -void -hub_intr_init(devfs_handle_t hubv) -{ -} - -/* - * hub_device_desc_update - * Update the passed in device descriptor with the actual the - * target cpu number and interrupt priority level. - * NOTE : These might be the same as the ones passed in thru - * the descriptor. - */ -static void -hub_device_desc_update(device_desc_t dev_desc, - ilvl_t intr_swlevel, - cpuid_t cpu) -{ -} - -int allocate_my_bit = INTRCONNECT_ANYBIT; - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -static hub_intr_t -do_hub_intr_alloc(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev, /* owner of this interrupt, if known */ - int uncond_nothread) /* unconditionally non-threaded */ -{ - cpuid_t cpu = (cpuid_t)0; /* cpu to receive interrupt */ - int cpupicked = 0; - int bit; /* interrupt vector */ - /*REFERENCED*/ - int intr_resflags = 0; - hub_intr_t intr_hdl; - cnodeid_t nodeid; /* node to receive interrupt */ - /*REFERENCED*/ - nasid_t nasid; /* nasid to receive interrupt */ - struct xtalk_intr_s *xtalk_info; - iopaddr_t xtalk_addr; /* xtalk addr on hub to set intr */ - xwidget_info_t xwidget_info; /* standard crosstalk widget info handle */ - char *intr_name = NULL; - ilvl_t intr_swlevel = (ilvl_t)0; - extern int default_intr_pri; - extern void synergy_intr_alloc(int, int); - - - if (dev_desc) { - if (dev_desc->flags & D_INTR_ISERR) { - intr_resflags = II_ERRORINT; - } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) { - intr_resflags = II_THREADED; - } else { - /* Neither an error nor a thread. */ - intr_resflags = 0; - } - } else { - intr_swlevel = default_intr_pri; - if (!uncond_nothread) - intr_resflags = II_THREADED; - } - - /* XXX - Need to determine if the interrupt should be threaded. */ - - /* If the cpu has not been picked already then choose a candidate - * interrupt target and reserve the interrupt bit - */ - if (!cpupicked) { - cpu = intr_heuristic(dev,dev_desc,allocate_my_bit, - intr_resflags,owner_dev, - intr_name,&bit); - } - - /* At this point we SHOULD have a valid cpu */ - if (cpu == CPU_NONE) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v hub_intr_alloc could not allocate interrupt\n", - owner_dev); -#else - printk(KERN_WARNING "%p hub_intr_alloc could not allocate interrupt\n", - (void *)owner_dev); -#endif - return(0); - - } - - /* If the cpu has been picked already (due to the bridge data - * corruption bug) then try to reserve an interrupt bit . - */ - if (cpupicked) { - bit = intr_reserve_level(cpu, allocate_my_bit, - intr_resflags, - owner_dev, intr_name); - if (bit < 0) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " - " %d and dev %v\n", - cpu,owner_dev); -#else - printk(KERN_WARNING "Could not reserve an interrupt bit for cpu " - " %d and dev %p\n", - (int)cpu, (void *)owner_dev); -#endif - - return(0); - } - } - - nodeid = cpuid_to_cnodeid(cpu); - nasid = cpuid_to_nasid(cpu); - xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu))); - - /* - * Allocate an interrupt handle, and fill it in. There are two - * pieces to an interrupt handle: the piece needed by generic - * xtalk code which is used by crosstalk device drivers, and - * the piece needed by low-level IP27 hardware code. - */ - intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid); - ASSERT_ALWAYS(intr_hdl); - - /* - * Fill in xtalk information for generic xtalk interfaces that - * operate on xtalk_intr_hdl's. - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = dev; - xtalk_info->xi_vector = bit; - xtalk_info->xi_addr = xtalk_addr; - - /* - * Regardless of which CPU we ultimately interrupt, a given crosstalk - * widget always handles interrupts (and PIO and DMA) through its - * designated "master" crosstalk provider. - */ - xwidget_info = xwidget_info_get(dev); - if (xwidget_info) - xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); - - /* Fill in low level hub information for hub_* interrupt interface */ - intr_hdl->i_swlevel = intr_swlevel; - intr_hdl->i_cpuid = cpu; - intr_hdl->i_bit = bit; - intr_hdl->i_flags = HUB_INTR_IS_ALLOCED; - - /* Store the actual interrupt priority level & interrupt target - * cpu back in the device descriptor. - */ - hub_device_desc_update(dev_desc, intr_swlevel, cpu); - synergy_intr_alloc((int)bit, (int)cpu); - return(intr_hdl); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Uncondtionally request non-threaded, regardless of what the device - * descriptor might say. - * Returns a hub interrupt handle on success, or 0 on failure. - */ -hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt, if known */ -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -hub_intr_free(hub_intr_t intr_hdl) -{ - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_t xtalk_info; - - if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { - /* Setting the following fields in the xtalk interrupt info - * clears the interrupt target register in the xtalk user - */ - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = NODEV; - xtalk_info->xi_vector = 0; - xtalk_info->xi_addr = 0; - hub_intr_disconnect(intr_hdl); - } - - if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) - kfree(intr_hdl); - - intr_unreserve_level(cpu, bit); -} - - -/* - * Associate resources allocated with a previous hub_intr_alloc call with the - * described handler, arg, name, etc. - */ -/*ARGSUSED*/ -int -hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - extern int synergy_intr_connect(int, int); - - ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); - - rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, NULL); - if (rv < 0) - return(rv); - - intr_hdl->i_xtalk_info.xi_setfunc = setfunc; - intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; - - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; - return(synergy_intr_connect((int)bit, (int)cpu)); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -hub_intr_disconnect(hub_intr_t intr_hdl) -{ - /*REFERENCED*/ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_setfunc_t setfunc; - - setfunc = intr_hdl->i_xtalk_info.xi_setfunc; - - /* TBD: send disconnected interrupts somewhere harmless */ - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - rv = intr_disconnect_level(cpu, bit); - ASSERT(rv == 0); - intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl) -{ - cpuid_t cpuid = intr_hdl->i_cpuid; - ASSERT(cpuid != CPU_NONE); - - return(cpuid_to_vertex(cpuid)); -} diff -Nru a/arch/ia64/sn/io/sn1/hubcounters.c b/arch/ia64/sn/io/sn1/hubcounters.c --- a/arch/ia64/sn/io/sn1/hubcounters.c Wed Dec 4 07:06:47 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,283 +0,0 @@ -/* $Id: hubcounters.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. - * All rights reserved. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_error_handler(char *, int); /* huberror.c */ - -static int hubstats_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -struct file_operations hub_mon_fops = { - ioctl: hubstats_ioctl, -}; - -#define HUB_CAPTURE_TICKS (2 * HZ) - -#define HUB_ERR_THRESH 500 -#define USEC_PER_SEC 1000000 -#define NSEC_PER_SEC USEC_PER_SEC*1000 - -volatile int hub_print_usecs = 600 * USEC_PER_SEC; - -/* Return success if the hub's crosstalk link is working */ -int -hub_xtalk_link_up(nasid_t nasid) -{ - hubreg_t llp_csr_reg; - - /* Read the IO LLP control status register */ - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - - /* Check if the xtalk link is working */ - if (llp_csr_reg & IIO_LLP_CSR_IS_UP) - return(1); - - return(0); - - -} - -static char *error_flag_to_type(unsigned char error_flag) -{ - switch(error_flag) { - case 0x1: return ("NI retries"); - case 0x2: return ("NI SN errors"); - case 0x4: return ("NI CB errors"); - case 0x8: return ("II CB errors"); - case 0x10: return ("II SN errors"); - default: return ("Errors"); - } -} - -int -print_hub_error(hubstat_t *hsp, hubreg_t reg, - int64_t delta, unsigned char error_flag) -{ - int64_t rate; - - reg *= hsp->hs_per_minute; /* Convert to minutes */ - rate = reg / delta; - - if (rate > HUB_ERR_THRESH) { - - if(hsp->hs_maint & error_flag) - { - printk( "Excessive %s (%ld/min) on %s", - error_flag_to_type(error_flag), rate, hsp->hs_name); - } - else - { - hsp->hs_maint |= error_flag; - printk( "Excessive %s (%ld/min) on %s", - error_flag_to_type(error_flag), rate, hsp->hs_name); - } - return 1; - } else { - return 0; - } -} - - -int -check_hub_error_rates(hubstat_t *hsp) -{ - int64_t delta = hsp->hs_timestamp - hsp->hs_timebase; - int printed = 0; - - printed += print_hub_error(hsp, hsp->hs_ni_retry_errors, - delta, 0x1); - -#if 0 - printed += print_hub_error(hsp, hsp->hs_ni_sn_errors, - delta, 0x2); -#endif - - printed += print_hub_error(hsp, hsp->hs_ni_cb_errors, - delta, 0x4); - - - /* If the hub's xtalk link is not working there is - * no need to print the "Excessive..." warning - * messages - */ - if (!hub_xtalk_link_up(hsp->hs_nasid)) - return(printed); - - - printed += print_hub_error(hsp, hsp->hs_ii_cb_errors, - delta, 0x8); - - printed += print_hub_error(hsp, hsp->hs_ii_sn_errors, - delta, 0x10); - - return printed; -} - - -void -capture_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) -{ - nasid_t nasid; - hubstat_t *hsp = &(npda->hubstats); - hubreg_t port_error; - ii_illr_u_t illr; - int count; - int overflow = 0; - - /* - * If our link wasn't up at boot time, don't worry about error rates. - */ - if (!(hsp->hs_ni_port_status & NPS_LINKUP_MASK)) { - printk("capture_hub_stats: cnode=%d hs_ni_port_status=0x%016lx : link is not up\n", - cnodeid, hsp->hs_ni_port_status); - return; - } - - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - - hsp->hs_timestamp = GET_RTC_COUNTER(); - - port_error = REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); - count = ((port_error & NPE_RETRYCOUNT_MASK) >> NPE_RETRYCOUNT_SHFT); - hsp->hs_ni_retry_errors += count; - if (count == NPE_COUNT_MAX) - overflow = 1; - count = ((port_error & NPE_SNERRCOUNT_MASK) >> NPE_SNERRCOUNT_SHFT); - hsp->hs_ni_sn_errors += count; - if (count == NPE_COUNT_MAX) - overflow = 1; - count = ((port_error & NPE_CBERRCOUNT_MASK) >> NPE_CBERRCOUNT_SHFT); - hsp->hs_ni_cb_errors += count; - if (overflow || count == NPE_COUNT_MAX) - hsp->hs_ni_overflows++; - - if (port_error & NPE_FATAL_ERRORS) { -#ifdef ajm - hubni_error_handler("capture_hub_stats", 1); -#else - printk("Error: hubni_error_handler in capture_hub_stats"); -#endif - } - - illr.ii_illr_regval = REMOTE_HUB_L(nasid, IIO_LLP_LOG); - REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); - - hsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt; - hsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt; - if ((illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) || - (illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX)) - hsp->hs_ii_overflows++; - - if (hsp->hs_print) { - if (check_hub_error_rates(hsp)) { - hsp->hs_last_print = GET_RTC_COUNTER(); - hsp->hs_print = 0; - } - } else { - if ((GET_RTC_COUNTER() - - hsp->hs_last_print) > hub_print_usecs) - hsp->hs_print = 1; - } - - npda->hubticks = HUB_CAPTURE_TICKS; -} - - -void -init_hub_stats(cnodeid_t cnodeid, struct nodepda_s *npda) -{ - hubstat_t *hsp = &(npda->hubstats); - nasid_t nasid = cnodeid_to_nasid(cnodeid); - bzero(&(npda->hubstats), sizeof(hubstat_t)); - - hsp->hs_version = HUBSTAT_VERSION; - hsp->hs_cnode = cnodeid; - hsp->hs_nasid = nasid; - hsp->hs_timebase = GET_RTC_COUNTER(); - hsp->hs_ni_port_status = REMOTE_HUB_L(nasid, NI_PORT_STATUS); - - /* Clear the II error counts. */ - REMOTE_HUB_S(nasid, IIO_LLP_LOG, 0); - - /* Clear the NI counts. */ - REMOTE_HUB_L(nasid, NI_PORT_ERROR_CLEAR); - - hsp->hs_per_minute = (long long)RTC_CYCLES_PER_SEC * 60LL; - - npda->hubticks = HUB_CAPTURE_TICKS; - - /* XX should use kmem_alloc_node */ - hsp->hs_name = (char *)kmalloc(MAX_HUB_PATH, GFP_KERNEL); - ASSERT_ALWAYS(hsp->hs_name); - - sprintf(hsp->hs_name, "/dev/hw/" EDGE_LBL_MODULE "/%03d/" - EDGE_LBL_NODE "/" EDGE_LBL_HUB, - npda->module_id); - - hsp->hs_last_print = 0; - hsp->hs_print = 1; - - hub_print_usecs = hub_print_usecs; - -#if 0 - printk("init_hub_stats: cnode=%d nasid=%d hs_version=%d hs_ni_port_status=0x%016lx\n", - cnodeid, nasid, hsp->hs_version, hsp->hs_ni_port_status); -#endif -} - -static int -hubstats_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - cnodeid_t cnode; - nodepda_t *npdap; - uint64_t longarg; - devfs_handle_t d; - - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; - cnode = (cnodeid_t)hwgraph_fastinfo_get(d); - npdap = NODEPDA(cnode); - - if (npdap->hubstats.hs_version != HUBSTAT_VERSION) { - init_hub_stats(cnode, npdap); - } - - switch (cmd) { - case SNDRV_GET_INFOSIZE: - longarg = sizeof(hubstat_t); - if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { - return -EFAULT; - } - break; - - case SNDRV_GET_HUBINFO: - /* refresh npda->hubstats */ - capture_hub_stats(cnode, npdap); - if (copy_to_user((void *)arg, &npdap->hubstats, sizeof(hubstat_t))) { - return -EFAULT; - } - break; - - default: - return -EINVAL; - } - - return 0; -} diff -Nru a/arch/ia64/sn/io/sn1/huberror.c b/arch/ia64/sn/io/sn1/huberror.c --- a/arch/ia64/sn/io/sn1/huberror.c Tue Dec 3 10:07:25 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,228 +0,0 @@ -/* $Id: huberror.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_eint_init(cnodeid_t cnode); -extern void hubii_eint_init(cnodeid_t cnode); -extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - -extern int maxcpus; - -#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ - - -void -hub_error_clear(nasid_t nasid) -{ - int i; - hubreg_t idsr; - int sn; - - for(sn=0; snh_cnodeid == cnode); - - ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); - - if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { - /* - * HUB II link is not up. - * Just disable LLP, and don't connect any interrupts. - */ - ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); - return; - } - /* Select a possible interrupt target where there is a free interrupt - * bit and also reserve the interrupt bit for this IO error interrupt - */ - intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, - "HUB IO error interrupt",&bit); - if (intr_cpu == CPU_NONE) { - printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); - return; - } - - rv = intr_connect_level(intr_cpu, bit, 0, NULL); - synergy_intr_connect(bit, intr_cpu); - request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); - ASSERT_ALWAYS(rv >= 0); - hubio_eint.ii_iidsr_regval = 0; - hubio_eint.ii_iidsr_fld_s.i_enable = 1; - hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ - hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); - hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); - -} - -void -hubni_eint_init(cnodeid_t cnode) -{ - int intr_bit; - cpuid_t targ; - - - if ((targ = cnodeid_to_cpuid(cnode)) == CPU_NONE) - return; - - /* The prom chooses which cpu gets these interrupts, but we - * don't know which one it chose. We will register all of the - * cpus to be sure. This only costs us an irqaction per cpu. - */ - for (; targ < CPUS_PER_NODE; targ++) { - if (!cpu_enabled(targ) ) continue; - /* connect the INTEND1 bits. */ - for (intr_bit = XB_ERROR; intr_bit <= MSC_PANIC_INTR; intr_bit++) { - intr_connect_level(targ, intr_bit, II_ERRORINT, NULL); - } - request_irq(SGI_HUB_ERROR_IRQ + (targ << 8), snia_error_intr_handler, 0, "SN hub error", NULL); - /* synergy masks are initialized in the prom to enable all interrupts. */ - /* We'll just leave them that way, here, for these interrupts. */ - } -} - - -/*ARGSUSED*/ -void -hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) -{ - - panic("Hubii interrupt\n"); -} diff -Nru a/arch/ia64/sn/io/sn1/ip37.c b/arch/ia64/sn/io/sn1/ip37.c --- a/arch/ia64/sn/io/sn1/ip37.c Fri Mar 8 18:11:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,47 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * ip37.c - * Support for IP35/IP37 machines - */ - -#include - -#include -#include -#include -#include /* for bridge_t */ - - -xwidgetnum_t -hub_widget_id(nasid_t nasid) -{ - hubii_wcr_t ii_wcr; /* the control status register */ - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - - return ii_wcr.wcr_fields_s.wcr_widget_id; -} - -int -is_fine_dirmode(void) -{ - return (((LOCAL_HUB_L(LB_REV_ID) & LRI_SYSTEM_SIZE_MASK) - >> LRI_SYSTEM_SIZE_SHFT) == SYSTEM_SIZE_SMALL); - -} - - -void -ni_reset_port(void) -{ - LOCAL_HUB_S(NI_RESET_ENABLE, NRE_RESETOK); - LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); -} diff -Nru a/arch/ia64/sn/io/sn1/mem_refcnt.c b/arch/ia64/sn/io/sn1/mem_refcnt.c --- a/arch/ia64/sn/io/sn1/mem_refcnt.c Tue Dec 3 10:07:25 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,220 +0,0 @@ -/* $Id: mem_refcnt.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// From numa_hw.h - -#define MIGR_COUNTER_MAX_GET(nodeid) \ - (NODEPDA_MCD((nodeid))->migr_system_kparms.migr_threshold_reference) -/* - * Get the Absolute Theshold - */ -#define MIGR_THRESHOLD_ABS_GET(nodeid) ( \ - MD_MIG_VALUE_THRESH_GET(COMPACT_TO_NASID_NODEID(nodeid))) -/* - * Get the current Differential Threshold - */ -#define MIGR_THRESHOLD_DIFF_GET(nodeid) \ - (NODEPDA_MCD(nodeid)->migr_as_kparms.migr_base_threshold) - -#define NUM_OF_HW_PAGES_PER_SW_PAGE() (NBPP / MD_PAGE_SIZE) - -// #include "migr_control.h" - -int -mem_refcnt_attach(devfs_handle_t hub) -{ -#if 0 - devfs_handle_t refcnt_dev; - - hwgraph_char_device_add(hub, - "refcnt", - "hubspc_", - &refcnt_dev); - device_info_set(refcnt_dev, (void*)(ulong)HUBSPC_REFCOUNTERS); -#endif - - return (0); -} - - -/*ARGSUSED*/ -int -mem_refcnt_open(devfs_handle_t *devp, mode_t oflag, int otyp, cred_t *crp) -{ - cnodeid_t node; - - node = master_node_get(*devp); - - ASSERT( (node >= 0) && (node < numnodes) ); - - if (NODEPDA(node)->migr_refcnt_counterbuffer == NULL) { - return (ENODEV); - } - - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != (size_t)0 ); - - return (0); -} - -/*ARGSUSED*/ -int -mem_refcnt_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED*/ -int -mem_refcnt_mmap(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - cnodeid_t node; - int errcode; - char* buffer; - size_t blen; - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - /* - * XXXX deal with prot's somewhere around here.... - */ - - buffer = NODEPDA(node)->migr_refcnt_counterbuffer; - blen = NODEPDA(node)->migr_refcnt_cbsize; - - /* - * Force offset to be a multiple of sizeof(refcnt_t) - * We round up. - */ - - off = (((off - 1)/sizeof(refcnt_t)) + 1) * sizeof(refcnt_t); - - if ( ((buffer + blen) - (buffer + off + len)) < 0 ) { - return (EPERM); - } - - errcode = v_mapphys(vt, - buffer + off, - len); - - return errcode; -} - -/*ARGSUSED*/ -int -mem_refcnt_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* ARGSUSED */ -int -mem_refcnt_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int mode, - cred_t *cred_p, - int *rvalp) -{ - cnodeid_t node; - int errcode; - extern int numnodes; - - node = master_node_get(dev); - - ASSERT( (node >= 0) && (node < numnodes) ); - - ASSERT( NODEPDA(node)->migr_refcnt_counterbuffer != NULL); - ASSERT( NODEPDA(node)->migr_refcnt_counterbase != NULL ); - ASSERT( NODEPDA(node)->migr_refcnt_cbsize != 0 ); - - errcode = 0; - - switch (cmd) { - case RCB_INFO_GET: - { - rcb_info_t rcb; - - rcb.rcb_len = NODEPDA(node)->migr_refcnt_cbsize; - - rcb.rcb_sw_sets = NODEPDA(node)->migr_refcnt_numsets; - rcb.rcb_sw_counters_per_set = numnodes; - rcb.rcb_sw_counter_size = sizeof(refcnt_t); - - rcb.rcb_base_pages = NODEPDA(node)->migr_refcnt_numsets / - NUM_OF_HW_PAGES_PER_SW_PAGE(); - rcb.rcb_base_page_size = NBPP; - rcb.rcb_base_paddr = ctob(slot_getbasepfn(node, 0)); - - rcb.rcb_cnodeid = node; - rcb.rcb_granularity = MD_PAGE_SIZE; -#ifdef LATER - rcb.rcb_hw_counter_max = MIGR_COUNTER_MAX_GET(node); - rcb.rcb_diff_threshold = MIGR_THRESHOLD_DIFF_GET(node); -#endif - rcb.rcb_abs_threshold = MIGR_THRESHOLD_ABS_GET(node); - rcb.rcb_num_slots = MAX_MEM_SLOTS; - - if (COPYOUT(&rcb, arg, sizeof(rcb_info_t))) { - errcode = EFAULT; - } - - break; - } - case RCB_SLOT_GET: - { - rcb_slot_t slot[MAX_MEM_SLOTS]; - int s; - int nslots; - - nslots = MAX_MEM_SLOTS; - ASSERT(nslots <= MAX_MEM_SLOTS); - for (s = 0; s < nslots; s++) { - slot[s].base = (uint64_t)ctob(slot_getbasepfn(node, s)); -#ifdef LATER - slot[s].size = (uint64_t)ctob(slot_getsize(node, s)); -#else - slot[s].size = (uint64_t)1; -#endif - } - if (COPYOUT(&slot[0], arg, nslots * sizeof(rcb_slot_t))) { - errcode = EFAULT; - } - - *rvalp = nslots; - break; - } - - default: - errcode = EINVAL; - break; - - } - - return errcode; -} diff -Nru a/arch/ia64/sn/io/sn1/ml_SN_intr.c b/arch/ia64/sn/io/sn1/ml_SN_intr.c --- a/arch/ia64/sn/io/sn1/ml_SN_intr.c Sun May 25 17:00:00 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1154 +0,0 @@ -/* $Id: ml_SN_intr.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * intr.c- - * This file contains all of the routines necessary to set up and - * handle interrupts on an IP27 board. - */ - -#ident "$Revision: 1.1 $" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if DEBUG_INTR_TSTAMP_DEBUG -#include -#include -#include -void do_splx_log(int, int); -void spldebug_log_event(int); -#endif - -#ifdef CONFIG_SMP -extern unsigned long cpu_online_map; -#endif -#define cpu_allows_intr(cpu) (1) -// If I understand what's going on with this, 32 should work. -// physmem_maxradius seems to be the maximum number of router -// hops to get from one end of the system to the other. With -// a maximally configured machine, with the dumbest possible -// topology, we would make 32 router hops. For what we're using -// it for, the dumbest possible should suffice. -#define physmem_maxradius() 32 - -#define SUBNODE_ANY (-1) - -extern int nmied; -extern int hub_intr_wakeup_cnt; -extern synergy_da_t *Synergy_da_indr[]; -extern cpuid_t master_procid; - -extern cnodeid_t master_node_get(devfs_handle_t vhdl); - -extern void snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs); - - -#define INTR_LOCK(vecblk) \ - (s = mutex_spinlock(&(vecblk)->vector_lock)) -#define INTR_UNLOCK(vecblk) \ - mutex_spinunlock(&(vecblk)->vector_lock, s) - -/* - * REACT/Pro - */ - - - -/* - * Find first bit set - * Used outside this file also - */ -int ms1bit(unsigned long x) -{ - int b; - - if (x >> 32) b = 32, x >>= 32; - else b = 0; - if (x >> 16) b += 16, x >>= 16; - if (x >> 8) b += 8, x >>= 8; - if (x >> 4) b += 4, x >>= 4; - if (x >> 2) b += 2, x >>= 2; - - return b + (int) (x >> 1); -} - -/* ARGSUSED */ -void -intr_stray(void *lvl) -{ - printk(KERN_WARNING "Stray Interrupt - level %ld to cpu %d", (long)lvl, smp_processor_id()); -} - -#if defined(DEBUG) - -/* Infrastructure to gather the device - target cpu mapping info */ -#define MAX_DEVICES 1000 /* Reasonable large number . Need not be - * the exact maximum # devices possible. - */ -#define MAX_NAME 100 -typedef struct { - dev_t dev; /* device */ - cpuid_t cpuid; /* target cpu */ - cnodeid_t cnodeid;/* node on which the target cpu is present */ - int bit; /* intr bit reserved */ - char intr_name[MAX_NAME]; /* name of the interrupt */ -} intr_dev_targ_map_t; - -intr_dev_targ_map_t intr_dev_targ_map[MAX_DEVICES]; -uint64_t intr_dev_targ_map_size; -spinlock_t intr_dev_targ_map_lock; - -/* Print out the device - target cpu mapping. - * This routine is used only in the idbg command - * "intrmap" - */ -void -intr_dev_targ_map_print(cnodeid_t cnodeid) -{ - int i,j,size = 0; - int print_flag = 0,verbose = 0; - char node_name[10]; - - if (cnodeid != CNODEID_NONE) { - nodepda_t *npda; - - npda = NODEPDA(cnodeid); - for (j=0; jintr_dispatch0.info[i].ii_flags); - qprintf("\n INT_PEND1: "); - for(i = 0 ; i < N_INTPEND_BITS ; i++) - qprintf("%d",SNPDA(npda,j)->intr_dispatch1.info[i].ii_flags); - } - verbose = 1; - } - qprintf("\n Device - Target Map [Interrupts: %s Node%s]\n\n", - (verbose ? "All" : "Non-hardwired"), - (cnodeid == CNODEID_NONE) ? "s: All" : node_name); - - qprintf("Device\tCpu\tCnode\tIntr_bit\tIntr_name\n"); - for (i = 0 ; i < intr_dev_targ_map_size ; i++) { - - print_flag = 0; - if (verbose) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } else { - if (intr_dev_targ_map[i].dev != 0) { - if (cnodeid != CNODEID_NONE) { - if (cnodeid == - intr_dev_targ_map[i].cnodeid) - print_flag = 1; - } else { - print_flag = 1; - } - } - } - if (print_flag) { - size++; - qprintf("%d\t%d\t%d\t%d\t%s\n", - intr_dev_targ_map[i].dev, - intr_dev_targ_map[i].cpuid, - intr_dev_targ_map[i].cnodeid, - intr_dev_targ_map[i].bit, - intr_dev_targ_map[i].intr_name); - } - - } - qprintf("\nTotal : %d\n",size); -} -#endif /* DEBUG */ - -/* - * The spinlocks have already been initialized. Now initialize the interrupt - * vectors. One processor on each hub does the work. - */ -void -intr_init_vecblk(nodepda_t *npda, cnodeid_t node, int sn) -{ - int i, ip=0; - intr_vecblk_t *vecblk; - subnode_pda_t *snpda; - - - snpda = SNPDA(npda,sn); - do { - if (ip == 0) { - vecblk = &snpda->intr_dispatch0; - } else { - vecblk = &snpda->intr_dispatch1; - } - - /* Initialize this vector. */ - for (i = 0; i < N_INTPEND_BITS; i++) { - vecblk->vectors[i].iv_func = intr_stray; - vecblk->vectors[i].iv_prefunc = NULL; - vecblk->vectors[i].iv_arg = (void *)(__psint_t)(ip * N_INTPEND_BITS + i); - - vecblk->info[i].ii_owner_dev = 0; - strcpy(vecblk->info[i].ii_name, "Unused"); - vecblk->info[i].ii_flags = 0; /* No flags */ - vecblk->vectors[i].iv_mustruncpu = -1; /* No CPU yet. */ - - } - - mutex_spinlock_init(&vecblk->vector_lock); - - vecblk->vector_count = 0; - for (i = 0; i < CPUS_PER_SUBNODE; i++) - vecblk->cpu_count[i] = 0; - - vecblk->vector_state = VECTOR_UNINITED; - - } while (++ip < 2); - -} - - -/* - * do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - * devfs_handle_t owner_dev, char *name) - * Internal work routine to reserve or unreserve an interrupt level. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to reserve. -1 means any level - * resflags should include II_ERRORINT if this is an - * error interrupt, II_THREADED if the interrupt handler - * will be threaded, or 0 otherwise. - * reserve should be set to II_RESERVE or II_UNRESERVE - * to get or clear a reservation. - * owner_dev is the device that "owns" this interrupt, if supplied - * name is a human-readable name for this interrupt, if supplied - * intr_reserve_level returns the bit reserved or -1 to indicate an error - */ -static int -do_intr_reserve_level(cpuid_t cpu, int bit, int resflags, int reserve, - devfs_handle_t owner_dev, char *name) -{ - intr_vecblk_t *vecblk; - hub_intmasks_t *hub_intmasks; - unsigned long s; - int rv = 0; - int ip; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - // if (pdaindr[cpu].pda == NULL) return -1; - if ((bit < N_INTPEND_BITS) && !(resflags & II_ERRORINT)) { - vecblk = hub_intmasks->dispatch0; - ip = 0; - } else { - ASSERT((bit >= N_INTPEND_BITS) || (bit == -1)); - bit -= N_INTPEND_BITS; /* Get position relative to INT_PEND1 reg. */ - vecblk = hub_intmasks->dispatch1; - ip = 1; - } - - INTR_LOCK(vecblk); - - if (bit <= -1) { - bit = 0; - ASSERT(reserve == II_RESERVE); - /* Choose any available level */ - for (; bit < N_INTPEND_BITS; bit++) { - if (!(vecblk->info[bit].ii_flags & II_RESERVE)) { - rv = bit; - break; - } - } - - /* Return -1 if all interrupt levels int this register are taken. */ - if (bit == N_INTPEND_BITS) - rv = -1; - - } else { - /* Reserve a particular level if it's available. */ - if ((vecblk->info[bit].ii_flags & II_RESERVE) == reserve) { - /* Can't (un)reserve a level that's already (un)reserved. */ - rv = -1; - } else { - rv = bit; - } - } - - /* Reserve the level and bump the count. */ - if (rv != -1) { - if (reserve) { - vecblk->info[bit].ii_flags |= (II_RESERVE | resflags); - vecblk->info[bit].ii_owner_dev = owner_dev; - /* Copy in the name. */ - if (name) - strlcpy(vecblk->info[bit].ii_name, name, - sizeof(vecblk->info[bit].ii_name)); - else - vecblk->info[bit].ii_name[0] = '\0'; - vecblk->vector_count++; - } else { - vecblk->info[bit].ii_flags = 0; /* Clear all the flags */ - vecblk->info[bit].ii_owner_dev = 0; - /* Clear the name. */ - vecblk->info[bit].ii_name[0] = '\0'; - vecblk->vector_count--; - } - } - - INTR_UNLOCK(vecblk); - -#if defined(DEBUG) - if (rv >= 0) { - /* Gather this device - target cpu mapping information - * in a table which can be used later by the idbg "intrmap" - * command - */ - s = mutex_spinlock(&intr_dev_targ_map_lock); - if (intr_dev_targ_map_size < MAX_DEVICES) { - intr_dev_targ_map_t *p; - - p = &intr_dev_targ_map[intr_dev_targ_map_size]; - p->dev = owner_dev; - p->cpuid = cpu; - p->cnodeid = cpuid_to_cnodeid(cpu); - p->bit = ip * N_INTPEND_BITS + rv; - if (name) - strlcpy(p->intr_name, name, sizeof(p->intr_name)); - else - p->intr_name[0] = '\0'; - intr_dev_targ_map_size++; - } - mutex_spinunlock(&intr_dev_targ_map_lock,s); - } -#endif /* DEBUG */ - - return (((rv == -1) ? rv : (ip * N_INTPEND_BITS) + rv)) ; -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Reserve an interrupt level. - */ -int -intr_reserve_level(cpuid_t cpu, int bit, int resflags, devfs_handle_t owner_dev, char *name) -{ - return(do_intr_reserve_level(cpu, bit, resflags, II_RESERVE, owner_dev, name)); -} - - -/* - * WARNING: This routine should only be called from within ml/SN. - * Unreserve an interrupt level. - */ -void -intr_unreserve_level(cpuid_t cpu, int bit) -{ - (void)do_intr_reserve_level(cpu, bit, 0, II_UNRESERVE, 0, NULL); -} - -/* - * Get values that vary depending on which CPU and bit we're operating on - */ -static hub_intmasks_t * -intr_get_ptrs(cpuid_t cpu, int bit, - int *new_bit, /* Bit relative to the register */ - hubreg_t **intpend_masks, /* Masks for this register */ - intr_vecblk_t **vecblk, /* Vecblock for this interrupt */ - int *ip) /* Which intpend register */ -{ - hub_intmasks_t *hub_intmasks; - synergy_da_t *sda; - int which_synergy; - cnodeid_t cnode; - - ASSERT(bit < N_INTPEND_BITS * 2); - - cnode = cpuid_to_cnodeid(cpu); - which_synergy = cpuid_to_synergy(cpu); - sda = Synergy_da_indr[(cnode * 2) + which_synergy]; - hub_intmasks = &sda->s_intmasks; - - // hub_intmasks = &pdaindr[cpu].pda->p_intmasks; - - if (bit < N_INTPEND_BITS) { - *intpend_masks = hub_intmasks->intpend0_masks; - *vecblk = hub_intmasks->dispatch0; - *ip = 0; - *new_bit = bit; - } else { - *intpend_masks = hub_intmasks->intpend1_masks; - *vecblk = hub_intmasks->dispatch1; - *ip = 1; - *new_bit = bit - N_INTPEND_BITS; - } - - return hub_intmasks; -} - - -/* - * intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, - * intr_func_t intr_func, void *intr_arg); - * This is the lowest-level interface to the interrupt code. It shouldn't - * be called from outside the ml/SN directory. - * intr_connect_level hooks up an interrupt to a particular bit in - * the INT_PEND0/1 masks. Returns 0 on success. - * cpu is the CPU to which the interrupt will be sent. - * bit is the level bit to connect to - * intr_swlevel tells which software level to use - * intr_func is the interrupt handler - * intr_arg is an arbitrary argument interpreted by the handler - * intr_prefunc is a prologue function, to be called - * with interrupts disabled, to disable - * the interrupt at source. It is called - * with the same argument. Should be NULL for - * typical interrupts, which can be masked - * by the infrastructure at the level bit. - * intr_connect_level returns 0 on success or nonzero on an error - */ -/* ARGSUSED */ -int -intr_connect_level(cpuid_t cpu, int bit, ilvl_t intr_swlevel, intr_func_t intr_prefunc) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - int rv = 0; - int ip; - unsigned long s; - - ASSERT(bit < N_INTPEND_BITS * 2); - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & II_INUSE) || - (!(vecblk->info[bit].ii_flags & II_RESERVE))) { - /* Can't assign to a level that's in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_prefunc = intr_prefunc; - vecblk->info[bit].ii_flags |= II_INUSE; - } - - /* Now stuff the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - // nasid_t nasid = COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)); - nasid_t nasid = cpuid_to_nasid(cpu); - int subnode = cpuid_to_subnode(cpu); - - /* Make sure it's not already pending when we connect it. */ - REMOTE_HUB_PI_CLR_INTR(nasid, subnode, bit + ip * N_INTPEND_BITS); - - if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { - intpend_masks[0] |= (1ULL << (uint64_t)bit); - } - - lslice = cpuid_to_localslice(cpu); - vecblk->cpu_count[lslice]++; -#if SN1 - /* - * On SN1, there are 8 interrupt mask registers per node: - * PI_0 MASK_0 A - * PI_0 MASK_1 A - * PI_0 MASK_0 B - * PI_0 MASK_1 B - * PI_1 MASK_0 A - * PI_1 MASK_1 A - * PI_1 MASK_0 B - * PI_1 MASK_1 B - */ -#endif - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK0_A + PI_INT_MASK_OFFSET * lslice); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(nasid, subnode, - PI_INT_MASK1_A + PI_INT_MASK_OFFSET * lslice); - } - - HUB_S(mask_reg, intpend_masks[0]); - } - - INTR_UNLOCK(vecblk); - - return rv; -} - - -/* - * intr_disconnect_level(cpuid_t cpu, int bit) - * - * This is the lowest-level interface to the interrupt code. It should - * not be called from outside the ml/SN directory. - * intr_disconnect_level removes a particular bit from an interrupt in - * the INT_PEND0/1 masks. Returns 0 on success or nonzero on failure. - */ -int -intr_disconnect_level(cpuid_t cpu, int bit) -{ - intr_vecblk_t *vecblk; - hubreg_t *intpend_masks; - unsigned long s; - int rv = 0; - int ip; - - (void)intr_get_ptrs(cpu, bit, &bit, &intpend_masks, - &vecblk, &ip); - - INTR_LOCK(vecblk); - - if ((vecblk->info[bit].ii_flags & (II_RESERVE | II_INUSE)) != - ((II_RESERVE | II_INUSE))) { - /* Can't remove a level that's not in use or isn't reserved. */ - rv = -1; - } else { - /* Stuff parameters into vector and info */ - vecblk->vectors[bit].iv_func = (intr_func_t)NULL; - vecblk->vectors[bit].iv_prefunc = (intr_func_t)NULL; - vecblk->vectors[bit].iv_arg = 0; - vecblk->info[bit].ii_flags &= ~II_INUSE; -#ifdef BASE_ITHRTEAD - vecblk->vectors[bit].iv_mustruncpu = -1; /* No mustrun CPU any more. */ -#endif - } - - /* Now clear the masks if everything's okay. */ - if (!rv) { - int lslice; - volatile hubreg_t *mask_reg; - - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - lslice = cpuid_to_localslice(cpu); - vecblk->cpu_count[lslice]--; - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), - ip == 0 ? PI_INT_MASK0_A : PI_INT_MASK1_A); - mask_reg = (volatile hubreg_t *)((__psunsigned_t)mask_reg + - (PI_INT_MASK_OFFSET * lslice)); - *mask_reg = intpend_masks[0]; - } - - INTR_UNLOCK(vecblk); - - return rv; -} - -/* - * Actually block or unblock an interrupt - */ -void -do_intr_block_bit(cpuid_t cpu, int bit, int block) -{ - intr_vecblk_t *vecblk; - int ip; - unsigned long s; - hubreg_t *intpend_masks; - volatile hubreg_t mask_value; - volatile hubreg_t *mask_reg; - - intr_get_ptrs(cpu, bit, &bit, &intpend_masks, &vecblk, &ip); - - INTR_LOCK(vecblk); - - if (block) - /* Block */ - intpend_masks[0] &= ~(1ULL << (uint64_t)bit); - else - /* Unblock */ - intpend_masks[0] |= (1ULL << (uint64_t)bit); - - if (ip == 0) { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK0_A); - } else { - mask_reg = REMOTE_HUB_PI_ADDR(COMPACT_TO_NASID_NODEID(cpuid_to_cnodeid(cpu)), - cpuid_to_subnode(cpu), PI_INT_MASK1_A); - } - - HUB_S(mask_reg, intpend_masks[0]); - - /* - * Wait for it to take effect. (One read should suffice.) - * This is only necessary when blocking an interrupt - */ - if (block) - while ((mask_value = HUB_L(mask_reg)) != intpend_masks[0]) - ; - - INTR_UNLOCK(vecblk); -} - - -/* - * Block a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_block_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 1); -} - - -/* - * Unblock a particular interrupt (cpu/bit pair). - */ -/* ARGSUSED */ -void -intr_unblock_bit(cpuid_t cpu, int bit) -{ - do_intr_block_bit(cpu, bit, 0); -} - - -/* verifies that the specified CPUID is on the specified SUBNODE (if any) */ -#define cpu_on_subnode(cpuid, which_subnode) \ - (((which_subnode) == SUBNODE_ANY) || (cpuid_to_subnode(cpuid) == (which_subnode))) - - -/* - * Choose one of the CPUs on a specified node or subnode to receive - * interrupts. Don't pick a cpu which has been specified as a NOINTR cpu. - * - * Among all acceptable CPUs, the CPU that has the fewest total number - * of interrupts targetted towards it is chosen. Note that we never - * consider how frequent each of these interrupts might occur, so a rare - * hardware error interrupt is weighted equally with a disk interrupt. - */ -static cpuid_t -do_intr_cpu_choose(cnodeid_t cnode, int which_subnode) -{ - cpuid_t cpu, best_cpu = CPU_NONE; - int slice, min_count=1000; - - min_count = 1000; - for (slice=0; slice < CPUS_PER_NODE; slice++) { - intr_vecblk_t *vecblk0, *vecblk1; - int total_intrs_to_slice; - subnode_pda_t *snpda; - int local_cpu_num; - - cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) - continue; - - /* If this cpu isn't enabled for interrupts, skip it */ - if (!cpu_enabled(cpu) || !cpu_allows_intr(cpu)) - continue; - - /* If this isn't the right subnode, skip it */ - if (!cpu_on_subnode(cpu, which_subnode)) - continue; - - /* OK, this one's a potential CPU for interrupts */ - snpda = SUBNODEPDA(cnode,SUBNODE(slice)); - vecblk0 = &snpda->intr_dispatch0; - vecblk1 = &snpda->intr_dispatch1; - local_cpu_num = LOCALCPU(slice); - total_intrs_to_slice = vecblk0->cpu_count[local_cpu_num] + - vecblk1->cpu_count[local_cpu_num]; - - if (min_count > total_intrs_to_slice) { - min_count = total_intrs_to_slice; - best_cpu = cpu; - } - } - return best_cpu; -} - -/* - * Choose an appropriate interrupt target CPU on a specified node. - * If which_subnode is SUBNODE_ANY, then subnode is not considered. - * Otherwise, the chosen CPU must be on the specified subnode. - */ -static cpuid_t -intr_cpu_choose_from_node(cnodeid_t cnode, int which_subnode) -{ - return(do_intr_cpu_choose(cnode, which_subnode)); -} - - -/* Make it easy to identify subnode vertices in the hwgraph */ -void -mark_subnodevertex_as_subnode(devfs_handle_t vhdl, int which_subnode) -{ - graph_error_t rv; - - ASSERT(0 <= which_subnode); - ASSERT(which_subnode < NUM_SUBNODES); - - rv = hwgraph_info_add_LBL(vhdl, INFO_LBL_CPUBUS, (arbitrary_info_t)which_subnode); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); - - rv = hwgraph_info_export_LBL(vhdl, INFO_LBL_CPUBUS, sizeof(arbitrary_info_t)); - ASSERT_ALWAYS(rv == GRAPH_SUCCESS); -} - - -/* - * Given a device descriptor, extract interrupt target information and - * choose an appropriate CPU. Return CPU_NONE if we can't make sense - * out of the target information. - * TBD: Should this be considered platform-independent code? - */ - - -/* - * intr_bit_reserve_test(cpuid,which_subnode,cnode,req_bit,intr_resflags, - * owner_dev,intr_name,*resp_bit) - * Either cpuid is not CPU_NONE or cnodeid not CNODE_NONE but - * not both. - * 1. If cpuid is specified, this routine tests if this cpu can be a valid - * interrupt target candidate. - * 2. If cnodeid is specified, this routine tests if there is a cpu on - * this node which can be a valid interrupt target candidate. - * 3. If a valid interrupt target cpu candidate is found then an attempt at - * reserving an interrupt bit on the corresponding cnode is made. - * - * If steps 1 & 2 both fail or step 3 fails then we are not able to get a valid - * interrupt target cpu then routine returns CPU_NONE (failure) - * Otherwise routine returns cpuid of interrupt target (success) - */ -static cpuid_t -intr_bit_reserve_test(cpuid_t cpuid, - int favor_subnode, - cnodeid_t cnodeid, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - - ASSERT((cpuid==CPU_NONE) || (cnodeid==CNODEID_NONE)); - - if (cnodeid != CNODEID_NONE) { - /* Try to choose a interrupt cpu candidate */ - cpuid = intr_cpu_choose_from_node(cnodeid, favor_subnode); - } - - if (cpuid != CPU_NONE) { - /* Try to reserve an interrupt bit on the hub - * corresponding to the canidate cnode. If we - * are successful then we got a cpu which can - * act as an interrupt target for the io device. - * Otherwise we need to continue the search - * further. - */ - *resp_bit = do_intr_reserve_level(cpuid, - req_bit, - intr_resflags, - II_RESERVE, - owner_dev, - intr_name); - - if (*resp_bit >= 0) - /* The interrupt target specified was fine */ - return(cpuid); - } - return(CPU_NONE); -} -/* - * intr_heuristic(dev_t dev,device_desc_t dev_desc, - * int req_bit,int intr_resflags,dev_t owner_dev, - * char *intr_name,int *resp_bit) - * - * Choose an interrupt destination for an interrupt. - * dev is the device for which the interrupt is being set up - * dev_desc is a description of hardware and policy that could - * help determine where this interrupt should go - * req_bit is the interrupt bit requested - * (can be INTRCONNECT_ANY_BIT in which the first available - * interrupt bit is used) - * intr_resflags indicates whether we want to (un)reserve bit - * owner_dev is the owner device - * intr_name is the readable interrupt name - * resp_bit indicates whether we succeeded in getting the required - * action { (un)reservation} done - * negative value indicates failure - * - */ -/* ARGSUSED */ -cpuid_t -intr_heuristic(devfs_handle_t dev, - device_desc_t dev_desc, - int req_bit, - int intr_resflags, - devfs_handle_t owner_dev, - char *intr_name, - int *resp_bit) -{ - cpuid_t cpuid; /* possible intr targ*/ - cnodeid_t candidate; /* possible canidate */ - int which_subnode = SUBNODE_ANY; - -/* SN1 + pcibr Addressing Limitation */ - { - devfs_handle_t pconn_vhdl; - pcibr_soft_t pcibr_soft; - - /* - * This combination of SN1 and Bridge hardware has an odd "limitation". - * Due to the choice of addresses for PI0 and PI1 registers on SN1 - * and historical limitations in Bridge, Bridge is unable to - * send interrupts to both PI0 CPUs and PI1 CPUs -- we have - * to choose one set or the other. That choice is implicitly - * made when Bridge first attaches its error interrupt. After - * that point, all subsequent interrupts are restricted to the - * same PI number (though it's possible to send interrupts to - * the same PI number on a different node). - * - * Since neither SN1 nor Bridge designers are willing to admit a - * bug, we can't really call this a "workaround". It's a permanent - * solution for an SN1-specific and Bridge-specific hardware - * limitation that won't ever be lifted. - */ - if ((hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) && - ((pcibr_soft = pcibr_soft_get(pconn_vhdl)) != NULL)) { - /* - * We "know" that the error interrupt is the first - * interrupt set up by pcibr_attach. Send all interrupts - * on this bridge to the same subnode number. - */ - if (pcibr_soft->bsi_err_intr) { - which_subnode = cpuid_to_subnode(((hub_intr_t) pcibr_soft->bsi_err_intr)->i_cpuid); - } - } - } - - /* Check if we can find a valid interrupt target candidate on - * the master node for the device. - */ - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - master_node_get(dev), - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); /* got a valid interrupt target */ - else - intr_unreserve_level(cpuid, *resp_bit); - } - - printk(KERN_WARNING "Cannot target interrupts to closest node(%d): (0x%lx)\n", - master_node_get(dev),(unsigned long)owner_dev); - - /* Fall through into the default algorithm - * (exhaustive-search-for-the-nearest-possible-interrupt-target) - * for finding the interrupt target - */ - - { - /* - * Do a stupid round-robin assignment of the node. - * (Should do a "nearest neighbor" but not for SN1. - */ - static cnodeid_t last_node = -1; - - if (last_node >= numnodes) last_node = 0; - for (candidate = last_node + 1; candidate != last_node; candidate++) { - if (candidate == numnodes) candidate = 0; - cpuid = intr_bit_reserve_test(CPU_NONE, - which_subnode, - candidate, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) { - last_node = candidate; - return(cpuid); /* got a valid interrupt target */ - } - else - intr_unreserve_level(cpuid, *resp_bit); - } - } - last_node = candidate; - } - - printk(KERN_WARNING "Cannot target interrupts to any close node: %ld (0x%lx)\n", - (long)owner_dev, (unsigned long)owner_dev); - - /* In the worst case try to allocate interrupt bits on the - * master processor's node. We may get here during error interrupt - * allocation phase when the topology matrix is not yet setup - * and hence cannot do an exhaustive search. - */ - ASSERT(cpu_allows_intr(master_procid)); - cpuid = intr_bit_reserve_test(master_procid, - which_subnode, - CNODEID_NONE, - req_bit, - intr_resflags, - owner_dev, - intr_name, - resp_bit); - - if (cpuid != CPU_NONE) { - if (cpu_on_subnode(cpuid, which_subnode)) - return(cpuid); - else - intr_unreserve_level(cpuid, *resp_bit); - } - - printk(KERN_WARNING "Cannot target interrupts: (0x%lx)\n", - (unsigned long)owner_dev); - - return(CPU_NONE); /* Should never get here */ -} - -struct hardwired_intr_s { - signed char level; - int flags; - char *name; -} const hardwired_intr[] = { - { INT_PEND0_BASELVL + RESERVED_INTR, 0, "Reserved" }, - { INT_PEND0_BASELVL + GFX_INTR_A, 0, "Gfx A" }, - { INT_PEND0_BASELVL + GFX_INTR_B, 0, "Gfx B" }, - { INT_PEND0_BASELVL + PG_MIG_INTR, II_THREADED, "Migration" }, - { INT_PEND0_BASELVL + UART_INTR, II_THREADED, "Bedrock/L1" }, - { INT_PEND0_BASELVL + CC_PEND_A, 0, "Crosscall A" }, - { INT_PEND0_BASELVL + CC_PEND_B, 0, "Crosscall B" }, - { INT_PEND1_BASELVL + CLK_ERR_INTR, II_ERRORINT, "Clock Error" }, - { INT_PEND1_BASELVL + COR_ERR_INTR_A, II_ERRORINT, "Correctable Error A" }, - { INT_PEND1_BASELVL + COR_ERR_INTR_B, II_ERRORINT, "Correctable Error B" }, - { INT_PEND1_BASELVL + MD_COR_ERR_INTR, II_ERRORINT, "MD Correct. Error" }, - { INT_PEND1_BASELVL + NI_ERROR_INTR, II_ERRORINT, "NI Error" }, - { INT_PEND1_BASELVL + NI_BRDCAST_ERR_A, II_ERRORINT, "Remote NI Error"}, - { INT_PEND1_BASELVL + NI_BRDCAST_ERR_B, II_ERRORINT, "Remote NI Error"}, - { INT_PEND1_BASELVL + MSC_PANIC_INTR, II_ERRORINT, "MSC Panic" }, - { INT_PEND1_BASELVL + LLP_PFAIL_INTR_A, II_ERRORINT, "LLP Pfail WAR" }, - { INT_PEND1_BASELVL + LLP_PFAIL_INTR_B, II_ERRORINT, "LLP Pfail WAR" }, - { INT_PEND1_BASELVL + NACK_INT_A, 0, "CPU A Nack count == NACK_CMP" }, - { INT_PEND1_BASELVL + NACK_INT_B, 0, "CPU B Nack count == NACK_CMP" }, - { INT_PEND1_BASELVL + LB_ERROR, 0, "Local Block Error" }, - { INT_PEND1_BASELVL + XB_ERROR, 0, "Local XBar Error" }, - { -1, 0, (char *)NULL}, -}; - -/* - * Reserve all of the hardwired interrupt levels so they're not used as - * general purpose bits later. - */ -void -intr_reserve_hardwired(cnodeid_t cnode) -{ - cpuid_t cpu; - int level; - int i; - char subnode_done[NUM_SUBNODES]; - - // cpu = cnodetocpu(cnode); - for (cpu = 0; cpu < smp_num_cpus; cpu++) { - if (cpuid_to_cnodeid(cpu) == cnode) { - break; - } - } - if (cpu == smp_num_cpus) cpu = CPU_NONE; - if (cpu == CPU_NONE) { - printk("Node %d has no CPUs", cnode); - return; - } - - for (i=0; iii_name, - vector->iv_func, vector->iv_arg, vector->iv_prefunc); - pf(" vertex 0x%x %s%s", - info->ii_owner_dev, - ((info->ii_flags) & II_RESERVE) ? "R" : "U", - ((info->ii_flags) & II_INUSE) ? "C" : "-"); - pf("%s%s%s%s", - ip & value ? "P" : "-", - ima & value ? "A" : "-", - imb & value ? "B" : "-", - ((info->ii_flags) & II_ERRORINT) ? "E" : "-"); - pf("\n"); -} - - -/* - * Dump information about interrupt vector assignment. - */ -void -intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)) -{ - nodepda_t *npda; - int ip, sn, bit; - intr_vecblk_t *dispatch; - hubreg_t ipr, ima, imb; - nasid_t nasid; - - if ((cnode < 0) || (cnode >= numnodes)) { - pf("intr_dumpvec: cnodeid out of range: %d\n", cnode); - return ; - } - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - if (nasid == INVALID_NASID) { - pf("intr_dumpvec: Bad cnodeid: %d\n", cnode); - return ; - } - - - npda = NODEPDA(cnode); - - for (sn = 0; sn < NUM_SUBNODES; sn++) { - for (ip = 0; ip < 2; ip++) { - dispatch = ip ? &(SNPDA(npda,sn)->intr_dispatch1) : &(SNPDA(npda,sn)->intr_dispatch0); - ipr = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_PEND1 : PI_INT_PEND0); - ima = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_A : PI_INT_MASK0_A); - imb = REMOTE_HUB_PI_L(nasid, sn, ip ? PI_INT_MASK1_B : PI_INT_MASK0_B); - - pf("Node %d INT_PEND%d:\n", cnode, ip); - - if (dispatch->ithreads_enabled) - pf(" Ithreads enabled\n"); - else - pf(" Ithreads disabled\n"); - pf(" vector_count = %d, vector_state = %d\n", - dispatch->vector_count, - dispatch->vector_state); - pf(" CPU A count %d, CPU B count %d\n", - dispatch->cpu_count[0], - dispatch->cpu_count[1]); - pf(" &vector_lock = 0x%x\n", - &(dispatch->vector_lock)); - for (bit = 0; bit < N_INTPEND_BITS; bit++) { - if ((dispatch->info[bit].ii_flags & II_RESERVE) || - (ipr & (1L << bit))) { - dump_vector(&(dispatch->info[bit]), - &(dispatch->vectors[bit]), - bit, ipr, ima, imb, pf); - } - } - pf("\n"); - } - } -} - diff -Nru a/arch/ia64/sn/io/sn1/pcibr.c b/arch/ia64/sn/io/sn1/pcibr.c --- a/arch/ia64/sn/io/sn1/pcibr.c Tue Feb 25 10:47:06 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,7704 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -int NeedXbridgeSwap = 0; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - -extern boolean_t is_sys_critical_vertex(devfs_handle_t); - -#undef PCIBR_ATE_DEBUG - -#if 0 -#define DEBUG 1 /* To avoid lots of bad printk() formats leave off */ -#endif -#define PCI_DEBUG 1 -#define ATTACH_DEBUG 1 -#define PCIBR_SOFT_LIST 1 - -#ifndef LOCAL -#define LOCAL static -#endif - -/* - * Macros related to the Lucent USS 302/312 usb timeout workaround. It - * appears that if the lucent part can get into a retry loop if it sees a - * DAC on the bus during a pio read retry. The loop is broken after about - * 1ms, so we need to set up bridges holding this part to allow at least - * 1ms for pio. - */ - -#define USS302_TIMEOUT_WAR - -#ifdef USS302_TIMEOUT_WAR -#define LUCENT_USBHC_VENDOR_ID_NUM 0x11c1 -#define LUCENT_USBHC302_DEVICE_ID_NUM 0x5801 -#define LUCENT_USBHC312_DEVICE_ID_NUM 0x5802 -#define USS302_BRIDGE_TIMEOUT_HLD 4 -#endif - -#define PCIBR_LLP_CONTROL_WAR -#if defined (PCIBR_LLP_CONTROL_WAR) -int pcibr_llp_control_war_cnt; -#endif /* PCIBR_LLP_CONTROL_WAR */ - -int pcibr_devflag = D_MP; - -#ifdef LATER -#define F(s,n) { 1l<<(s),-(s), n } - -struct reg_desc bridge_int_status_desc[] = -{ - F(31, "MULTI_ERR"), - F(30, "PMU_ESIZE_EFAULT"), - F(29, "UNEXPECTED_RESP"), - F(28, "BAD_XRESP_PACKET"), - F(27, "BAD_XREQ_PACKET"), - F(26, "RESP_XTALK_ERROR"), - F(25, "REQ_XTALK_ERROR"), - F(24, "INVALID_ADDRESS"), - F(23, "UNSUPPORTED_XOP"), - F(22, "XREQ_FIFO_OFLOW"), - F(21, "LLP_REC_SNERROR"), - F(20, "LLP_REC_CBERROR"), - F(19, "LLP_RCTY"), - F(18, "LLP_TX_RETRY"), - F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), - F(15, "PCI_ABORT"), - F(14, "PCI_PARITY"), - F(13, "PCI_SERR"), - F(12, "PCI_PERR"), - F(11, "PCI_MASTER_TOUT"), - F(10, "PCI_RETRY_CNT"), - F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), - F(7, "INT7"), - F(6, "INT6"), - F(5, "INT5"), - F(4, "INT4"), - F(3, "INT3"), - F(2, "INT2"), - F(1, "INT1"), - F(0, "INT0"), - {0} -}; - -struct reg_values space_v[] = -{ - {PCIIO_SPACE_NONE, "none"}, - {PCIIO_SPACE_ROM, "ROM"}, - {PCIIO_SPACE_IO, "I/O"}, - {PCIIO_SPACE_MEM, "MEM"}, - {PCIIO_SPACE_MEM32, "MEM(32)"}, - {PCIIO_SPACE_MEM64, "MEM(64)"}, - {PCIIO_SPACE_CFG, "CFG"}, - {PCIIO_SPACE_WIN(0), "WIN(0)"}, - {PCIIO_SPACE_WIN(1), "WIN(1)"}, - {PCIIO_SPACE_WIN(2), "WIN(2)"}, - {PCIIO_SPACE_WIN(3), "WIN(3)"}, - {PCIIO_SPACE_WIN(4), "WIN(4)"}, - {PCIIO_SPACE_WIN(5), "WIN(5)"}, - {PCIIO_SPACE_BAD, "BAD"}, - {0} -}; - -struct reg_desc space_desc[] = -{ - {0xFF, 0, "space", 0, space_v}, - {0} -}; - -#if DEBUG -#define device_desc device_bits -LOCAL struct reg_desc device_bits[] = -{ - {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, - {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, - {BRIDGE_DEV_FORCE_PCI_PAR, 0, "FORCE_PCI_PAR"}, - {BRIDGE_DEV_VIRTUAL_EN, 0, "VIRTUAL_EN"}, - {BRIDGE_DEV_PMU_WRGA_EN, 0, "PMU_WRGA_EN"}, - {BRIDGE_DEV_DIR_WRGA_EN, 0, "DIR_WRGA_EN"}, - {BRIDGE_DEV_DEV_SIZE, 0, "DEV_SIZE"}, - {BRIDGE_DEV_RT, 0, "RT"}, - {BRIDGE_DEV_SWAP_PMU, 0, "SWAP_PMU"}, - {BRIDGE_DEV_SWAP_DIR, 0, "SWAP_DIR"}, - {BRIDGE_DEV_PREF, 0, "PREF"}, - {BRIDGE_DEV_PRECISE, 0, "PRECISE"}, - {BRIDGE_DEV_COH, 0, "COH"}, - {BRIDGE_DEV_BARRIER, 0, "BARRIER"}, - {BRIDGE_DEV_GBR, 0, "GBR"}, - {BRIDGE_DEV_DEV_SWAP, 0, "DEV_SWAP"}, - {BRIDGE_DEV_DEV_IO_MEM, 0, "DEV_IO_MEM"}, - {BRIDGE_DEV_OFF_MASK, BRIDGE_DEV_OFF_ADDR_SHFT, "DEV_OFF", "%x"}, - {0} -}; -#endif /* DEBUG */ - -#ifdef SUPPORT_PRINTING_R_FORMAT -LOCAL struct reg_values xio_cmd_pactyp[] = -{ - {0x0, "RdReq"}, - {0x1, "RdResp"}, - {0x2, "WrReqWithResp"}, - {0x3, "WrResp"}, - {0x4, "WrReqNoResp"}, - {0x5, "Reserved(5)"}, - {0x6, "FetchAndOp"}, - {0x7, "Reserved(7)"}, - {0x8, "StoreAndOp"}, - {0x9, "Reserved(9)"}, - {0xa, "Reserved(a)"}, - {0xb, "Reserved(b)"}, - {0xc, "Reserved(c)"}, - {0xd, "Reserved(d)"}, - {0xe, "SpecialReq"}, - {0xf, "SpecialResp"}, - {0} -}; - -LOCAL struct reg_desc xio_cmd_bits[] = -{ - {WIDGET_DIDN, -28, "DIDN", "%x"}, - {WIDGET_SIDN, -24, "SIDN", "%x"}, - {WIDGET_PACTYP, -20, "PACTYP", 0, xio_cmd_pactyp}, - {WIDGET_TNUM, -15, "TNUM", "%x"}, - {WIDGET_COHERENT, 0, "COHERENT"}, - {WIDGET_DS, 0, "DS"}, - {WIDGET_GBR, 0, "GBR"}, - {WIDGET_VBPM, 0, "VBPM"}, - {WIDGET_ERROR, 0, "ERROR"}, - {WIDGET_BARRIER, 0, "BARRIER"}, - {0} -}; -#endif /* SUPPORT_PRINTING_R_FORMAT */ - -#if PCIBR_FREEZE_TIME || PCIBR_ATE_DEBUG -LOCAL struct reg_desc ate_bits[] = -{ - {0xFFFF000000000000ull, -48, "RMF", "%x"}, - {~(IOPGSIZE - 1) & /* may trim off some low bits */ - 0x0000FFFFFFFFF000ull, 0, "XIO", "%x"}, - {0x0000000000000F00ull, -8, "port", "%x"}, - {0x0000000000000010ull, 0, "Barrier"}, - {0x0000000000000008ull, 0, "Prefetch"}, - {0x0000000000000004ull, 0, "Precise"}, - {0x0000000000000002ull, 0, "Coherent"}, - {0x0000000000000001ull, 0, "Valid"}, - {0} -}; -#endif - -#if PCIBR_ATE_DEBUG -LOCAL struct reg_values ssram_sizes[] = -{ - {BRIDGE_CTRL_SSRAM_512K, "512k"}, - {BRIDGE_CTRL_SSRAM_128K, "128k"}, - {BRIDGE_CTRL_SSRAM_64K, "64k"}, - {BRIDGE_CTRL_SSRAM_1K, "1k"}, - {0} -}; - -LOCAL struct reg_desc control_bits[] = -{ - {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"}, - {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"}, - {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"}, - {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"}, - {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"}, - {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"}, - {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"}, - {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"}, - {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"}, - {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"}, - {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes}, - {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"}, - {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"}, - {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"}, - {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"}, - {BRIDGE_CTRL_SYS_END, 0, "SYS_END"}, - {BRIDGE_CTRL_MAX_TRANS_MASK, -4, "MAX_TRANS", "%d"}, - {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"}, - {0} -}; -#endif -#endif /* LATER */ - -/* kbrick widgetnum-to-bus layout */ -int p_busnum[MAX_PORT_NUM] = { /* widget# */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 2, /* 0x8 */ - 1, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 5, /* 0xc */ - 6, /* 0xd */ - 4, /* 0xe */ - 3, /* 0xf */ -}; - -/* - * Additional PIO spaces per slot are - * recorded in this structure. - */ -struct pciio_piospace_s { - pciio_piospace_t next; /* another space for this device */ - char free; /* 1 if free, 0 if in use */ - pciio_space_t space; /* Which space is in use */ - iopaddr_t start; /* Starting address of the PIO space */ - size_t count; /* size of PIO space */ -}; - -#if PCIBR_SOFT_LIST -pcibr_list_p pcibr_list = 0; -#endif - -#define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" - -#define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) -#define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) - -#define PCIBR_VALID_SLOT(s) (s < 8) - -#ifdef SN_XXX -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); -#endif -extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); -extern void free_pciio_dmamap(pcibr_dmamap_t); - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - -extern devfs_handle_t hwgraph_root; -extern graph_error_t hwgraph_vertex_unref(devfs_handle_t vhdl); -extern int cap_able(uint64_t x); -extern uint64_t rmalloc(struct map *mp, size_t size); -extern void rmfree(struct map *mp, size_t size, uint64_t a); -extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); -extern long atoi(register char *p); -extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr); -extern struct map *rmallocmap(uint64_t mapsiz); -extern void rmfreemap(struct map *mp); -extern int compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr); -extern int io_path_map_widget(devfs_handle_t vertex); - - - -/* ===================================================================== - * Function Table of Contents - * - * The order of functions in this file has stopped - * making much sense. We might want to take a look - * at it some time and bring back some sanity, or - * perhaps bust this file into smaller chunks. - */ - -LOCAL void do_pcibr_rrb_clear(bridge_t *, int); -LOCAL void do_pcibr_rrb_flush(bridge_t *, int); -LOCAL int do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t); -LOCAL int do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int); -LOCAL int do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int); - -LOCAL void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int); - -int pcibr_wrb_flush(devfs_handle_t); -int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -int pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int); -void pcibr_rrb_flush(devfs_handle_t); - -LOCAL int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); -void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); - -LOCAL void pcibr_clearwidint(bridge_t *); -LOCAL void pcibr_setwidint(xtalk_intr_t); -LOCAL int pcibr_probe_slot(bridge_t *, cfg_p, unsigned *); - -void pcibr_init(void); -int pcibr_attach(devfs_handle_t); -int pcibr_detach(devfs_handle_t); -int pcibr_open(devfs_handle_t *, int, int, cred_t *); -int pcibr_close(devfs_handle_t, int, int, cred_t *); -int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int pcibr_unmap(devfs_handle_t, vhandl_t *); -int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -void pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t); - -LOCAL int pcibr_init_ext_ate_ram(bridge_t *); -LOCAL int pcibr_ate_alloc(pcibr_soft_t, int); -LOCAL void pcibr_ate_free(pcibr_soft_t, int, int); - -LOCAL pcibr_info_t pcibr_info_get(devfs_handle_t); -LOCAL pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -LOCAL void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); -LOCAL iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); - -pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pcibr_piomap_free(pcibr_piomap_t); -caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); -void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); - -LOCAL iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); -LOCAL bridge_ate_t pcibr_flags_to_ate(unsigned); - -pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void pcibr_dmamap_free(pcibr_dmamap_t); -LOCAL bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -LOCAL iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); -iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); -void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); -iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); - -static unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines); -pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); -void pcibr_intr_free(pcibr_intr_t); -LOCAL void pcibr_setpciint(xtalk_intr_t); -int pcibr_intr_connect(pcibr_intr_t); -void pcibr_intr_disconnect(pcibr_intr_t); - -devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); -void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void pcibr_intr_func(intr_arg_t); - -void pcibr_provider_startup(devfs_handle_t); -void pcibr_provider_shutdown(devfs_handle_t); - -int pcibr_reset(devfs_handle_t); -pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); -int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); - -LOCAL cfg_p pcibr_config_addr(devfs_handle_t, unsigned); -uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -LOCAL uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); -void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -LOCAL void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); - -LOCAL pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -void pcibr_hints_fix_rrbs(devfs_handle_t); -void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); - -LOCAL int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); - -#ifdef LATER -LOCAL int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, - pcibr_slot_info_resp_t); -LOCAL void pcibr_slot_func_info_return(pcibr_info_h, int, - pcibr_slot_func_info_resp_t); -#endif /* LATER */ - -LOCAL int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); -LOCAL int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); -LOCAL int pcibr_slot_call_device_attach(devfs_handle_t, - pciio_slot_t, int); -LOCAL int pcibr_slot_call_device_detach(devfs_handle_t, - pciio_slot_t, int); - -LOCAL int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int); -LOCAL int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); -#ifdef LATER -LOCAL int pcibr_slot_query(devfs_handle_t, pcibr_slot_info_req_t); -#endif - -/* ===================================================================== - * RRB management - */ - -#define LSBIT(word) ((word) &~ ((word)-1)) - -#define PCIBR_RRB_SLOT_VIRTUAL 8 - -LOCAL void -do_pcibr_rrb_clear(bridge_t *bridge, int rrb) -{ - bridgereg_t status; - - /* bridge_lock must be held; - * this RRB must be disabled. - */ - - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } -} - -LOCAL void -do_pcibr_rrb_flush(bridge_t *bridge, int rrbn) -{ - reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; - bridgereg_t rrbv; - int shft = 4 * (rrbn >> 1); - unsigned ebit = BRIDGE_RRB_EN << shft; - - rrbv = *rrbp; - if (rrbv & ebit) - *rrbp = rrbv & ~ebit; - - do_pcibr_rrb_clear(bridge, rrbn); - - if (rrbv & ebit) - *rrbp = rrbv; -} - -/* - * pcibr_rrb_count_valid: count how many RRBs are - * marked valid for the specified PCI slot on this - * bridge. - * - * NOTE: The "slot" parameter for all pcibr_rrb - * management routines must include the "virtual" - * bit; when manageing both the normal and the - * virtual channel, separate calls to these - * routines must be made. To denote the virtual - * channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot - * number. - * - * IMPL NOTE: The obvious algorithm is to iterate - * through the RRB fields, incrementing a count if - * the RRB is valid and matches the slot. However, - * it is much simpler to use an algorithm derived - * from the "partitioned add" idea. First, XOR in a - * pattern such that the fields that match this - * slot come up "all ones" and all other fields - * have zeros in the mismatching bits. Then AND - * together the bits in the field, so we end up - * with one bit turned on for each field that - * matched. Now we need to count these bits. This - * can be done either with a series of shift/add - * instructions or by using "tmp % 15"; I expect - * that the cascaded shift/add will be faster. - */ - -LOCAL int -do_pcibr_rrb_count_valid(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp ^= 0x11111111 * (7 - slot / 2); - tmp &= (0xCCCCCCCC & tmp) >> 2; - tmp &= (0x22222222 & tmp) >> 1; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_count_avail: count how many RRBs are - * available to be allocated for the specified slot. - * - * IMPL NOTE: similar to the above, except we are - * just counting how many fields have the valid bit - * turned off. - */ -LOCAL int -do_pcibr_rrb_count_avail(bridge_t *bridge, - pciio_slot_t slot) -{ - bridgereg_t tmp; - - tmp = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~tmp) >> 3; - tmp += tmp >> 4; - tmp += tmp >> 8; - tmp += tmp >> 16; - return tmp & 15; -} - -/* - * do_pcibr_rrb_alloc: allocate some additional RRBs - * for the specified slot. Returns -1 if there were - * insufficient free RRBs to satisfy the request, - * or 0 if the request was fulfilled. - * - * Note that if a request can be partially filled, - * it will be, even if we return failure. - * - * IMPL NOTE: again we avoid iterating across all - * the RRBs; instead, we form up a word containing - * one bit for each free RRB, then peel the bits - * off from the low end. - */ -LOCAL int -do_pcibr_rrb_alloc(bridge_t *bridge, - pciio_slot_t slot, - int more) -{ - int rv = 0; - bridgereg_t reg, tmp, bit; - - reg = bridge->b_rrb_map[slot & 1].reg; - tmp = (0x88888888 & ~reg) >> 3; - while (more-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2))); - } - bridge->b_rrb_map[slot & 1].reg = reg; - return rv; -} - -/* - * do_pcibr_rrb_free: release some of the RRBs that - * have been allocated for the specified - * slot. Returns zero for success, or negative if - * it was unable to free that many RRBs. - * - * IMPL NOTE: We form up a bit for each RRB - * allocated to the slot, aligned with the VALID - * bitfield this time; then we peel bits off one at - * a time, releasing the corresponding RRB. - */ -LOCAL int -do_pcibr_rrb_free(bridge_t *bridge, - pciio_slot_t slot, - int less) -{ - int rv = 0; - bridgereg_t reg, tmp, clr, bit; - int i; - - clr = 0; - reg = bridge->b_rrb_map[slot & 1].reg; - - /* This needs to be done otherwise the rrb's on the virtual channel - * for this slot won't be freed !! - */ - tmp = reg & 0xbbbbbbbb; - - tmp ^= (0x11111111 * (7 - slot / 2)); - tmp &= (0x33333333 & tmp) << 2; - tmp &= (0x44444444 & tmp) << 1; - while (less-- > 0) { - bit = LSBIT(tmp); - if (!bit) { - rv = -1; - break; - } - tmp &= ~bit; - reg &= ~bit; - clr |= bit; - } - bridge->b_rrb_map[slot & 1].reg = reg; - - for (i = 0; i < 8; i++) - if (clr & (8 << (4 * i))) - do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1)); - - return rv; -} - -LOCAL void -do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, - int slot, - int more_rrbs) -{ - bridge_t *bridge = pcibr_soft->bs_base; - int got; - - for (got = 0; got < more_rrbs; ++got) { - if (pcibr_soft->bs_rrb_res[slot & 7] > 0) - pcibr_soft->bs_rrb_res[slot & 7]--; - else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) - pcibr_soft->bs_rrb_avail[slot & 1]--; - else - break; - if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0) - break; -#if PCIBR_RRB_DEBUG - printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n", - slot & 7, slot & 8 ? "v" : ""); -#endif - pcibr_soft->bs_rrb_valid[slot]++; - } -#if PCIBR_RRB_DEBUG - printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (slot = 0; slot < 8; ++slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif -} - -/* - * Device driver interface to flush the write buffers for a specified - * device hanging off the bridge. - */ -int -pcibr_wrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - volatile bridgereg_t *wrb_flush; - - wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); - while (*wrb_flush); - - return(0); -} -/* - * Device driver interface to request RRBs for a specified device - * hanging off a Bridge. The driver requests the total number of - * RRBs it would like for the normal channel (vchan0) and for the - * "virtual channel" (vchan1). The actual number allocated to each - * channel is returned. - * - * If we cannot allocate at least one RRB to a channel that needs - * at least one, return -1 (failure). Otherwise, satisfy the request - * as best we can and return 0. - */ -int -pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - int desired_vchan0; - int desired_vchan1; - int orig_vchan0; - int orig_vchan1; - int delta_vchan0; - int delta_vchan1; - int final_vchan0; - int final_vchan1; - int avail_rrbs; - unsigned long s; - int error; - - /* - * TBD: temper request with admin info about RRB allocation, - * and according to demand from other devices on this Bridge. - * - * One way of doing this would be to allocate two RRBs - * for each device on the bus, before any drivers start - * asking for extras. This has the weakness that one - * driver might not give back an "extra" RRB until after - * another driver has already failed to get one that - * it wanted. - */ - - s = pcibr_lock(pcibr_soft); - - /* How many RRBs do we own? */ - orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; - orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - /* How many RRBs do we want? */ - desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; - desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; - - /* How many RRBs are free? */ - avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot]; - - /* Figure desired deltas */ - delta_vchan0 = desired_vchan0 - orig_vchan0; - delta_vchan1 = desired_vchan1 - orig_vchan1; - - /* Trim back deltas to something - * that we can actually meet, by - * decreasing the ending allocation - * for whichever channel wants - * more RRBs. If both want the same - * number, cut the second channel. - * NOTE: do not change the allocation for - * a channel that was passed as NULL. - */ - while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { - if (count_vchan0 && - (!count_vchan1 || - ((orig_vchan0 + delta_vchan0) > - (orig_vchan1 + delta_vchan1)))) - delta_vchan0--; - else - delta_vchan1--; - } - - /* Figure final RRB allocations - */ - final_vchan0 = orig_vchan0 + delta_vchan0; - final_vchan1 = orig_vchan1 + delta_vchan1; - - /* If either channel wants RRBs but our actions - * would leave it with none, declare an error, - * but DO NOT change any RRB allocations. - */ - if ((desired_vchan0 && !final_vchan0) || - (desired_vchan1 && !final_vchan1)) { - - error = -1; - - } else { - - /* Commit the allocations: free, then alloc. - */ - if (delta_vchan0 < 0) - (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0); - if (delta_vchan1 < 0) - (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1); - - if (delta_vchan0 > 0) - (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0); - if (delta_vchan1 > 0) - (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1); - - /* Return final values to caller. - */ - if (count_vchan0) - *count_vchan0 = final_vchan0; - if (count_vchan1) - *count_vchan1 = final_vchan1; - - /* prevent automatic changes to this slot's RRBs - */ - pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; - - /* Track the actual allocations, release - * any further reservations, and update the - * number of available RRBs. - */ - - pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0; - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot] - - delta_vchan0 - - delta_vchan1; - pcibr_soft->bs_rrb_res[pciio_slot] = 0; - -#if PCIBR_RRB_DEBUG - printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", - pciio_slot, final_vchan0, final_vchan1, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], - 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[pciio_slot]); - printk("\n"); -#endif - - error = 0; - } - - pcibr_unlock(pcibr_soft, s); - return error; -} - -/* - * Device driver interface to check the current state - * of the RRB allocations. - * - * pconn_vhdl is your PCI connection point (specifies which - * PCI bus and which slot). - * - * count_vchan0 points to where to return the number of RRBs - * assigned to the primary DMA channel, used by all DMA - * that does not explicitly ask for the alternate virtual - * channel. - * - * count_vchan1 points to where to return the number of RRBs - * assigned to the secondary DMA channel, used when - * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. - * - * count_reserved points to where to return the number of RRBs - * that have been automatically reserved for your device at - * startup, but which have not been assigned to a - * channel. RRBs must be assigned to a channel to be used; - * this can be done either with an explicit pcibr_rrb_alloc - * call, or automatically by the infrastructure when a DMA - * translation is constructed. Any call to pcibr_rrb_alloc - * will release any unassigned reserved RRBs back to the - * free pool. - * - * count_pool points to where to return the number of RRBs - * that are currently unassigned and unreserved. This - * number can (and will) change as other drivers make calls - * to pcibr_rrb_alloc, or automatically allocate RRBs for - * DMA beyond their initial reservation. - * - * NULL may be passed for any of the return value pointers - * the caller is not interested in. - * - * The return value is "0" if all went well, or "-1" if - * there is a problem. Additionally, if the wrong vertex - * is passed in, one of the subsidiary support functions - * could panic with a "bad pciio fingerprint." - */ - -int -pcibr_rrb_check(devfs_handle_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1, - int *count_reserved, - int *count_pool) -{ - pciio_info_t pciio_info; - pciio_slot_t pciio_slot; - pcibr_soft_t pcibr_soft; - unsigned long s; - int error = -1; - - if ((pciio_info = pciio_info_get(pconn_vhdl)) && - (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && - ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { - - s = pcibr_lock(pcibr_soft); - - if (count_vchan0) - *count_vchan0 = - pcibr_soft->bs_rrb_valid[pciio_slot]; - - if (count_vchan1) - *count_vchan1 = - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; - - if (count_reserved) - *count_reserved = - pcibr_soft->bs_rrb_res[pciio_slot]; - - if (count_pool) - *count_pool = - pcibr_soft->bs_rrb_avail[pciio_slot & 1]; - - error = 0; - - pcibr_unlock(pcibr_soft, s); - } - return error; -} - -/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities - * requested for each of the devies. The evn_odd argument indicates whether - * allcoation for the odd or even rrbs is requested and next group of four pairse - * are the amount to assign to each device (they should sum to <= 8) and - * whether to set the viritual bit for that device (1 indictaes yes, 0 indicates no) - * the devices in order are either 0, 2, 4, 6 or 1, 3, 5, 7 - * if even_odd is even we alloc even rrbs else we allocate odd rrbs - * returns 0 if no errors else returns -1 - */ - -int -pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, - int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, - int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4) -{ - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft = NULL; - bridge_t *bridge = NULL; - - uint32_t rrb_setting = 0; - int rrb_shift = 7; - uint32_t cur_rrb; - int dev_rrbs[4]; - int virt[4]; - int i, j; - unsigned long s; - - if (GRAPH_SUCCESS == - hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) - bridge = pcibr_soft->bs_base; - hwgraph_vertex_unref(pcibr_vhdl); - } - if (bridge == NULL) - bridge = (bridge_t *) xtalk_piotrans_addr - (vhdl, NULL, 0, sizeof(bridge_t), 0); - - even_odd &= 1; - - dev_rrbs[0] = dev_1_rrbs; - dev_rrbs[1] = dev_2_rrbs; - dev_rrbs[2] = dev_3_rrbs; - dev_rrbs[3] = dev_4_rrbs; - - virt[0] = virt1; - virt[1] = virt2; - virt[2] = virt3; - virt[3] = virt4; - - if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { - return -1; - } - if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { - return -1; - } - /* walk through rrbs */ - for (i = 0; i < 4; i++) { - if (virt[i]) { - cur_rrb = i | 0xc; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - dev_rrbs[i] = dev_rrbs[i] - 1; - } - for (j = 0; j < dev_rrbs[i]; j++) { - cur_rrb = i | 0x8; - cur_rrb = cur_rrb << (rrb_shift * 4); - rrb_shift--; - rrb_setting = rrb_setting | cur_rrb; - } - } - - if (pcibr_soft) - s = pcibr_lock(pcibr_soft); - - bridge->b_rrb_map[even_odd].reg = rrb_setting; - - if (pcibr_soft) { - - pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; - - /* since we've "FIXED" the allocations - * for these slots, we probably can dispense - * with tracking avail/res/valid data, but - * keeping it up to date helps debugging. - */ - - pcibr_soft->bs_rrb_avail[even_odd] = - 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); - - pcibr_soft->bs_rrb_res[even_odd + 0] = 0; - pcibr_soft->bs_rrb_res[even_odd + 2] = 0; - pcibr_soft->bs_rrb_res[even_odd + 4] = 0; - pcibr_soft->bs_rrb_res[even_odd + 6] = 0; - - pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; - - pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; - pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; - pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; - pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; - - pcibr_unlock(pcibr_soft, s); - } - return 0; -} - -/* - * pcibr_rrb_flush: chase down all the RRBs assigned - * to the specified connection point, and flush - * them. - */ -void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - unsigned long s; - reg_p rrbp; - unsigned rrbm; - int i; - int rrbn; - unsigned sval; - unsigned mask; - - sval = BRIDGE_RRB_EN | (pciio_slot >> 1); - mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; - rrbn = pciio_slot & 1; - rrbp = &bridge->b_rrb_map[rrbn].reg; - - s = pcibr_lock(pcibr_soft); - rrbm = *rrbp; - for (i = 0; i < 8; ++i) { - if ((rrbm & mask) == sval) - do_pcibr_rrb_flush(bridge, rrbn); - rrbm >>= 4; - rrbn += 2; - } - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Device(x) register management - */ - -/* pcibr_try_set_device: attempt to modify Device(x) - * for the specified slot on the specified bridge - * as requested in flags, limited to the specified - * bits. Returns which BRIDGE bits were in conflict, - * or ZERO if everything went OK. - * - * Caller MUST hold pcibr_lock when calling this function. - */ -LOCAL int -pcibr_try_set_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - unsigned flags, - bridgereg_t mask) -{ - bridge_t *bridge; - pcibr_soft_slot_t slotp; - bridgereg_t old; - bridgereg_t new; - bridgereg_t chg; - bridgereg_t bad; - bridgereg_t badpmu; - bridgereg_t badd32; - bridgereg_t badd64; - bridgereg_t fix; - unsigned long s; - bridgereg_t xmask; - - xmask = mask; - if (pcibr_soft->bs_xbridge) { - if (mask == BRIDGE_DEV_PMU_BITS) - xmask = XBRIDGE_DEV_PMU_BITS; - if (mask == BRIDGE_DEV_D64_BITS) - xmask = XBRIDGE_DEV_D64_BITS; - } - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - bridge = pcibr_soft->bs_base; - - old = slotp->bss_device; - - /* figure out what the desired - * Device(x) bits are based on - * the flags specified. - */ - - new = old; - - /* Currently, we inherit anything that - * the new caller has not specified in - * one way or another, unless we take - * action here to not inherit. - * - * This is needed for the "swap" stuff, - * since it could have been set via - * pcibr_endian_set -- altho note that - * any explicit PCIBR_BYTE_STREAM or - * PCIBR_WORD_VALUES will freely override - * the effect of that call (and vice - * versa, no protection either way). - * - * I want to get rid of pcibr_endian_set - * in favor of tracking DMA endianness - * using the flags specified when DMA - * channels are created. - */ - -#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) -#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) - - /* Do not use Barrier, Write Gather, - * or Prefetch unless asked. - * Leave everything else as it - * was from the last time. - */ - new = new - & ~BRIDGE_DEV_BARRIER - & ~BRIDGE_DEV_WRGA_BITS - & ~BRIDGE_DEV_PREF - ; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { - new = (new - & ~BRIDGE_DEV_BARRIER) /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ - - } - if (flags & PCIIO_DMA_CMD) { - new = ((new - & ~BRIDGE_DEV_PREF) /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ - } - /* Generic detail flags - */ - if (flags & PCIIO_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIIO_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIIO_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIBR_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_BYTE_STREAM) - new |= (pcibr_soft->bs_xbridge) ? - BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; - if (flags & PCIIO_WORD_VALUES) - new &= (pcibr_soft->bs_xbridge) ? - ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; - - /* Provider-specific flags - */ - if (flags & PCIBR_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - new |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - new &= ~BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - new |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - new &= ~BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - new |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - new &= ~BRIDGE_DEV_DEV_SIZE; - - chg = old ^ new; /* what are we changing, */ - chg &= xmask; /* of the interesting bits */ - - if (chg) { - - badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; - if (pcibr_soft->bs_xbridge) { - badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; - } else { - badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; - } - bad = badpmu | badd32 | badd64; - - if (bad) { - - /* some conflicts can be resolved by - * forcing the bit on. this may cause - * some performance degredation in - * the stream(s) that want the bit off, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) ){ - bad &= ~fix; - /* don't change these bits if - * they are already set in "old" - */ - chg &= ~(fix & old); - } - /* some conflicts can be resolved by - * forcing the bit off. this may cause - * some performance degredation in - * the stream(s) that want the bit on, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ) { - bad &= ~fix; - /* don't change these bits if - * we wanted to turn them on. - */ - chg &= ~(fix & new); - } - /* conflicts in other bits mean - * we can not establish this DMA - * channel while the other(s) are - * still present. - */ - if (bad) { - pcibr_unlock(pcibr_soft, s); -#if (DEBUG && PCIBR_DEV_DEBUG) - printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits); -#endif - return bad; - } - } - } - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr++; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr++; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr++; - - /* the value we want to write is the - * original value, with the bits for - * our selected changes flipped, and - * with any disabled features turned off. - */ - new = old ^ chg; /* only change what we want to change */ - - if (slotp->bss_device == new) { - pcibr_unlock(pcibr_soft, s); - return 0; - } - bridge->b_device[slot].reg = new; - slotp->bss_device = new; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg); -#endif - - return 0; -} - -void -pcibr_release_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - bridgereg_t mask) -{ - pcibr_soft_slot_t slotp; - unsigned long s; - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr--; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr--; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr--; - - pcibr_unlock(pcibr_soft, s); -} - -/* - * flush write gather buffer for slot - */ -LOCAL void -pcibr_device_write_gather_flush(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - bridge_t *bridge; - unsigned long s; - volatile uint32_t wrf; - s = pcibr_lock(pcibr_soft); - bridge = pcibr_soft->bs_base; - wrf = bridge->b_wr_req_buf[slot].reg; - pcibr_unlock(pcibr_soft, s); -} - -/* ===================================================================== - * Bridge (pcibr) "Device Driver" entry points - */ - -/* - * pcibr_probe_slot: read a config space word - * while trapping any errors; reutrn zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -LOCAL int -pcibr_probe_slot(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) -{ - int rv; - bridgereg_t old_enable, new_enable; - int badaddr_val(volatile void *, int, volatile void *); - - - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - - bridge->b_int_enable = new_enable; - - /* - * The xbridge doesn't clear b_err_int_view unless - * multi-err is cleared... - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) cfg, 4, valp); - - /* - * The xbridge doesn't set master timeout in b_int_status - * here. Fortunately it's in error_interrupt_view. - */ - if (is_xbridge(bridge)) - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ - } - - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - return rv; -} - -/* - * pcibr_init: called once during system startup or - * when a loadable driver is loaded. - * - * The driver_register function should normally - * be in _reg, not _init. But the pcibr driver is - * required by devinit before the _reg routines - * are called, so this is an exception. - */ -void -pcibr_init(void) -{ -#if DEBUG && ATTACH_DEBUG - printk("pcibr_init\n"); -#endif - - xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, - XBRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); - xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, - BRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); -} - -/* - * open/close mmap/munmap interface would be used by processes - * that plan to map the PCI bridge, and muck around with the - * registers. This is dangerous to do, and will be allowed - * to a select brand of programs. Typically these are - * diagnostics programs, or some user level commands we may - * write to do some weird things. - * To start with expect them to have root priveleges. - * We will ask for more later. - */ -/* ARGSUSED */ -int -pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - int error; - devfs_handle_t vhdl = dev_to_vhdl(dev); - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - ASSERT(pcibr_soft); - len = ctob(btoc(len)); /* Make len page aligned */ - error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); - - /* - * If the offset being mapped corresponds to the flash prom - * base, and if the mapping succeeds, and if the user - * has requested the protections to be WRITE, enable the - * flash prom to be written. - * - * XXX- deprecate this in favor of using the - * real flash driver ... - */ - if (!error && - ((off == BRIDGE_EXTERNAL_FLASH) || - (len > BRIDGE_EXTERNAL_FLASH))) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return error; -} - -/*ARGSUSED */ -int -pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - return 0; -} - -/* This is special case code used by grio. There are plans to make - * this a bit more general in the future, but till then this should - * be sufficient. - */ -pciio_slot_t -pcibr_device_slot_get(devfs_handle_t dev_vhdl) -{ - char devname[MAXDEVNAME]; - devfs_handle_t tdev; - pciio_info_t pciio_info; - pciio_slot_t slot = PCIIO_SLOT_NONE; - - vertex_to_name(dev_vhdl, devname, MAXDEVNAME); - - /* run back along the canonical path - * until we find a PCI connection point. - */ - tdev = hwgraph_connectpt_get(dev_vhdl); - while (tdev != GRAPH_VERTEX_NONE) { - pciio_info = pciio_info_chk(tdev); - if (pciio_info) { - slot = pciio_info_slot_get(pciio_info); - break; - } - hwgraph_vertex_unref(tdev); - tdev = hwgraph_connectpt_get(tdev); - } - hwgraph_vertex_unref(tdev); - - return slot; -} - -/*========================================================================== - * BRIDGE PCI SLOT RELATED IOCTLs - */ -char *pci_space_name[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - - -/*ARGSUSED */ -int -pcibr_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev); -#ifdef LATER - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); -#endif - int error = 0; - - hwgraph_vertex_unref(pcibr_vhdl); - - switch (cmd) { -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able((uint64_t)CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH); - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - pciio_slot_t slot = 0; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printk("pcibr:: prev_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - if ((slot = pcibr_device_slot_get(info.prev_vhdl)) == - PCIIO_SLOT_NONE) { - error = EIO; - break; - } - if (info.reqbw) - pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW); - break; - } - - case PCIBR_SLOT_POWERUP: - { - pciio_slot_t slot; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_SHUTDOWN: - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - slot = (pciio_slot_t)(uint64_t)arg; - error = pcibr_slot_powerup(pcibr_vhdl,slot); - break; - } - case PCIBR_SLOT_QUERY: - { - struct pcibr_slot_info_req_s req; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &req, sizeof(req))) { - error = EFAULT; - break; - } - - error = pcibr_slot_query(pcibr_vhdl, &req); - break; - } -#endif /* LATER */ - default: - break; - - } - - return error; -} - -void -pcibr_freeblock_sub(iopaddr_t *free_basep, - iopaddr_t *free_lastp, - iopaddr_t base, - size_t size) -{ - iopaddr_t free_base = *free_basep; - iopaddr_t free_last = *free_lastp; - iopaddr_t last = base + size - 1; - - if ((last < free_base) || (base > free_last)); /* free block outside arena */ - - else if ((base <= free_base) && (last >= free_last)) - /* free block contains entire arena */ - *free_basep = *free_lastp = 0; - - else if (base <= free_base) - /* free block is head of arena */ - *free_basep = last + 1; - - else if (last >= free_last) - /* free block is tail of arena */ - *free_lastp = base - 1; - - /* - * We are left with two regions: the free area - * in the arena "below" the block, and the free - * area in the arena "above" the block. Keep - * the one that is bigger. - */ - - else if ((base - free_base) > (free_last - last)) - *free_lastp = base - 1; /* keep lower chunk */ - else - *free_basep = last + 1; /* keep upper chunk */ -} - -/* Convert from ssram_bits in control register to number of SSRAM entries */ -#define ATE_NUM_ENTRIES(n) _ate_info[n] - -/* Possible choices for number of ATE entries in Bridge's SSRAM */ -LOCAL int _ate_info[] = -{ - 0, /* 0 entries */ - 8 * 1024, /* 8K entries */ - 16 * 1024, /* 16K entries */ - 64 * 1024 /* 64K entries */ -}; - -#define ATE_NUM_SIZES (sizeof(_ate_info) / sizeof(int)) -#define ATE_PROBE_VALUE 0x0123456789abcdefULL - -/* - * Determine the size of this bridge's external mapping SSRAM, and set - * the control register appropriately to reflect this size, and initialize - * the external SSRAM. - */ -LOCAL int -pcibr_init_ext_ate_ram(bridge_t *bridge) -{ - int largest_working_size = 0; - int num_entries, entry; - int i, j; - bridgereg_t old_enable, new_enable; - int s; - - /* Probe SSRAM to determine its size. */ - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - - for (i = 1; i < ATE_NUM_SIZES; i++) { - /* Try writing a value */ - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - - /* Guard against wrap */ - for (j = 1; j < i; j++) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; - - /* See if value was written */ - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - - s = splhi(); - bridge->b_wid_control = (bridge->b_wid_control - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - - num_entries = ATE_NUM_ENTRIES(largest_working_size); - -#if PCIBR_ATE_DEBUG - if (num_entries) - printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries); - else - printk("bridge at 0x%x: no externa9422l ATE RAM found\n", bridge); -#endif - - /* Initialize external mapping entries */ - for (entry = 0; entry < num_entries; entry++) - bridge->b_ext_ate_ram[entry] = 0; - - return (num_entries); -} - -/* - * Allocate "count" contiguous Bridge Address Translation Entries - * on the specified bridge to be used for PCI to XTALK mappings. - * Indices in rm map range from 1..num_entries. Indicies returned - * to caller range from 0..num_entries-1. - * - * Return the start index on success, -1 on failure. - */ -LOCAL int -pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count) -{ - int index = 0; - - index = (int) rmalloc(pcibr_soft->bs_int_ate_map, (size_t) count); -/* printk("Colin: pcibr_ate_alloc - index %d count %d \n", index, count); */ - - if (!index && pcibr_soft->bs_ext_ate_map) - index = (int) rmalloc(pcibr_soft->bs_ext_ate_map, (size_t) count); - - /* rmalloc manages resources in the 1..n - * range, with 0 being failure. - * pcibr_ate_alloc manages resources - * in the 0..n-1 range, with -1 being failure. - */ - return index - 1; -} - -LOCAL void -pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count) -/* Who says there's no such thing as a free meal? :-) */ -{ - /* note the "+1" since rmalloc handles 1..n but - * we start counting ATEs at zero. - */ -/* printk("Colin: pcibr_ate_free - index %d count %d\n", index, count); */ - - rmfree((index < pcibr_soft->bs_int_ate_size) - ? pcibr_soft->bs_int_ate_map - : pcibr_soft->bs_ext_ate_map, - count, index + 1); -} - -LOCAL pcibr_info_t -pcibr_info_get(devfs_handle_t vhdl) -{ - return (pcibr_info_t) pciio_info_get(vhdl); -} - -pcibr_info_t -pcibr_device_info_new( - pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pciio_function_t rfunc, - pciio_vendor_id_t vendor, - pciio_device_id_t device) -{ - pcibr_info_t pcibr_info; - pciio_function_t func; - int ibit; - - func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; - - NEW(pcibr_info); - pciio_device_info_new(&pcibr_info->f_c, - pcibr_soft->bs_vhdl, - slot, rfunc, - vendor, device); - - if (slot != PCIIO_SLOT_NONE) { - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - * - * XXX- allow pcibr_hints to override default - * XXX- allow ADMIN to override pcibr_hints - */ - for (ibit = 0; ibit < 4; ++ibit) - pcibr_info->f_ibit[ibit] = - (slot + 4 * ibit) & 7; - - /* - * Record the info in the sparse func info space. - */ - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) - pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; - } - return pcibr_info; -} - -void -pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info_t pcibr_info; - pciio_function_t func; - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; - int nfunc = slotp->bss_ninfo; - - - for (func = 0; func < nfunc; func++) { - pcibr_info = slotp->bss_infos[func]; - - if (!pcibr_info) - continue; - - slotp->bss_infos[func] = 0; - pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); - pciio_device_info_free(&pcibr_info->f_c); - DEL(pcibr_info); - } - - /* Clear the DEVIO(x) for this slot */ - slotp->bss_devio.bssd_space = PCIIO_SPACE_NONE; - slotp->bss_devio.bssd_base = PCIBR_D32_BASE_UNSET; - slotp->bss_device = 0; - - - /* Reset the mapping usage counters */ - slotp->bss_pmu_uctr = 0; - slotp->bss_d32_uctr = 0; - slotp->bss_d64_uctr = 0; - - /* Clear the Direct translation info */ - slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; - slotp->bss_d64_flags = 0; - slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; - slotp->bss_d32_flags = 0; - - /* Clear out shadow info necessary for the external SSRAM workaround */ - slotp->bss_ext_ates_active = ATOMIC_INIT(0); - slotp->bss_cmd_pointer = 0; - slotp->bss_cmd_shadow = 0; - -} - -/* - * PCI_ADDR_SPACE_LIMITS_LOAD - * Gets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_LOAD() \ - pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base; \ - pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last; \ - pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base; \ - pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last; \ - pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base; \ - pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last; -/* - * PCI_ADDR_SPACE_LIMITS_STORE - * Sets the current values of - * pci io base, - * pci io last, - * pci low memory base, - * pci low memory last, - * pci high memory base, - * pci high memory last - */ -#define PCI_ADDR_SPACE_LIMITS_STORE() \ - pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb; \ - pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl; \ - pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb; \ - pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl; \ - pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb; \ - pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl; - -#define PCI_ADDR_SPACE_LIMITS_PRINT() \ - printf("+++++++++++++++++++++++\n" \ - "IO base 0x%x last 0x%x\n" \ - "SWIN base 0x%x last 0x%x\n" \ - "MEM base 0x%x last 0x%x\n" \ - "+++++++++++++++++++++++\n", \ - pcibr_soft->bs_spinfo.pci_io_base, \ - pcibr_soft->bs_spinfo.pci_io_last, \ - pcibr_soft->bs_spinfo.pci_swin_base, \ - pcibr_soft->bs_spinfo.pci_swin_last, \ - pcibr_soft->bs_spinfo.pci_mem_base, \ - pcibr_soft->bs_spinfo.pci_mem_last); - -/* - * pcibr_slot_info_init - * Probe for this slot and see if it is populated. - * If it is populated initialize the generic PCI infrastructural - * information associated with this particular PCI device. - */ -int -pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - cfg_p cfgw; - unsigned idword; - unsigned pfail; - unsigned idwords[8]; - pciio_vendor_id_t vendor; - pciio_device_id_t device; - unsigned htype; - cfg_p wptr; - int win; - pciio_space_t space; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - int nfunc; - pciio_function_t rfunc; - int func; - devfs_handle_t conn_vhdl; - pcibr_soft_slot_t slotp; - - /* Get the basic software information required to proceed */ - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - if (!PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization - * is done by the host slot then we are done. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - /* Check for a slot with any system critical functions */ - if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - /* Load the current values of allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - /* Try to read the device-id/vendor-id from the config space */ - cfgw = bridge->b_type0_cfg_dev[slot].l; - - if (pcibr_probe_slot(bridge, cfgw, &idword)) - return(ENODEV); - - slotp = &pcibr_soft->bs_slot[slot]; - slotp->slot_status |= SLOT_POWER_UP; - - vendor = 0xFFFF & idword; - /* If the vendor id is not valid then the slot is not populated - * and we are done. - */ - if (vendor == 0xFFFF) - return(ENODEV); - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - - nfunc = 1; - rfunc = PCIIO_FUNC_NONE; - pfail = 0; - - /* NOTE: if a card claims to be multifunction - * but only responds to config space 0, treat - * it as a unifunction card. - */ - - if (htype & 0x80) { /* MULTIFUNCTION */ - for (func = 1; func < 8; ++func) { - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) { - pfail |= 1 << func; - continue; - } - vendor = 0xFFFF & idwords[func]; - if (vendor == 0xFFFF) { - pfail |= 1 << func; - continue; - } - nfunc = func + 1; - rfunc = 0; - } - cfgw = bridge->b_type0_cfg_dev[slot].l; - } - NEWA(pcibr_infoh, nfunc); - - pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - for (func = 0; func < nfunc; ++func) { - unsigned cmd_reg; - - if (func) { - if (pfail & (1 << func)) - continue; - - idword = idwords[func]; - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - rfunc = func; - } - htype &= 0x7f; - if (htype != 0x00) { - printk(KERN_WARNING "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", - pcibr_soft->bs_name, slot, func, htype); - continue; - } -#if DEBUG && ATTACH_DEBUG - printk(KERN_NOTICE - "%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x", - pcibr_soft->bs_name, slot, func, vendor, device); -#endif - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, rfunc, vendor, device); - conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); - if (func == 0) - slotp->slot_conn = conn_vhdl; - -#ifdef LITTLE_ENDIAN - cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4]; -#else - cmd_reg = cfgw[PCI_CFG_COMMAND / 4]; -#endif - - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) { - iopaddr_t base, mask, code; - size_t size; - - /* - * GET THE BASE & SIZE OF THIS WINDOW: - * - * The low two or four bits of the BASE register - * determines which address space we are in; the - * rest is a base address. BASE registers - * determine windows that are power-of-two sized - * and naturally aligned, so we can get the size - * of a window by writing all-ones to the - * register, reading it back, and seeing which - * bits are used for decode; the least - * significant nonzero bit is also the size of - * the window. - * - * WARNING: someone may already have allocated - * some PCI space to this window, and in fact - * PIO may be in process at this very moment - * from another processor (or even from this - * one, if we get interrupted)! So, if the BASE - * already has a nonzero address, be generous - * and use the LSBit of that address as the - * size; this could overstate the window size. - * Usually, when one card is set up, all are set - * up; so, since we don't bitch about - * overlapping windows, we are ok. - * - * UNFORTUNATELY, some cards do not clear their - * BASE registers on reset. I have two heuristics - * that can detect such cards: first, if the - * decode enable is turned off for the space - * that the window uses, we can disregard the - * initial value. second, if the address is - * outside the range that we use, we can disregard - * it as well. - * - * This is looking very PCI generic. Except for - * knowing how many slots and where their config - * spaces are, this window loop and the next one - * could probably be shared with other PCI host - * adapters. It would be interesting to see if - * this could be pushed up into pciio, when we - * start supporting more PCI providers. - */ -#ifdef LITTLE_ENDIAN - base = wptr[((win*4)^4)/4]; -#else - base = wptr[win]; -#endif - - if (base & PCI_BA_IO_SPACE) { - /* BASE is in I/O space. */ - space = PCIIO_SPACE_IO; - mask = -4; - code = base & 3; - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { - base = 0; /* decode not enabled */ - } - } else { - /* BASE is in MEM space. */ - space = PCIIO_SPACE_MEM; - mask = -16; - code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { - base = 0; /* decode not enabled */ - } else if (base & 0xC0000000) { - base = 0; /* outside permissable range */ - } else if ((code == PCI_BA_MEM_64BIT) && -#ifdef LITTLE_ENDIAN - (wptr[(((win + 1)*4)^4)/4] != 0)) { -#else - (wptr[win + 1] != 0)) { -#endif /* LITTLE_ENDIAN */ - base = 0; /* outside permissable range */ - } - } - - if (base != 0) { /* estimate size */ - size = base & -base; - } else { /* calculate size */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = ~0; /* turn on all bits */ - size = wptr[((win*4)^4)/4]; /* get stored bits */ -#else - wptr[win] = ~0; /* turn on all bits */ - size = wptr[win]; /* get stored bits */ -#endif /* LITTLE_ENDIAN */ - size &= mask; /* keep addr */ - size &= -size; /* keep lsbit */ - if (size == 0) - continue; - } - - pcibr_info->f_window[win].w_space = space; - pcibr_info->f_window[win].w_base = base; - pcibr_info->f_window[win].w_size = size; - - /* - * If this window already has PCI space - * allocated for it, "subtract" that space from - * our running freeblocks. Don't worry about - * overlaps in existing allocated windows; we - * may be overstating their sizes anyway. - */ - - if (base && size) { - if (space == PCIIO_SPACE_IO) { - pcibr_freeblock_sub(&pci_io_fb, - &pci_io_fl, - base, size); - } else { - pcibr_freeblock_sub(&pci_lo_fb, - &pci_lo_fl, - base, size); - pcibr_freeblock_sub(&pci_hi_fb, - &pci_hi_fl, - base, size); - } - } -#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) - /* - * IOC3 BASE_ADDR* BUG WORKAROUND - * - - * If we write to BASE1 on the IOC3, the - * data in BASE0 is replaced. The - * original workaround was to remember - * the value of BASE0 and restore it - * when we ran off the end of the BASE - * registers; however, a later - * workaround was added (I think it was - * rev 1.44) to avoid setting up - * anything but BASE0, with the comment - * that writing all ones to BASE1 set - * the enable-parity-error test feature - * in IOC3's SCR bit 14. - * - * So, unless we defer doing any PCI - * space allocation until drivers - * attach, and set up a way for drivers - * (the IOC3 in paricular) to tell us - * generically to keep our hands off - * BASE registers, we gotta "know" about - * the IOC3 here. - * - * Too bad the PCI folks didn't reserve the - * all-zero value for 'no BASE here' (it is a - * valid code for an uninitialized BASE in - * 32-bit PCI memory space). - */ - - if ((vendor == IOC3_VENDOR_ID_NUM) && - (device == IOC3_DEVICE_ID_NUM)) - break; -#endif - if (code == PCI_BA_MEM_64BIT) { - win++; /* skip upper half */ -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = 0; /* which must be zero */ -#else - wptr[win] = 0; /* which must be zero */ -#endif /* LITTLE_ENDIAN */ - } - } /* next win */ - } /* next func */ - - /* Store back the values for allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_info_free - * Remove all the PCI infrastructural information associated - * with a particular PCI device. - */ -int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - int nfunc; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - - pcibr_device_info_free(pcibr_vhdl, slot); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - DELA(pcibr_infoh,nfunc); - pcibr_soft->bs_slot[slot].bss_ninfo = 0; - - return(0); -} - -int as_debug = 0; -/* - * pcibr_slot_addr_space_init - * Reserve chunks of PCI address space as required by - * the base registers in the card. - */ -int -pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - size_t align; - iopaddr_t mask; - int nbars; - int nfunc; - int func; - int win; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* Get the current values for the allocated PCI address spaces */ - PCI_ADDR_SPACE_LIMITS_LOAD(); - - if (as_debug) -#ifdef LATER - PCI_ADDR_SPACE_LIMITS_PRINT(); -#endif - /* allocate address space, - * for windows that have not been - * previously assigned. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return(0); - } - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - if (nfunc < 1) - return(EINVAL); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - if (!pcibr_infoh) - return(EINVAL); - - /* - * Try to make the DevIO windows not - * overlap by pushing the "io" and "hi" - * allocation areas up to the next one - * or two megabyte bound. This also - * keeps them from being zero. - * - * DO NOT do this with "pci_lo" since - * the entire "lo" area is only a - * megabyte, total ... - */ - align = (slot < 2) ? 0x200000 : 0x100000; - mask = -align; - pci_io_fb = (pci_io_fb + align - 1) & mask; - pci_hi_fb = (pci_hi_fb + align - 1) & mask; - - for (func = 0; func < nfunc; ++func) { - cfg_p cfgw; - cfg_p wptr; - pciio_space_t space; - iopaddr_t base; - size_t size; - cfg_p pci_cfg_cmd_reg_p; - unsigned pci_cfg_cmd_reg; - unsigned pci_cfg_cmd_reg_add = 0; - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - cfgw = bridge->b_type0_cfg_dev[slot].f[func].l; - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - nbars = PCI_CFG_BASE_ADDRS; - - for (win = 0; win < nbars; ++win) { - - space = pcibr_info->f_window[win].w_space; - base = pcibr_info->f_window[win].w_base; - size = pcibr_info->f_window[win].w_size; - - if (size < 1) - continue; - - if (base >= size) { -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n", - slot, func, win, space, base, base + size - 1); -#endif - continue; /* already allocated */ - } - align = size; /* ie. 0x00001000 */ - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ - mask = -align; /* ie. 0xFFFFC000 */ - - switch (space) { - case PCIIO_SPACE_IO: - base = (pci_io_fb + align - 1) & mask; - if ((base + size) > pci_io_fl) { - base = 0; - break; - } - pci_io_fb = base + size; - break; - - case PCIIO_SPACE_MEM: -#ifdef LITTLE_ENDIAN - if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) == -#else - if ((wptr[win] & PCI_BA_MEM_LOCATION) == -#endif /* LITTLE_ENDIAN */ - PCI_BA_MEM_1MEG) { - /* allocate from 20-bit PCI space */ - base = (pci_lo_fb + align - 1) & mask; - if ((base + size) > pci_lo_fl) { - base = 0; - break; - } - pci_lo_fb = base + size; - } else { - /* allocate from 32-bit or 64-bit PCI space */ - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) { - base = 0; - break; - } - pci_hi_fb = base + size; - } - break; - - default: - base = 0; -#if DEBUG && PCI_DEBUG - printk("pcibr: slot %d window %d had bad space code %d\n", - slot, win, space); -#endif - } - pcibr_info->f_window[win].w_base = base; -#ifdef LITTLE_ENDIAN - wptr[((win*4)^4)/4] = base; -#if DEBUG && PCI_DEBUG - printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base); -#endif -#else - wptr[win] = base; -#endif /* LITTLE_ENDIAN */ - -#if DEBUG && PCI_DEBUG - if (base >= size) - printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n", - slot, func, win, space, base, base + size - 1); - else - printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n", - slot, func, win, size, space); -#endif - } /* next base */ - - /* - * Allocate space for the EXPANSION ROM - * NOTE: DO NOT DO THIS ON AN IOC3, - * as it blows the system away. - */ - base = size = 0; - if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || - (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { - - wptr = cfgw + PCI_EXPANSION_ROM / 4; -#ifdef LITTLE_ENDIAN - wptr[1] = 0xFFFFF000; - mask = wptr[1]; -#else - *wptr = 0xFFFFF000; - mask = *wptr; -#endif /* LITTLE_ENDIAN */ - if (mask & 0xFFFFF000) { - size = mask & -mask; - align = size; - if (align < _PAGESZ) - align = _PAGESZ; - mask = -align; - base = (pci_hi_fb + align - 1) & mask; - if ((base + size) > pci_hi_fl) - base = size = 0; - else { - pci_hi_fb = base + size; -#ifdef LITTLE_ENDIAN - wptr[1] = base; -#else - *wptr = base; -#endif /* LITTLE_ENDIAN */ -#if DEBUG && PCI_DEBUG - printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n", - pcibr_soft->bs_name, slot, - base, base + size - 1); -#endif - } - } - } - pcibr_info->f_rbase = base; - pcibr_info->f_rsize = size; - - /* - * if necessary, update the board's - * command register to enable decoding - * in the windows we added. - * - * There are some bits we always want to - * be sure are set. - */ - pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - - /* - * The Adaptec 1160 FC Controller WAR #767995: - * The part incorrectly ignores the upper 32 bits of a 64 bit - * address when decoding references to its registers so to - * keep it from responding to a bus cycle that it shouldn't - * we only use I/O space to get at it's registers. Don't - * enable memory space accesses on that PCI device. - */ - #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ - #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ - - if ((pcibr_info->f_vendor != FCADP_VENDID) || - (pcibr_info->f_device != FCADP_DEVID)) - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; - - pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - - pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4; - pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p; -#if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ - if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) - fast_back_to_back_enable = 0; -#endif - pci_cfg_cmd_reg &= 0xFFFF; - if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add; - - } /* next func */ - - /* Now that we have allocated new chunks of PCI address spaces to this - * card we need to update the bookkeeping values which indicate - * the current PCI address space allocations. - */ - PCI_ADDR_SPACE_LIMITS_STORE(); - return(0); -} - -/* - * pcibr_slot_device_init - * Setup the device register in the bridge for this PCI slot. - */ -int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - bridgereg_t devreg; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* - * Adjustments to Device(x) - * and init of bss_device shadow - */ - devreg = bridge->b_device[slot].reg; - devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; - devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN; -#ifdef LITTLE_ENDIAN - devreg |= BRIDGE_DEV_DEV_SWAP; -#endif - pcibr_soft->bs_slot[slot].bss_device = devreg; - bridge->b_device[slot].reg = devreg; - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg); -#endif - -#if DEBUG && PCI_DEBUG - printk("pcibr: PCI space allocation done.\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_guest_info_init - * Setup the host/guest relations for a PCI slot. - */ -int -pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - pcibr_soft_slot_t slotp; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - slotp = &pcibr_soft->bs_slot[slot]; - - /* create info and verticies for guest slots; - * for compatibilitiy macros, create info - * for even unpopulated slots (but do not - * build verticies for them). - */ - if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { - NEWA(pcibr_infoh, 1); - pcibr_soft->bs_slot[slot].bss_ninfo = 1; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - - if (pcibr_soft->bs_slot[slot].has_host) { - slotp->slot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - } - } - - /* generate host/guest relations - */ - if (pcibr_soft->bs_slot[slot].has_host) { - int host = pcibr_soft->bs_slot[slot].host_slot; - pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; - - hwgraph_edge_add(slotp->slot_conn, - host_slotp->slot_conn, - EDGE_LBL_HOST); - - /* XXX- only gives us one guest edge per - * host. If/when we have a host with more than - * one guest, we will need to figure out how - * the host finds all its guests, and sorts - * out which one is which. - */ - hwgraph_edge_add(host_slotp->slot_conn, - slotp->slot_conn, - EDGE_LBL_GUEST); - } - - return(0); -} - -/* - * pcibr_slot_initial_rrb_alloc - * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation - * strategy routine defined per platform. - */ - -int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - bridge_t *bridge; - int c0, c1; - int r; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - bridge = pcibr_soft->bs_base; - - /* How may RRBs are on this slot? - */ - c0 = do_pcibr_rrb_count_valid(bridge, slot); - c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL); - -#if PCIBR_RRB_DEBUG - printk("pcibr_attach: slot %d started with %d+%d\n", slot, c0, c1); -#endif - - /* Do we really need any? - */ - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - pcibr_info = pcibr_infoh[0]; - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - if (c0 > 0) - do_pcibr_rrb_free(bridge, slot, c0); - if (c1 > 0) - do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); - pcibr_soft->bs_rrb_valid[slot] = 0x1000; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; - return(ENODEV); - } - - pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; - pcibr_soft->bs_rrb_valid[slot] = c0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; - - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); - - r = 3 - (c0 + c1); - - if (r > 0) { - pcibr_soft->bs_rrb_res[slot] = r; - pcibr_soft->bs_rrb_avail[slot & 1] -= r; - } - -#if PCIBR_RRB_DEBUG - printk("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - printk("\n"); -#endif - - return(0); -} - -/* - * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - async_attach_t aa = NULL; - int func; - devfs_handle_t xconn_vhdl,conn_vhdl; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - - if (pcibr_soft->bs_slot[slot].has_host) { - return(EPERM); - } - - xconn_vhdl = pcibr_soft->bs_conn; - aa = async_attach_get_info(xconn_vhdl); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - -#ifdef LATER - /* - * Activate if and when we support cdl. - */ - if (aa) - async_attach_add_info(conn_vhdl, aa); -#endif /* LATER */ - - error_func = pciio_device_attach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; - } else { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int func; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(EINVAL); - - if (pcibr_soft->bs_slot[slot].has_host) - return(EPERM); - - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - - error_func = pciio_device_detach(conn_vhdl, drv_flags); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - - if (error) { - if ((error != ENODEV) && (error != EUNATCH)) - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; - } else { - if (conn_vhdl != GRAPH_VERTEX_NONE) - pcibr_device_unregister(conn_vhdl); - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; - } - - return(error); -} - -/* - * pcibr_slot_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. - */ -int -pcibr_slot_detach(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - int error; - - /* Call the device detach function */ - error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); - return (error); - -} - -/* - * pcibr_is_slot_sys_critical - * Check slot for any functions that are system critical. - * Return 1 if any are system critical or 0 otherwise. - * - * This function will always return 0 when called by - * pcibr_attach() because the system critical vertices - * have not yet been set in the hwgraph. - */ -int -pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int func; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) - return(0); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - if (is_sys_critical_vertex(conn_vhdl)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); -#else - printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); -#endif - return(1); - } - - } - - return(0); -} - -/* - * pcibr_device_unregister - * This frees up any hardware resources reserved for this PCI device - * and removes any PCI infrastructural information setup for it. - * This is usually used at the time of shutting down of the PCI card. - */ -int -pcibr_device_unregister(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - int error_call; - int error = 0; - - pciio_info = pciio_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = pciio_info_slot_get(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Clear all the hardware xtalk resources for this device */ - xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); - - /* Flush all the rrbs */ - pcibr_rrb_flush(pconn_vhdl); - - /* Free the rrbs allocated to this slot */ - error_call = do_pcibr_rrb_free(bridge, slot, - pcibr_soft->bs_rrb_valid[slot] + - pcibr_soft->bs_rrb_valid[slot + - PCIBR_RRB_SLOT_VIRTUAL]); - - if (error_call) - error = ERANGE; - - pcibr_soft->bs_rrb_valid[slot] = 0; - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0; - pcibr_soft->bs_rrb_res[slot] = 0; - - /* Flush the write buffers !! */ - error_call = pcibr_wrb_flush(pconn_vhdl); - - if (error_call) - error = error_call; - - /* Clear the information specific to the slot */ - error_call = pcibr_slot_info_free(pcibr_vhdl, slot); - - if (error_call) - error = error_call; - - return(error); - -} - -/* - * build a convenience link path in the - * form of "...//bus/" - * - * returns 1 on success, 0 otherwise - * - * depends on hwgraph separator == '/' - */ -int -pcibr_bus_cnvlink(devfs_handle_t f_c, int slot) -{ - char dst[MAXDEVNAME]; - char *dp = dst; - char *cp, *xp; - int widgetnum; - char pcibus[8]; - devfs_handle_t nvtx, svtx; - int rv; - -#if DEBUG - printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", - slot, f_c); - { - int pos; - char dname[256]; - pos = devfs_generate_path(f_c, dname, 256); - printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); - } -#endif - - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME)) - return 0; - - /* dst example == /hw/module/001c02/Pbrick/xtalk/8/pci/direct */ - - /* find the widget number */ - xp = strstr(dst, "/"EDGE_LBL_XTALK"/"); - if (xp == NULL) - return 0; - widgetnum = atoi(xp+7); - if (widgetnum < XBOW_PORT_8 || widgetnum > XBOW_PORT_F) - return 0; - - /* remove "/pci/direct" from path */ - cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct"); - if (cp == NULL) - return 0; - *cp = (char)NULL; - - /* get the vertex for the widget */ - if (GRAPH_SUCCESS != hwgraph_traverse(NULL, dp, &svtx)) - return 0; - - *xp = (char)NULL; /* remove "/xtalk/..." from path */ - - /* dst example now == /hw/module/001c02/Pbrick */ - - /* get the bus number */ - strcat(dst, "/bus"); - sprintf(pcibus, "%d", p_busnum[widgetnum]); - - /* link to bus to widget */ - rv = hwgraph_path_add(NULL, dp, &nvtx); - if (GRAPH_SUCCESS == rv) - rv = hwgraph_edge_add(nvtx, svtx, pcibus); - - return (rv == GRAPH_SUCCESS); -} - - -/* - * pcibr_attach: called every time the crosstalk - * infrastructure is asked to initialize a widget - * that matches the part number we handed to the - * registration routine above. - */ -/*ARGSUSED */ -int -pcibr_attach(devfs_handle_t xconn_vhdl) -{ - /* REFERENCED */ - graph_error_t rc; - devfs_handle_t pcibr_vhdl; - devfs_handle_t ctlr_vhdl; - bridge_t *bridge = NULL; - bridgereg_t id; - int rev; - pcibr_soft_t pcibr_soft; - pcibr_info_t pcibr_info; - xwidget_info_t info; - xtalk_intr_t xtalk_intr; - device_desc_t dev_desc = (device_desc_t)0; - int slot; - int ibit; - devfs_handle_t noslot_conn; - char devnm[MAXDEVNAME], *s; - pcibr_hints_t pcibr_hints; - bridgereg_t b_int_enable; - unsigned rrb_fixed = 0; - - iopaddr_t pci_io_fb, pci_io_fl; - iopaddr_t pci_lo_fb, pci_lo_fl; - iopaddr_t pci_hi_fb, pci_hi_fl; - - int spl_level; -#ifdef LATER - char *nicinfo = (char *)0; -#endif - -#if PCI_FBBE - int fast_back_to_back_enable; -#endif - l1sc_t *scp; - nasid_t nasid; - - async_attach_t aa = NULL; - - aa = async_attach_get_info(xconn_vhdl); - -#if DEBUG && ATTACH_DEBUG - printk("pcibr_attach: xconn_vhdl= %p\n", xconn_vhdl); - { - int pos; - char dname[256]; - pos = devfs_generate_path(xconn_vhdl, dname, 256); - printk("%s : path= %s \n", __FUNCTION__, &dname[pos]); - } -#endif - - /* Setup the PRB for the bridge in CONVEYOR BELT - * mode. PRBs are setup in default FIRE-AND-FORGET - * mode during the initialization. - */ - hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR); - - bridge = (bridge_t *) - xtalk_piotrans_addr(xconn_vhdl, NULL, - 0, sizeof(bridge_t), 0); - -#ifndef MEDUSA_HACK - if ((bridge->b_wid_stat & BRIDGE_STAT_PCI_GIO_N) == 0) - return -1; /* someone else handles GIO bridges. */ -#endif - - if (XWIDGET_PART_REV_NUM(bridge->b_wid_id) == XBRIDGE_PART_REV_A) - NeedXbridgeSwap = 1; - - /* - * Create the vertex for the PCI bus, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl); - ASSERT(rc == GRAPH_SUCCESS); - - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - - ASSERT(ctlr_vhdl != NULL); - - /* - * decode the nic, and hang its stuff off our - * connection point where other drivers can get - * at it. - */ -#ifdef LATER - nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic); -#endif - - /* - * Get the hint structure; if some NIC callback - * marked this vertex as "hands-off" then we - * just return here, before doing anything else. - */ - pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); - - if (pcibr_hints && pcibr_hints->ph_hands_off) - return -1; /* generic operations disabled */ - - id = bridge->b_wid_id; - rev = XWIDGET_PART_REV_NUM(id); - - hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, (arbitrary_info_t) rev); - - /* - * allocate soft state structure, fill in some - * fields, and hook it up to our vertex. - */ - NEW(pcibr_soft); - BZERO(pcibr_soft, sizeof *pcibr_soft); - pcibr_soft_set(pcibr_vhdl, pcibr_soft); - - pcibr_soft->bs_conn = xconn_vhdl; - pcibr_soft->bs_vhdl = pcibr_vhdl; - pcibr_soft->bs_base = bridge; - pcibr_soft->bs_rev_num = rev; - pcibr_soft->bs_intr_bits = pcibr_intr_bits; - if (is_xbridge(bridge)) { - pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 1; - } else { - pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; - pcibr_soft->bs_xbridge = 0; - } - - nasid = NASID_GET(bridge); - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - pcibr_soft->bs_l1sc = scp; - pcibr_soft->bs_moduleid = iobrick_module_get(scp); - pcibr_soft->bsi_err_intr = 0; - - /* Bridges up through REV C - * are unable to set the direct - * byteswappers to BYTE_STREAM. - */ - if (pcibr_soft->bs_rev_num <= BRIDGE_PART_REV_C) { - pcibr_soft->bs_pio_end_io = PCIIO_WORD_VALUES; - pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES; - } -#if PCIBR_SOFT_LIST - { - pcibr_list_p self; - - NEW(self); - self->bl_soft = pcibr_soft; - self->bl_vhdl = pcibr_vhdl; - self->bl_next = pcibr_list; - pcibr_list = self; - } -#endif - - /* - * get the name of this bridge vertex and keep the info. Use this - * only where it is really needed now: like error interrupts. - */ - s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); - pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(pcibr_soft->bs_name, s); - -#if SHOW_REVS || DEBUG -#if !DEBUG - if (kdebug) -#endif - printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n", - is_xbridge(bridge) ? "X" : "", - (rev == BRIDGE_PART_REV_A) ? "A" : - (rev == BRIDGE_PART_REV_B) ? "B" : - (rev == BRIDGE_PART_REV_C) ? "C" : - (rev == BRIDGE_PART_REV_D) ? "D" : - (rev == XBRIDGE_PART_REV_A) ? "A" : - (rev == XBRIDGE_PART_REV_B) ? "B" : - "unknown", - rev, pcibr_soft->bs_name); -#endif - - info = xwidget_info_get(xconn_vhdl); - pcibr_soft->bs_xid = xwidget_info_id_get(info); - pcibr_soft->bs_master = xwidget_info_master_get(info); - pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); - - /* - * Init bridge lock. - */ - spin_lock_init(&pcibr_soft->bs_lock); - - /* - * If we have one, process the hints structure. - */ - if (pcibr_hints) { - rrb_fixed = pcibr_hints->ph_rrb_fixed; - - pcibr_soft->bs_rrb_fixed = rrb_fixed; - - if (pcibr_hints->ph_intr_bits) - pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; - - for (slot = 0; slot < 8; ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; - - if (hslot < 0) { - pcibr_soft->bs_slot[slot].host_slot = slot; - } else { - pcibr_soft->bs_slot[slot].has_host = 1; - pcibr_soft->bs_slot[slot].host_slot = hslot; - } - } - } - /* - * set up initial values for state fields - */ - for (slot = 0; slot < 8; ++slot) { - pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0); - } - - for (ibit = 0; ibit < 8; ++ibit) { - pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = - &(bridge->b_int_status); - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; - } - - /* - * Initialize various Bridge registers. - */ - - /* - * On pre-Rev.D bridges, set the PCI_RETRY_CNT - * to zero to avoid dropping stores. (#475347) - */ - if (rev < BRIDGE_PART_REV_D) - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_MASK; - - /* - * Clear all pending interrupts. - */ - bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR); - - /* - * Until otherwise set up, - * assume all interrupts are - * from slot 7. - */ - bridge->b_int_device = (uint32_t) 0xffffffff; - - { - bridgereg_t dirmap; - paddr_t paddr; - iopaddr_t xbase; - xwidgetnum_t xport; - iopaddr_t offset; - int num_entries = 0; - int entry; - cnodeid_t cnodeid; - nasid_t nasid; - - /* Set the Bridge's 32-bit PCI to XTalk - * Direct Map register to the most useful - * value we can determine. Note that we - * must use a single xid for all of: - * direct-mapped 32-bit DMA accesses - * direct-mapped 64-bit DMA accesses - * DMA accesses through the PMU - * interrupts - * This is the only way to guarantee that - * completion interrupts will reach a CPU - * after all DMA data has reached memory. - * (Of course, there may be a few special - * drivers/controlers that explicitly manage - * this ordering problem.) - */ - - cnodeid = 0; /* default node id */ - /* - * Determine the base address node id to be used for all 32-bit - * Direct Mapping I/O. The default is node 0, but this can be changed - * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE - * attribute in the irix.sm config file. A device driver can obtain - * this node value via a call to pcibr_get_dmatrans_node(). - */ - nasid = COMPACT_TO_NASID_NODEID(cnodeid); - paddr = NODE_OFFSET(nasid) + 0; - - /* currently, we just assume that if we ask - * for a DMA mapping to "zero" the XIO - * host will transmute this into a request - * for the lowest hunk of memory. - */ - xbase = xtalk_dmatrans_addr(xconn_vhdl, 0, - paddr, _PAGESZ, 0); - - if (xbase != XIO_NOWHERE) { - if (XIO_PACKED(xbase)) { - xport = XIO_PORT(xbase); - xbase = XIO_ADDR(xbase); - } else - xport = pcibr_soft->bs_mxid; - - offset = xbase & ((1ull << BRIDGE_DIRMAP_OFF_ADDRSHFT) - 1ull); - xbase >>= BRIDGE_DIRMAP_OFF_ADDRSHFT; - - dirmap = xport << BRIDGE_DIRMAP_W_ID_SHFT; - - if (xbase) - dirmap |= BRIDGE_DIRMAP_OFF & xbase; - else if (offset >= (512 << 20)) - dirmap |= BRIDGE_DIRMAP_ADD512; - - bridge->b_dir_map = dirmap; - } - /* - * Set bridge's idea of page size according to the system's - * idea of "IO page size". TBD: The idea of IO page size - * should really go away. - */ - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - spl_level = splhi(); -#if IOPGSIZE == 4096 - bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE; -#elif IOPGSIZE == 16384 - bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE; -#else - <<>>; -#endif - bridge->b_wid_control; /* inval addr bug war */ - splx(spl_level); - - /* Initialize internal mapping entries */ - for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) - bridge->b_int_ate_ram[entry].wr = 0; - - /* - * Determine if there's external mapping SSRAM on this - * bridge. Set up Bridge control register appropriately, - * inititlize SSRAM, and set software up to manage RAM - * entries as an allocatable resource. - * - * Currently, we just use the rm* routines to manage ATE - * allocation. We should probably replace this with a - * Best Fit allocator. - * - * For now, if we have external SSRAM, avoid using - * the internal ssram: we can't turn PREFETCH on - * when we use the internal SSRAM; and besides, - * this also guarantees that no allocation will - * straddle the internal/external line, so we - * can increment ATE write addresses rather than - * recomparing against BRIDGE_INTERNAL_ATES every - * time. - */ - if (is_xbridge(bridge)) - num_entries = 0; - else - num_entries = pcibr_init_ext_ate_ram(bridge); - - /* we always have 128 ATEs (512 for Xbridge) inside the chip - * even if disabled for debugging. - */ - pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size); - pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size); -#endif - - if (num_entries > pcibr_soft->bs_int_ate_size) { -#if PCIBR_ATE_NOTBOTH /* for debug -- forces us to use external ates */ - printk("pcibr_attach: disabling internal ATEs.\n"); - pcibr_ate_alloc(pcibr_soft, pcibr_soft->bs_int_ate_size); -#endif - pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries); - pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size, - num_entries - pcibr_soft->bs_int_ate_size); -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: %d EXTERNAL ATEs\n", - num_entries - pcibr_soft->bs_int_ate_size); -#endif - } - } - - { - bridgereg_t dirmap; - iopaddr_t xbase; - - /* - * now figure the *real* xtalk base address - * that dirmap sends us to. - */ - dirmap = bridge->b_dir_map; - if (dirmap & BRIDGE_DIRMAP_OFF) - xbase = (iopaddr_t)(dirmap & BRIDGE_DIRMAP_OFF) - << BRIDGE_DIRMAP_OFF_ADDRSHFT; - else if (dirmap & BRIDGE_DIRMAP_ADD512) - xbase = 512 << 20; - else - xbase = 0; - - pcibr_soft->bs_dir_xbase = xbase; - - /* it is entirely possible that we may, at this - * point, have our dirmap pointing somewhere - * other than our "master" port. - */ - pcibr_soft->bs_dir_xport = - (dirmap & BRIDGE_DIRMAP_W_ID) >> BRIDGE_DIRMAP_W_ID_SHFT; - } - - /* pcibr sources an error interrupt; - * figure out where to send it. - * - * If any interrupts are enabled in bridge, - * then the prom set us up and our interrupt - * has already been reconnected in mlreset - * above. - * - * Need to set the D_INTR_ISERR flag - * in the dev_desc used for allocating the - * error interrupt, so our interrupt will - * be properly routed and prioritized. - * - * If our crosstalk provider wants to - * fix widget error interrupts to specific - * destinations, D_INTR_ISERR is how it - * knows to do this. - */ - - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl); - ASSERT(xtalk_intr != NULL); - - pcibr_soft->bsi_err_intr = xtalk_intr; - - /* - * On IP35 with XBridge, we do some extra checks in pcibr_setwidint - * in order to work around some addressing limitations. In order - * for that fire wall to work properly, we need to make sure we - * start from a known clean state. - */ - pcibr_clearwidint(bridge); - - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); - - /* - * now we can start handling error interrupts; - * enable all of them. - * NOTE: some PCI ints may already be enabled. - */ - b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS; - - - bridge->b_int_enable = b_int_enable; - bridge->b_int_mode = 0; /* do not send "clear interrupt" packets */ - - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - /* - * Depending on the rev of bridge, disable certain features. - * Easiest way seems to be to force the PCIBR_NOwhatever - * flag to be on for all DMA calls, which overrides any - * PCIBR_whatever flag or even the setting of whatever - * from the PCIIO_DMA_class flags (or even from the other - * PCIBR flags, since NO overrides YES). - */ - pcibr_soft->bs_dma_flags = 0; - - /* PREFETCH: - * Always completely disabled for REV.A; - * at "pcibr_prefetch_enable_rev", anyone - * asking for PCIIO_PREFETCH gets it. - * Between these two points, you have to ask - * for PCIBR_PREFETCH, which promises that - * your driver knows about known Bridge WARs. - */ - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) - pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; - else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - - /* WRITE_GATHER: - * Disabled up to but not including the - * rev number in pcibr_wg_enable_rev. There - * is no "WAR range" as with prefetch. - */ - if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) - pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; - - pciio_provider_register(pcibr_vhdl, &pcibr_provider); - pciio_provider_startup(pcibr_vhdl); - - pci_io_fb = 0x00000004; /* I/O FreeBlock Base */ - pci_io_fl = 0xFFFFFFFF; /* I/O FreeBlock Last */ - - pci_lo_fb = 0x00000010; /* Low Memory FreeBlock Base */ - pci_lo_fl = 0x001FFFFF; /* Low Memory FreeBlock Last */ - - pci_hi_fb = 0x00200000; /* High Memory FreeBlock Base */ - pci_hi_fl = 0x3FFFFFFF; /* High Memory FreeBlock Last */ - - - PCI_ADDR_SPACE_LIMITS_STORE(); - - /* build "no-slot" connection point - */ - pcibr_info = pcibr_device_info_new - (pcibr_soft, PCIIO_SLOT_NONE, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - noslot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - - /* Remember the no slot connection point info for tearing it - * down during detach. - */ - pcibr_soft->bs_noslot_conn = noslot_conn; - pcibr_soft->bs_noslot_info = pcibr_info; -#if PCI_FBBE - fast_back_to_back_enable = 1; -#endif - -#if PCI_FBBE - if (fast_back_to_back_enable) { - /* - * All devices on the bus are capable of fast back to back, so - * we need to set the fast back to back bit in all devices on - * the bus that are capable of doing such accesses. - */ - } -#endif - -#ifdef LATER - /* If the bridge has been reset then there is no need to reset - * the individual PCI slots. - */ - for (slot = 0; slot < 8; ++slot) - /* Reset all the slots */ - (void)pcibr_slot_reset(pcibr_vhdl, slot); -#endif - - for (slot = 0; slot < 8; ++slot) - /* Find out what is out there */ - (void)pcibr_slot_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Set up the address space for this slot in the pci land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - -#ifndef __ia64 - for (slot = 0; slot < 8; ++slot) - /* Set up convenience links */ - if (is_xbridge(bridge)) - if (pcibr_soft->bs_slot[slot].bss_ninfo > 0) /* if occupied */ - pcibr_bus_cnvlink(pcibr_info->f_vertex, slot); -#endif - - for (slot = 0; slot < 8; ++slot) - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl,slot); - - for (slot = 0; slot < 8; ++slot) - /* Initial RRB management */ - (void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot); - - /* driver attach routines should be called out from generic linux code */ - for (slot = 0; slot < 8; ++slot) - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); - - /* - * Each Pbrick PCI bus only has slots 1 and 2. Similarly for - * widget 0xe on Ibricks. Allocate RRB's accordingly. - */ - if (pcibr_soft->bs_moduleid > 0) { - switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) { - case 'p': /* Pbrick */ - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - break; - case 'i': /* Ibrick */ - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1); - } - break; - } /* switch */ - } - -#ifdef LATER - if (strstr(nicinfo, XTALK_PCI_PART_NUM)) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8); -#if PCIBR_RRB_DEBUG - printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl); - - printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n", - pcibr_vhdl, - pcibr_soft->bs_rrb_avail[0], - pcibr_soft->bs_rrb_avail[1]); - - for (slot = 0; slot < 8; ++slot) - printf("\t%d+%d+%d", - 0xFFF & pcibr_soft->bs_rrb_valid[slot], - 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - - printf("\n"); -#endif - } -#else - FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif - - if (aa) - async_attach_add_info(noslot_conn, aa); - - pciio_device_attach(noslot_conn, 0); - - - /* - * Tear down pointer to async attach info -- async threads for - * bridge's descendants may be running but the bridge's work is done. - */ - if (aa) - async_attach_del_info(xconn_vhdl); - - return 0; -} -/* - * pcibr_detach: - * Detach the bridge device from the hwgraph after cleaning out all the - * underlying vertices. - */ -int -pcibr_detach(devfs_handle_t xconn) -{ - pciio_slot_t slot; - devfs_handle_t pcibr_vhdl; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - - /* Get the bridge vertex from its xtalk connection point */ - if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) - return(1); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - - /* Disable the interrupts from the bridge */ - bridge->b_int_enable = 0; - - /* Detach all the PCI devices talking to this bridge */ - for(slot = 0; slot < 8; slot++) { -#ifdef DEBUG - printk("pcibr_device_detach called for %p/%d\n", - pcibr_vhdl,slot); -#endif - pcibr_slot_detach(pcibr_vhdl, slot, 0); - } - - /* Unregister the no-slot connection point */ - pciio_device_info_unregister(pcibr_vhdl, - &(pcibr_soft->bs_noslot_info->f_c)); - - spin_lock_destroy(&pcibr_soft->bs_lock); - kfree(pcibr_soft->bs_name); - - /* Error handler gets unregistered when the widget info is - * cleaned - */ - /* Free the soft ATE maps */ - if (pcibr_soft->bs_int_ate_map) - rmfreemap(pcibr_soft->bs_int_ate_map); - if (pcibr_soft->bs_ext_ate_map) - rmfreemap(pcibr_soft->bs_ext_ate_map); - - /* Disconnect the error interrupt and free the xtalk resources - * associated with it. - */ - xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); - xtalk_intr_free(pcibr_soft->bsi_err_intr); - - /* Clear the software state maintained by the bridge driver for this - * bridge. - */ - DEL(pcibr_soft); - /* Remove the Bridge revision labelled info */ - (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); - /* Remove the character device associated with this bridge */ - (void)hwgraph_edge_remove(pcibr_vhdl, EDGE_LBL_CONTROLLER, NULL); - /* Remove the PCI bridge vertex */ - (void)hwgraph_edge_remove(xconn, EDGE_LBL_PCI, NULL); - - return(0); -} - -int -pcibr_asic_rev(devfs_handle_t pconn_vhdl) -{ - devfs_handle_t pcibr_vhdl; - arbitrary_info_t ainfo; - - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) - return -1; - - if (GRAPH_SUCCESS != - hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo)) - return -1; - - return (int) ainfo; -} - -int -pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - pciio_slot_t slot; - slot = pciio_info_slot_get(pciio_info); - pcibr_device_write_gather_flush(pcibr_soft, slot); - return 0; -} - -/* ===================================================================== - * PIO MANAGEMENT - */ - -LOCAL iopaddr_t -pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, - pciio_slot_t slot, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - - unsigned bar; /* which BASE reg on device is decoding */ - iopaddr_t xio_addr = XIO_NOWHERE; - - pciio_space_t wspace; /* which space device is decoding */ - iopaddr_t wbase; /* base of device decode on PCI */ - size_t wsize; /* size of device decode on PCI */ - - int try; /* DevIO(x) window scanning order control */ - int win; /* which DevIO(x) window is being used */ - pciio_space_t mspace; /* target space for devio(x) register */ - iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ - size_t msize; /* size of devio(x) mapped area on PCI */ - size_t mmask; /* addr bits stored in Device(x) */ - - unsigned long s; - - s = pcibr_lock(pcibr_soft); - - if (pcibr_soft->bs_slot[slot].has_host) { - slot = pcibr_soft->bs_slot[slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; - } - if (space == PCIIO_SPACE_NONE) - goto done; - - if (space == PCIIO_SPACE_CFG) { - /* - * Usually, the first mapping - * established to a PCI device - * is to its config space. - * - * In any case, we definitely - * do NOT need to worry about - * PCI BASE registers, and - * MUST NOT attempt to point - * the DevIO(x) window at - * this access ... - */ - if (((flags & PCIIO_BYTE_STREAM) == 0) && - ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) - xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot); - - goto done; - } - if (space == PCIIO_SPACE_ROM) { - /* PIO to the Expansion Rom. - * Driver is responsible for - * enabling and disabling - * decodes properly. - */ - wbase = pcibr_info->f_rbase; - wsize = pcibr_info->f_rsize; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - pci_addr += wbase; - space = PCIIO_SPACE_MEM; - } - /* - * reduce window mappings to raw - * space mappings (maybe allocating - * windows), and try for DevIO(x) - * usage (setting it if it is available). - */ - bar = space - PCIIO_SPACE_WIN0; - if (bar < 6) { - wspace = pcibr_info->f_window[bar].w_space; - if (wspace == PCIIO_SPACE_NONE) - goto done; - - /* get PCI base and size */ - wbase = pcibr_info->f_window[bar].w_base; - wsize = pcibr_info->f_window[bar].w_size; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - /* shift from window relative to - * decoded space relative. - */ - pci_addr += wbase; - space = wspace; - } else - bar = -1; - - /* Scan all the DevIO(x) windows twice looking for one - * that can satisfy our request. The first time through, - * only look at assigned windows; the second time, also - * look at PCIIO_SPACE_NONE windows. Arrange the order - * so we always look at our own window first. - * - * We will not attempt to satisfy a single request - * by concatinating multiple windows. - */ - for (try = 0; try < 16; ++try) { - bridgereg_t devreg; - unsigned offset; - - win = (try + slot) % 8; - - /* If this DevIO(x) mapping area can provide - * a mapping to this address, use it. - */ - msize = (win < 2) ? 0x200000 : 0x100000; - mmask = -msize; - if (space != PCIIO_SPACE_IO) - mmask &= 0x3FFFFFFF; - - offset = pci_addr & (msize - 1); - - /* If this window can't possibly handle that request, - * go on to the next window. - */ - if (((pci_addr & (msize - 1)) + req_size) > msize) - continue; - - devreg = pcibr_soft->bs_slot[win].bss_device; - - /* Is this window "nailed down"? - * If not, maybe we can use it. - * (only check this the second time through) - */ - mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; - if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) { - - /* If this is the primary DevIO(x) window - * for some other device, skip it. - */ - if ((win != slot) && - (PCIIO_VENDOR_ID_NONE != - pcibr_soft->bs_slot[win].bss_vendor_id)) - continue; - - /* It's a free window, and we fit in it. - * Set up Device(win) to our taste. - */ - mbase = pci_addr & mmask; - - /* check that we would really get from - * here to there. - */ - if ((mbase | offset) != pci_addr) - continue; - - devreg &= ~BRIDGE_DEV_OFF_MASK; - if (space != PCIIO_SPACE_IO) - devreg |= BRIDGE_DEV_DEV_IO_MEM; - else - devreg &= ~BRIDGE_DEV_DEV_IO_MEM; - devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; - - /* default is WORD_VALUES. - * if you specify both, - * operation is undefined. - */ - if (flags & PCIIO_BYTE_STREAM) - devreg |= BRIDGE_DEV_DEV_SWAP; - else - devreg &= ~BRIDGE_DEV_DEV_SWAP; - - if (pcibr_soft->bs_slot[win].bss_device != devreg) { - bridge->b_device[win].reg = devreg; - pcibr_soft->bs_slot[win].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - -#if DEBUG && PCI_DEBUG - printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg); -#endif - } - pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; - pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", - __FUNCTION__, __LINE__, space, space_desc, - pci_addr, pci_addr + req_size - 1, - slot, win, devreg); -#endif - - goto done; - } /* endif DevIO(x) not pointed */ - mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; - - /* Now check for request incompat with DevIO(x) - */ - if ((mspace != space) || - (pci_addr < mbase) || - ((pci_addr + req_size) > (mbase + msize)) || - ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || - (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) - continue; - - /* DevIO(x) window is pointed at PCI space - * that includes our target. Calculate the - * final XIO address, release the lock and - * return. - */ - xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase); - -#if DEBUG && PCI_DEBUG - printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n", - __FUNCTION__, __LINE__, space, pci_addr, pci_addr + req_size - 1, slot, win); -#endif - goto done; - } - - switch (space) { - /* - * Accesses to device decode - * areas that do a not fit - * within the DevIO(x) space are - * modified to be accesses via - * the direct mapping areas. - * - * If necessary, drivers can - * explicitly ask for mappings - * into these address spaces, - * but this should never be needed. - */ - case PCIIO_SPACE_MEM: /* "mem space" */ - case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; - break; - - case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; - break; - - case PCIIO_SPACE_IO: /* "i/o space" */ - /* Bridge Hardware Bug WAR #482741: - * The 4G area that maps directly from - * XIO space to PCI I/O space is busted - * until Bridge Rev D. - */ - if ((pcibr_soft->bs_rev_num > BRIDGE_PART_REV_C) && - ((pci_addr + BRIDGE_PCI_IO_BASE + req_size - 1) <= - BRIDGE_PCI_IO_LIMIT)) - xio_addr = pci_addr + BRIDGE_PCI_IO_BASE; - break; - } - - /* Check that "Direct PIO" byteswapping matches, - * try to change it if it does not. - */ - if (xio_addr != XIO_NOWHERE) { - unsigned bst; /* nonzero to set bytestream */ - unsigned *bfp; /* addr of record of how swapper is set */ - unsigned swb; /* which control bit to mung */ - unsigned bfo; /* current swapper setting */ - unsigned bfn; /* desired swapper setting */ - - bfp = ((space == PCIIO_SPACE_IO) - ? (&pcibr_soft->bs_pio_end_io) - : (&pcibr_soft->bs_pio_end_mem)); - - bfo = *bfp; - - bst = flags & PCIIO_BYTE_STREAM; - - bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; - - if (bfn == bfo) { /* we already match. */ - ; - } else if (bfo != 0) { /* we have a conflict. */ -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n", - space, - bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - xio_addr = XIO_NOWHERE; - } else { /* OK to make the change. */ - bridgereg_t octl, nctl; - - swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP; - octl = bridge->b_wid_control; - nctl = bst ? octl | swb : octl & ~swb; - - if (octl != nctl) /* make the change if any */ - bridge->b_wid_control = nctl; - - *bfp = bfn; /* record the assignment */ - -#if DEBUG && PCI_DEBUG - printk("pcibr_addr_pci_to_xio: swap for space %d set to%s%s\n", - space, - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : ""); -#endif - } - } - done: - pcibr_unlock(pcibr_soft, s); - return xio_addr; -} - -/*ARGSUSED6 */ -pcibr_piomap_t -pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - size_t req_size_max, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - pcibr_piomap_t *mapptr; - pcibr_piomap_t maplist; - pcibr_piomap_t pcibr_piomap; - iopaddr_t xio_addr; - xtalk_piomap_t xtalk_piomap; - unsigned long s; - - /* Make sure that the req sizes are non-zero */ - if ((req_size < 1) || (req_size_max < 1)) - return NULL; - - /* - * Code to translate slot/space/addr - * into xio_addr is common between - * this routine and pcibr_piotrans_addr. - */ - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - /* Check the piomap list to see if there is already an allocated - * piomap entry but not in use. If so use that one. Otherwise - * allocate a new piomap entry and add it to the piomap list - */ - mapptr = &(pcibr_info->f_piomap); - - s = pcibr_lock(pcibr_soft); - for (pcibr_piomap = *mapptr; - pcibr_piomap != NULL; - pcibr_piomap = pcibr_piomap->bp_next) { - if (pcibr_piomap->bp_mapsz == 0) - break; - } - - if (pcibr_piomap) - mapptr = NULL; - else { - pcibr_unlock(pcibr_soft, s); - NEW(pcibr_piomap); - } - - pcibr_piomap->bp_dev = pconn_vhdl; - pcibr_piomap->bp_slot = pciio_slot; - pcibr_piomap->bp_flags = flags; - pcibr_piomap->bp_space = space; - pcibr_piomap->bp_pciaddr = pci_addr; - pcibr_piomap->bp_mapsz = req_size; - pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc[0] = ATOMIC_INIT(0); - - if (mapptr) { - s = pcibr_lock(pcibr_soft); - maplist = *mapptr; - pcibr_piomap->bp_next = maplist; - *mapptr = pcibr_piomap; - } - pcibr_unlock(pcibr_soft, s); - - - if (pcibr_piomap) { - xtalk_piomap = - xtalk_piomap_alloc(xconn_vhdl, 0, - xio_addr, - req_size, req_size_max, - flags & PIOMAP_FLAGS); - if (xtalk_piomap) { - pcibr_piomap->bp_xtalk_addr = xio_addr; - pcibr_piomap->bp_xtalk_pio = xtalk_piomap; - } else { - pcibr_piomap->bp_mapsz = 0; - pcibr_piomap = 0; - } - } - return pcibr_piomap; -} - -/*ARGSUSED */ -void -pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); - pcibr_piomap->bp_xtalk_pio = 0; - pcibr_piomap->bp_mapsz = 0; -} - -/*ARGSUSED */ -caddr_t -pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, - iopaddr_t pci_addr, - size_t req_size) -{ - return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, - pcibr_piomap->bp_xtalk_addr + - pci_addr - pcibr_piomap->bp_pciaddr, - req_size); -} - -/*ARGSUSED */ -void -pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) -{ - xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); -} - -/*ARGSUSED */ -caddr_t -pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - iopaddr_t xio_addr; - - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) - return NULL; - - return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); -} - -/* - * PIO Space allocation and management. - * Allocate and Manage the PCI PIO space (mem and io space) - * This routine is pretty simplistic at this time, and - * does pretty trivial management of allocation and freeing.. - * The current scheme is prone for fragmentation.. - * Change the scheme to use bitmaps. - */ - -/*ARGSUSED */ -iopaddr_t -pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - size_t req_size, - size_t alignment) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - pciio_piospace_t piosp; - unsigned long s; - - iopaddr_t *pciaddr, *pcilast; - iopaddr_t start_addr; - size_t align_mask; - - /* - * Check for proper alignment - */ - ASSERT(alignment >= NBPP); - ASSERT((alignment & (alignment - 1)) == 0); - - align_mask = alignment - 1; - s = pcibr_lock(pcibr_soft); - - /* - * First look if a previously allocated chunk exists. - */ - if ((piosp = pcibr_info->f_piospace)) { - /* - * Look through the list for a right sized free chunk. - */ - do { - if (piosp->free && - (piosp->space == space) && - (piosp->count >= req_size) && - !(piosp->start & align_mask)) { - piosp->free = 0; - pcibr_unlock(pcibr_soft, s); - return piosp->start; - } - piosp = piosp->next; - } while (piosp); - } - ASSERT(!piosp); - - switch (space) { - case PCIIO_SPACE_IO: - pciaddr = &pcibr_soft->bs_spinfo.pci_io_base; - pcilast = &pcibr_soft->bs_spinfo.pci_io_last; - break; - case PCIIO_SPACE_MEM: - case PCIIO_SPACE_MEM32: - pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base; - pcilast = &pcibr_soft->bs_spinfo.pci_mem_last; - break; - default: - ASSERT(0); - pcibr_unlock(pcibr_soft, s); - return 0; - } - - start_addr = *pciaddr; - - /* - * Align start_addr. - */ - if (start_addr & align_mask) - start_addr = (start_addr + align_mask) & ~align_mask; - - if ((start_addr + req_size) > *pcilast) { - /* - * If too big a request, reject it. - */ - pcibr_unlock(pcibr_soft, s); - return 0; - } - *pciaddr = (start_addr + req_size); - - NEW(piosp); - piosp->free = 0; - piosp->space = space; - piosp->start = start_addr; - piosp->count = req_size; - piosp->next = pcibr_info->f_piospace; - pcibr_info->f_piospace = piosp; - - pcibr_unlock(pcibr_soft, s); - return start_addr; -} - -/*ARGSUSED */ -void -pcibr_piospace_free(devfs_handle_t pconn_vhdl, - pciio_space_t space, - iopaddr_t pciaddr, - size_t req_size) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - pciio_piospace_t piosp; - unsigned long s; - char name[1024]; - - /* - * Look through the bridge data structures for the pciio_piospace_t - * structure corresponding to 'pciaddr' - */ - s = pcibr_lock(pcibr_soft); - piosp = pcibr_info->f_piospace; - while (piosp) { - /* - * Piospace free can only be for the complete - * chunk and not parts of it.. - */ - if (piosp->start == pciaddr) { - if (piosp->count == req_size) - break; - /* - * Improper size passed for freeing.. - * Print a message and break; - */ - hwgraph_vertex_name_get(pconn_vhdl, name, 1024); - printk(KERN_WARNING "pcibr_piospace_free: error"); - printk(KERN_WARNING "Device %s freeing size (0x%lx) different than allocated (0x%lx)", - name, req_size, piosp->count); - printk(KERN_WARNING "Freeing 0x%lx instead", piosp->count); - break; - } - piosp = piosp->next; - } - - if (!piosp) { - printk(KERN_WARNING - "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", - pciaddr, req_size); - pcibr_unlock(pcibr_soft, s); - return; - } - piosp->free = 1; - pcibr_unlock(pcibr_soft, s); - return; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * The Bridge ASIC provides three methods of doing - * DMA: via a "direct map" register available in - * 32-bit PCI space (which selects a contiguous 2G - * address space on some other widget), via - * "direct" addressing via 64-bit PCI space (all - * destination information comes from the PCI - * address, including transfer attributes), and via - * a "mapped" region that allows a bunch of - * different small mappings to be established with - * the PMU. - * - * For efficiency, we most prefer to use the 32-bit - * direct mapping facility, since it requires no - * resource allocations. The advantage of using the - * PMU over the 64-bit direct is that single-cycle - * PCI addressing can be used; the advantage of - * using 64-bit direct over PMU addressing is that - * we do not have to allocate entries in the PMU. - */ - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Direct Map attribute bits. - */ -LOCAL iopaddr_t -pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) -{ - iopaddr_t attributes = 0; - - /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef LATER - ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); -#endif - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ - attributes |= PCI64_ATTR_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= PCI64_ATTR_BAR; /* barrier bit on */ - attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - /* the swap bit is in the address attributes for xbridge */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - attributes |= PCI64_ATTR_SWAP; - if (flags & PCIIO_WORD_VALUES) - attributes &= ~PCI64_ATTR_SWAP; - } - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= PCI64_ATTR_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~PCI64_ATTR_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= PCI64_ATTR_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~PCI64_ATTR_PREC; - - if (flags & PCIBR_VCHAN1) - attributes |= PCI64_ATTR_VIRTUAL; - if (flags & PCIBR_VCHAN0) - attributes &= ~PCI64_ATTR_VIRTUAL; - - return (attributes); -} - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Address Translation Entry attribute bits. - */ -LOCAL bridge_ate_t -pcibr_flags_to_ate(unsigned flags) -{ - bridge_ate_t attributes; - - /* default if nothing specified: - * NOBARRIER - * NOPREFETCH - * NOPRECISE - * COHERENT - * Plus the valid bit - */ - attributes = ATE_CO | ATE_V; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~ATE_BAR; /* no barrier */ - attributes |= ATE_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= ATE_BAR; /* barrier bit on */ - attributes &= ~ATE_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~ATE_PREF; - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= ATE_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~ATE_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~ATE_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= ATE_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~ATE_PREC; - - return (attributes); -} - -/*ARGSUSED */ -pcibr_dmamap_t -pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - size_t req_size_max, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t slot; - xwidgetnum_t xio_port; - - xtalk_dmamap_t xtalk_dmamap; - pcibr_dmamap_t pcibr_dmamap; - int ate_count; - int ate_index; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - -#ifdef IRIX - NEWf(pcibr_dmamap, flags); -#else - /* - * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() - * can be called within an interrupt thread. - */ - pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); -#endif - - if (!pcibr_dmamap) - return 0; - - xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, - flags & DMAMAP_FLAGS); - if (!xtalk_dmamap) { -#if PCIBR_ATE_DEBUG - printk("pcibr_attach: xtalk_dmamap_alloc failed\n"); -#endif -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; - } - xio_port = pcibr_soft->bs_mxid; - slot = pciio_info_slot_get(pciio_info); - - pcibr_dmamap->bd_dev = pconn_vhdl; - pcibr_dmamap->bd_slot = slot; - pcibr_dmamap->bd_soft = pcibr_soft; - pcibr_dmamap->bd_xtalk = xtalk_dmamap; - pcibr_dmamap->bd_max_size = req_size_max; - pcibr_dmamap->bd_xio_port = xio_port; - - if (flags & PCIIO_DMA_A64) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { - iopaddr_t pci_addr; - int have_rrbs; - int min_rrbs; - - /* Device is capable of A64 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - */ - - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_pci_addr = pci_addr; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - if (flags & PCIBR_VCHAN1) - slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct64\n"); -#endif - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct64\n"); -#endif - flags &= ~PCIIO_DMA_A64; - } - if (flags & PCIIO_FIXED) { - /* warning: mappings may fail later, - * if direct32 can't get to the address. - */ - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { - /* User desires DIRECT A32 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - * Mapping calls may fail if target - * is outside the direct32 range. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using direct32\n"); -#endif - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; - pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use direct32\n"); -#endif - /* If the user demands FIXED and we can't - * give it to him, fail. - */ - xtalk_dmamap_free(xtalk_dmamap); -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; - } - /* - * Allocate Address Translation Entries from the mapping RAM. - * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, - * the maximum number of ATEs is based on the worst-case - * scenario, where the requested target is in the - * last byte of an ATE; thus, mapping IOPGSIZE+2 - * does end up requiring three ATEs. - */ - if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { - ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ - +req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } else { /* assume requested target is page aligned */ - ate_count = IOPG(req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } - - ate_index = pcibr_ate_alloc(pcibr_soft, ate_count); - - if (ate_index != -1) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { - bridge_ate_t ate_proto; - int have_rrbs; - int min_rrbs; - -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: using PMU\n"); -#endif - - ate_proto = pcibr_flags_to_ate(flags); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_pci_addr = - PCI32_MAPPED_BASE + IOPGSIZE * ate_index; - /* - * for xbridge the byte-swap bit == bit 29 of PCI address - */ - if (pcibr_soft->bs_xbridge) { - if (flags & PCIIO_BYTE_STREAM) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - /* - * If swap was set in bss_device in pcibr_endian_set() - * we need to change the address bit. - */ - if (pcibr_soft->bs_slot[slot].bss_device & - BRIDGE_DEV_SWAP_PMU) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - if (flags & PCIIO_WORD_VALUES) - ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); - } - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); - pcibr_dmamap->bd_ate_index = ate_index; - pcibr_dmamap->bd_ate_count = ate_count; - pcibr_dmamap->bd_ate_proto = ate_proto; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[slot]; - if (have_rrbs < 2) { - if (ate_proto & ATE_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs); - } - } - if (ate_index >= pcibr_soft->bs_int_ate_size && - !pcibr_soft->bs_xbridge) { - bridge_t *bridge = pcibr_soft->bs_base; - volatile unsigned *cmd_regp; - unsigned cmd_reg; - unsigned long s; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM; - - s = pcibr_lock(pcibr_soft); - cmd_regp = &(bridge-> - b_type0_cfg_dev[slot]. - l[PCI_CFG_COMMAND / 4]); - cmd_reg = *cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp; - pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg; - pcibr_unlock(pcibr_soft, s); - } - return pcibr_dmamap; - } -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: unable to use PMU\n"); -#endif - pcibr_ate_free(pcibr_soft, ate_index, ate_count); - } - /* total failure: sorry, you just can't - * get from here to there that way. - */ -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_alloc: complete failure.\n"); -#endif - xtalk_dmamap_free(xtalk_dmamap); -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - pciio_slot_t slot = pcibr_dmamap->bd_slot; - - unsigned flags = pcibr_dmamap->bd_flags; - - /* Make sure that bss_ext_ates_active - * is properly kept up to date. - */ - - if (PCIBR_DMAMAP_BUSY & flags) - if (PCIBR_DMAMAP_SSRAM & flags) - atomic_dec(&(pcibr_soft->bs_slot[slot]. bss_ext_ates_active)); - - xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); - - if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); - } - if (pcibr_dmamap->bd_ate_count) { - pcibr_ate_free(pcibr_dmamap->bd_soft, - pcibr_dmamap->bd_ate_index, - pcibr_dmamap->bd_ate_count); - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS); - } -#ifdef IRIX - DEL(pcibr_dmamap); -#else - free_pciio_dmamap(pcibr_dmamap); -#endif -} - -/* - * Setup an Address Translation Entry as specified. Use either the Bridge - * internal maps or the external map RAM, as appropriate. - */ -LOCAL bridge_ate_p -pcibr_ate_addr(pcibr_soft_t pcibr_soft, - int ate_index) -{ - bridge_t *bridge = pcibr_soft->bs_base; - - return (ate_index < pcibr_soft->bs_int_ate_size) - ? &(bridge->b_int_ate_ram[ate_index].wr) - : &(bridge->b_ext_ate_ram[ate_index]); -} - -/* - * pcibr_addr_xio_to_pci: given a PIO range, hand - * back the corresponding base PCI MEM address; - * this is used to short-circuit DMA requests that - * loop back onto this PCI bus. - */ -LOCAL iopaddr_t -pcibr_addr_xio_to_pci(pcibr_soft_t soft, - iopaddr_t xio_addr, - size_t req_size) -{ - iopaddr_t xio_lim = xio_addr + req_size - 1; - iopaddr_t pci_addr; - pciio_slot_t slot; - - if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && - (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; - return pci_addr; - } - if ((xio_addr >= BRIDGE_PCI_MEM64_BASE) && - (xio_lim <= BRIDGE_PCI_MEM64_LIMIT)) { - pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; - return pci_addr; - } - for (slot = 0; slot < 8; ++slot) - if ((xio_addr >= BRIDGE_DEVIO(slot)) && - (xio_lim < BRIDGE_DEVIO(slot + 1))) { - bridgereg_t dev; - - dev = soft->bs_slot[slot].bss_device; - pci_addr = dev & BRIDGE_DEV_OFF_MASK; - pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; - pci_addr += xio_addr - BRIDGE_DEVIO(slot); - return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; - } - return 0; -} - -/* We are starting to get more complexity - * surrounding writing ATEs, so pull - * the writing code into this new function. - */ - -#if PCIBR_FREEZE_TIME -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs) -#else -#define ATE_FREEZE() s = ate_freeze(pcibr_dmamap, cmd_regs) -#endif - -LOCAL unsigned -ate_freeze(pcibr_dmamap_t pcibr_dmamap, -#if PCIBR_FREEZE_TIME - unsigned *freeze_time_ptr, -#endif - unsigned *cmd_regs) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; -#ifdef LATER - int dma_slot = pcibr_dmamap->bd_slot; -#endif - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - int slot; - - unsigned long s; - unsigned cmd_reg; - volatile unsigned *cmd_lwa; - unsigned cmd_lwd; - - if (!ext_ates) - return 0; - - /* Bridge Hardware Bug WAR #484930: - * Bridge can't handle updating External ATEs - * while DMA is occurring that uses External ATEs, - * even if the particular ATEs involved are disjoint. - */ - - /* need to prevent anyone else from - * unfreezing the grant while we - * are working; also need to prevent - * this thread from being interrupted - * to keep PCI grant freeze time - * at an absolute minimum. - */ - s = pcibr_lock(pcibr_soft); - -#ifdef LATER - /* just in case pcibr_dmamap_done was not called */ - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); - } -#endif /* LATER */ -#if PCIBR_FREEZE_TIME - *freeze_time_ptr = get_timestamp(); -#endif - - cmd_lwa = 0; - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - cmd_reg = pcibr_soft-> - bs_slot[slot]. - bss_cmd_shadow; - if (cmd_reg & PCI_CMD_BUS_MASTER) { - cmd_lwa = pcibr_soft-> - bs_slot[slot]. - bss_cmd_pointer; - cmd_lwd = cmd_reg ^ PCI_CMD_BUS_MASTER; - cmd_lwa[0] = cmd_lwd; - } - cmd_regs[slot] = cmd_reg; - } else - cmd_regs[slot] = 0; - - if (cmd_lwa) { - bridge_t *bridge = pcibr_soft->bs_base; - - /* Read the last master bit that has been cleared. This PIO read - * on the PCI bus is to ensure the completion of any DMAs that - * are due to bus requests issued by PCI devices before the - * clearing of master bits. - */ - cmd_lwa[0]; - - /* Flush all the write buffers in the bridge */ - for (slot = 0; slot < 8; ++slot) - if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) { - /* Flush the write buffer associated with this - * PCI device which might be using dma map RAM. - */ - bridge->b_wr_req_buf[slot].reg; - } - } - return s; -} - -#define ATE_WRITE() ate_write(ate_ptr, ate_count, ate) - -LOCAL void -ate_write(bridge_ate_p ate_ptr, - int ate_count, - bridge_ate_t ate) -{ - while (ate_count-- > 0) { - *ate_ptr++ = ate; - ate += IOPGSIZE; - } -} - - -#if PCIBR_FREEZE_TIME -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, ate, ate_total, freeze_time, cmd_regs, s) -#else -#define ATE_THAW() ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s) -#endif - -LOCAL void -ate_thaw(pcibr_dmamap_t pcibr_dmamap, - int ate_index, -#if PCIBR_FREEZE_TIME - bridge_ate_t ate, - int ate_total, - unsigned freeze_time_start, -#endif - unsigned *cmd_regs, - unsigned s) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - int dma_slot = pcibr_dmamap->bd_slot; - int slot; - bridge_t *bridge = pcibr_soft->bs_base; - int ext_ates = pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM; - - unsigned cmd_reg; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; - static unsigned max_freeze_time = 0; - static unsigned max_ate_total; -#endif - - if (!ext_ates) - return; - - /* restore cmd regs */ - for (slot = 0; slot < 8; ++slot) - if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) - bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg; - - pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY; - atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active)); - -#if PCIBR_FREEZE_TIME - freeze_time = get_timestamp() - freeze_time_start; - - if ((max_freeze_time < freeze_time) || - (max_ate_total < ate_total)) { - if (max_freeze_time < freeze_time) - max_freeze_time = freeze_time; - if (max_ate_total < ate_total) - max_ate_total = ate_total; - pcibr_unlock(pcibr_soft, s); - printk("%s: pci freeze time %d usec for %d ATEs\n" - "\tfirst ate: %R\n", - pcibr_soft->bs_name, - freeze_time * 1000 / 1250, - ate_total, - ate, ate_bits); - } else -#endif - pcibr_unlock(pcibr_soft, s); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, - paddr_t paddr, - size_t req_size) -{ - pcibr_soft_t pcibr_soft; - iopaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - unsigned flags; - - ASSERT(pcibr_dmamap != NULL); - ASSERT(req_size > 0); - ASSERT(req_size <= pcibr_dmamap->bd_max_size); - - pcibr_soft = pcibr_dmamap->bd_soft; - - flags = pcibr_dmamap->bd_flags; - - xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - /* If this DMA is to an address that - * refers back to this Bridge chip, - * reduce it back to the correct - * PCI MEM address. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - } else if (flags & PCIIO_DMA_A64) { - /* A64 DMA: - * always use 64-bit direct mapping, - * which always works. - * Device(x) was set up during - * dmamap allocation. - */ - - /* attributes are already bundled up into bd_pci_addr. - */ - pci_addr = pcibr_dmamap->bd_pci_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) - | xio_addr; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - pci_addr &= ~PCI64_ATTR_PREF; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct64):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else if (flags & PCIIO_FIXED) { - /* A32 direct DMA: - * always use 32-bit direct mapping, - * which may fail. - * Device(x) was set up during - * dmamap allocation. - */ - - if (xio_port != pcibr_soft->bs_dir_xport) - pci_addr = 0; /* wrong DIDN */ - else if (xio_addr < pcibr_dmamap->bd_xio_addr) - pci_addr = 0; /* out of range */ - else if ((xio_addr + req_size) > - (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) - pci_addr = 0; /* out of range */ - else - pci_addr = pcibr_dmamap->bd_pci_addr + - xio_addr - pcibr_dmamap->bd_xio_addr; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmamap_addr (direct32):\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tXIO port 0x%x offset 0x%x\n" - "\treturning PCI 0x%x\n", - paddr, paddr + req_size - 1, - xio_port, xio_addr, pci_addr); -#endif - } else { - bridge_t *bridge = pcibr_soft->bs_base; - iopaddr_t offset = IOPGOFF(xio_addr); - bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; - int ate_count = IOPG(offset + req_size - 1) + 1; - - int ate_index = pcibr_dmamap->bd_ate_index; - unsigned cmd_regs[8]; - unsigned s; - -#if PCIBR_FREEZE_TIME - int ate_total = ate_count; - unsigned freeze_time; -#endif - -#if PCIBR_ATE_DEBUG - bridge_ate_t ate_cmp; - bridge_ate_p ate_cptr; - unsigned ate_lo, ate_hi; - int ate_bad = 0; - int ate_rbc = 0; -#endif - bridge_ate_p ate_ptr = pcibr_dmamap->bd_ate_ptr; - bridge_ate_t ate; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - ate_proto &= ~ATE_PREF; - - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - - pci_addr = pcibr_dmamap->bd_pci_addr + offset; - - /* Fill in our mapping registers - * with the appropriate xtalk data, - * and hand back the PCI address. - */ - - ASSERT(ate_count > 0); - if (ate_count <= pcibr_dmamap->bd_ate_count) { - ATE_FREEZE(); - ATE_WRITE(); - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } else { - /* The number of ATE's required is greater than the number - * allocated for this map. One way this can happen is if - * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP - * flag, and then when that map is used (right now), the - * target address tells us we really did need to roundup. - * The other possibility is that the map is just plain too - * small to handle the requested target area. - */ -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_addr :\n" - "\twanted paddr [0x%x..0x%x]\n" - "\tate_count 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - paddr, paddr + req_size - 1, - ate_count, pcibr_dmamap->bd_ate_count); -#endif - pci_addr = 0; - } - - } - return pci_addr; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, - alenlist_t palenlist, - unsigned flags) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge=NULL; - - unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - int inplace = flags & PCIIO_INPLACE; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist; - size_t length; - iopaddr_t offset; - unsigned direct64; - int ate_index = 0; - int ate_count = 0; - int ate_total = 0; - bridge_ate_p ate_ptr = (bridge_ate_p)0; - bridge_ate_t ate_proto = (bridge_ate_t)0; - bridge_ate_t ate_prev; - bridge_ate_t ate; - alenaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - alenaddr_t new_addr; - - unsigned cmd_regs[8]; - unsigned s = 0; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; -#endif - int ate_freeze_done = 0; /* To pair ATE_THAW - * with an ATE_FREEZE - */ - - pcibr_soft = pcibr_dmamap->bd_soft; - - xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; - if (!direct64) { - bridge = pcibr_soft->bs_base; - ate_ptr = pcibr_dmamap->bd_ate_ptr; - ate_index = pcibr_dmamap->bd_ate_index; - ate_proto = pcibr_dmamap->bd_ate_proto; - ATE_FREEZE(); - ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ - } - pci_addr = pcibr_dmamap->bd_pci_addr; - - ate_prev = 0; /* matches no valid ATEs */ - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &length, al_flags)) { - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - if (xio_port == pcibr_soft->bs_xid) { - new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) - goto fail; - } else if (direct64) { - new_addr = pci_addr | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - new_addr &= ~PCI64_ATTR_PREF; - - } else { - /* calculate the ate value for - * the first address. If it - * matches the previous - * ATE written (ie. we had - * multiple blocks in the - * same IOPG), then back up - * and reuse that ATE. - * - * We are NOT going to - * aggressively try to - * reuse any other ATEs. - */ - offset = IOPGOFF(xio_addr); - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - if (ate == ate_prev) { -#if PCIBR_ATE_DEBUG - printk("pcibr_dmamap_list: ATE share\n"); -#endif - ate_ptr--; - ate_index--; - pci_addr -= IOPGSIZE; - } - new_addr = pci_addr + offset; - - /* Fill in the hardware ATEs - * that contain this block. - */ - ate_count = IOPG(offset + length - 1) + 1; - ate_total += ate_count; - - /* Ensure that this map contains enough ATE's */ - if (ate_total > pcibr_dmamap->bd_ate_count) { -#if PCIBR_ATE_DEBUG - printk(KERN_WARNING "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count); -#endif - goto fail; - } - - ATE_WRITE(); - - ate_index += ate_count; - ate_ptr += ate_count; - - ate_count <<= IOPFNSHIFT; - ate += ate_count; - pci_addr += ate_count; - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) - goto fail; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - - /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the - * changes that ATE_FREEZE has done to implement the external SSRAM - * bug workaround. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - return pciio_alenlist; - - fail: - /* There are various points of failure after doing an ATE_FREEZE - * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. - * The decision to do an ATE_THAW needs to be based on whether a - * an ATE_FREEZE was done before. - */ - if (ate_freeze_done) { - ATE_THAW(); - bridge->b_wid_tflush; - } - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) -{ - /* - * We could go through and invalidate ATEs here; - * for performance reasons, we don't. - * We also don't enforce the strict alternation - * between _addr/_list and _done, but Hub does. - */ - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_BUSY) { - pcibr_dmamap->bd_flags &= ~PCIBR_DMAMAP_BUSY; - - if (pcibr_dmamap->bd_flags & PCIBR_DMAMAP_SSRAM) - atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active)); - } - - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); -} - - -/* - * For each bridge, the DIR_OFF value in the Direct Mapping Register - * determines the PCI to Crosstalk memory mapping to be used for all - * 32-bit Direct Mapping memory accesses. This mapping can be to any - * node in the system. This function will return that compact node id. - */ - -/*ARGSUSED */ -cnodeid_t -pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) -{ - - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - return(NASID_TO_COMPACT_NODEID(NASID_GET(pcibr_soft->bs_dir_xbase))); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - paddr_t paddr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - - xwidgetnum_t xio_port; - iopaddr_t xio_addr; - iopaddr_t pci_addr; - - int have_rrbs; - int min_rrbs; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, - flags & DMAMAP_FLAGS); - - if (!xio_addr) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - return pci_addr; - } - /* If the caller can use A64, try to - * satisfy the request with the 64-bit - * direct map. This can fail if the - * configuration bits in Device(x) - * conflict with our flags. - */ - - if (flags & PCIIO_DMA_A64) { - pci_addr = slotp->bss_d64_base; - if (!(flags & PCIBR_VCHAN1)) - flags |= PCIBR_VCHAN0; - if ((pci_addr != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - -#if DEBUG && PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_addr; - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - if (flags & PCIBR_VCHAN1) - pciio_slot += PCIBR_RRB_SLOT_VIRTUAL; - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tdirect 64bit address is 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ - flags = flags - & ~PCIIO_DMA_A64 - & ~PCIBR_VCHAN0 - ; - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-64\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - /* Try to satisfy the request with the 32-bit direct - * map. This can fail if the configuration bits in - * Device(x) conflict with our flags, or if the - * target address is outside where DIR_OFF points. - */ - { - size_t map_size = 1ULL << 31; - iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = req_size + offset; - - if ((req_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\txio region outside direct32 target\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } else { - pci_addr = slotp->bss_d32_base; - if ((pci_addr != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - - pci_addr |= offset; - -#if DEBUG && PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr: [reuse]\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr); -#endif - return (pci_addr); - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { - - pci_addr = PCI32_DIRECT_BASE; - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_addr; - pci_addr |= offset; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot]; - if (have_rrbs < 2) { - if (slotp->bss_device & BRIDGE_DEV_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs); - } - } -#if PCIBR_DMA_DEBUG -#if HWG_PERF_CHECK - if (xio_addr != 0x20000000) -#endif - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tmapped via direct32 offset 0x%x\n" - "\twill DMA via pci addr 0x%x\n" - "\tnew flags: 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr, offset, pci_addr, (uint64_t) flags); -#endif - return (pci_addr); - } - /* our flags conflict with Device(x). - */ -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tUnable to set Device(x) bits for Direct-32\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - } - } - -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n" - "\tno acceptable PCI address found or constructable\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - - return 0; -} - -/*ARGSUSED */ -alenlist_t -pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - alenlist_t palenlist, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - xwidgetnum_t xio_port; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist = 0; - - int inplace; - unsigned direct64; - unsigned al_flags; - - iopaddr_t xio_base; - alenaddr_t xio_addr; - size_t xio_size; - - size_t map_size; - iopaddr_t pci_base; - alenaddr_t pci_addr; - - unsigned relbits = 0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - inplace = flags & PCIIO_INPLACE; - direct64 = flags & PCIIO_DMA_A64; - al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - - if (direct64) { - map_size = 1ull << 48; - xio_base = 0; - pci_base = slotp->bss_d64_base; - if ((pci_base != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D64_BITS; - pci_base = - pcibr_flags_to_d64(flags, pcibr_soft); - } - } else { - xio_base = pcibr_soft->bs_dir_xbase; - map_size = 1ull << 31; - pci_base = slotp->bss_d32_base; - if ((pci_base != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { - /* DMA configuration conflict */ - goto fail; - } else { - relbits = BRIDGE_DEV_D32_BITS; - pci_base = PCI32_DIRECT_BASE; - } - } - - xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) - goto fail; - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) - goto fail; - } - - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &xio_size, al_flags)) { - - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { -#if PCIBR_DMA_DEBUG - printk("pcibr_dmatrans_addr:\n" - "\tpciio connection point %v\n" - "\txtalk connection point %v\n" - "\twanted paddr [0x%x..0x%x]\n" - "\txtalk_dmatrans_addr returned 0x%x\n", - pconn_vhdl, xconn_vhdl, - paddr, paddr + req_size - 1, - xio_addr); -#endif - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if ( (pci_addr == (alenaddr_t)NULL) ) - goto fail; - } else if (direct64) { - ASSERT(xio_port != 0); - pci_addr = pci_base | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - } else { - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = xio_size + offset; - - if ((xio_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) - goto fail; - - pci_addr = pci_base + (xio_addr - xio_base); - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) - goto fail; - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) - goto fail; - } - } - - if (relbits) { - if (direct64) { - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_base; - } else { - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_base; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - return pciio_alenlist; - - fail: - if (relbits) - pcibr_release_device(pcibr_soft, pciio_slot, relbits); - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -void -pcibr_dmamap_drain(pcibr_dmamap_t map) -{ - xtalk_dmamap_drain(map->bd_xtalk); -} - -void -pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, - paddr_t paddr, - size_t bytes) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); -} - -void -pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, - alenlist_t list) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmalist_drain(xconn_vhdl, list); -} - -/* - * Get the starting PCIbus address out of the given DMA map. - * This function is supposed to be used by a close friend of PCI bridge - * since it relies on the fact that the starting address of the map is fixed at - * the allocation time in the current implementation of PCI bridge. - */ -iopaddr_t -pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) -{ - return (pcibr_dmamap->bd_pci_addr); -} - -/* - * There are end cases where a deadlock can occur if interrupt - * processing completes and the Bridge b_int_status bit is still set. - * - * One scenerio is if a second PCI interrupt occurs within 60ns of - * the previous interrupt being cleared. In this case the Bridge - * does not detect the transition, the Bridge b_int_status bit - * remains set, and because no transition was detected no interrupt - * packet is sent to the Hub/Heart. - * - * A second scenerio is possible when a b_int_status bit is being - * shared by multiple devices: - * Device #1 generates interrupt - * Bridge b_int_status bit set - * Device #2 generates interrupt - * interrupt processing begins - * ISR for device #1 runs and - * clears interrupt - * Device #1 generates interrupt - * ISR for device #2 runs and - * clears interrupt - * (b_int_status bit still set) - * interrupt processing completes - * - * Interrupt processing is now complete, but an interrupt is still - * outstanding for Device #1. But because there was no transition of - * the b_int_status bit, no interrupt packet will be generated and - * a deadlock will occur. - * - * To avoid these deadlock situations, this function is used - * to check if a specific Bridge b_int_status bit is set, and if so, - * cause the setting of the corresponding interrupt bit. - * - * On a XBridge (IP35), we do this by writing the appropriate Bridge Force - * Interrupt register. - */ -void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) -{ - unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl); - - bit = wrap->iw_intr; - - if (pcibr_soft->bs_xbridge) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr)); - REMOTE_CPU_SEND_INTR(cpu, intr_bit); - } -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - */ - -static unsigned -pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines) -{ - pciio_slot_t slot = pciio_info_slot_get(info); - unsigned bbits = 0; - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - */ - - if (slot < 8) { - if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) - bbits |= 1 << slot; - if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) - bbits |= 1 << (slot ^ 4); - } - return bbits; -} - - -/*ARGSUSED */ -pcibr_intr_t -pcibr_intr_alloc(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - pciio_intr_line_t lines, - devfs_handle_t owner_dev) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pcibr_info->f_slot; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - bridge_t *bridge = pcibr_soft->bs_base; - int is_threaded = 0; - int thread_swlevel; - - xtalk_intr_t *xtalk_intr_p; - pcibr_intr_t *pcibr_intr_p; - pcibr_intr_list_t *intr_list_p; - - unsigned pcibr_int_bits; - unsigned pcibr_int_bit; - xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; - hub_intr_t hub_intr; - pcibr_intr_t pcibr_intr; - pcibr_intr_list_t intr_entry; - pcibr_intr_list_t intr_list; - bridgereg_t int_dev; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_alloc\n" - "%v:%s%s%s%s%s\n", - owner_dev, pconn_vhdl, - !(lines & 15) ? " No INTs?" : "", - lines & 1 ? " INTA" : "", - lines & 2 ? " INTB" : "", - lines & 4 ? " INTC" : "", - lines & 8 ? " INTD" : ""); -#endif - - NEW(pcibr_intr); - if (!pcibr_intr) - return NULL; - - if (dev_desc) { - cpuid_t intr_target_from_desc(device_desc_t, int); - } else { - extern int default_intr_pri; - - is_threaded = 1; /* PCI interrupts are threaded, by default */ - thread_swlevel = default_intr_pri; - } - - pcibr_intr->bi_dev = pconn_vhdl; - pcibr_intr->bi_lines = lines; - pcibr_intr->bi_soft = pcibr_soft; - pcibr_intr->bi_ibits = 0; /* bits will be added below */ - pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; - pcibr_intr->bi_mustruncpu = CPU_NONE; - mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock); - - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines); - - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ -#if DEBUG && INTR_DEBUG - printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits); -#endif - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - xtalk_intr = *xtalk_intr_p; - - if (xtalk_intr == NULL) { - /* - * This xtalk_intr_alloc is constrained for two reasons: - * 1) Normal interrupts and error interrupts need to be delivered - * through a single xtalk target widget so that there aren't any - * ordering problems with DMA, completion interrupts, and error - * interrupts. (Use of xconn_vhdl forces this.) - * - * 2) On IP35, addressing constraints on IP35 and Bridge force - * us to use a single PI number for all interrupts from a - * single Bridge. (IP35-specific code forces this, and we - * verify in pcibr_setwidint.) - */ - - /* - * All code dealing with threaded PCI interrupt handlers - * is located at the pcibr level. Because of this, - * we always want the lower layers (hub/heart_intr_alloc, - * intr_level_connect) to treat us as non-threaded so we - * don't set up a duplicate threaded environment. We make - * this happen by calling a special xtalk interface. - */ - xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, - owner_dev); -#if DEBUG && INTR_DEBUG - printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr); -#endif - - /* both an assert and a runtime check on this: - * we need to check in non-DEBUG kernels, and - * the ASSERT gets us more information when - * we use DEBUG kernels. - */ - ASSERT(xtalk_intr != NULL); - if (xtalk_intr == NULL) { - /* it is quite possible that our - * xtalk_intr_alloc failed because - * someone else got there first, - * and we can find their results - * in xtalk_intr_p. - */ - if (!*xtalk_intr_p) { -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_ALERT - "pcibr_intr_alloc %v: unable to get xtalk interrupt resources", - xconn_vhdl); -#else - printk(KERN_ALERT - "pcibr_intr_alloc 0x%p: unable to get xtalk interrupt resources", - (void *)xconn_vhdl); -#endif - /* yes, we leak resources here. */ - return 0; - } - } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { - /* - * now tell the bridge which slot is - * using this interrupt line. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit); - bridge->b_int_device = int_dev; /* XXXMP */ - -#if DEBUG && INTR_DEBUG - printk("%v: bridge intr bit %d clears my wrb\n", - pconn_vhdl, pcibr_int_bit); -#endif - } else { - /* someone else got one allocated first; - * free the one we just created, and - * retrieve the one they allocated. - */ - xtalk_intr_free(xtalk_intr); - xtalk_intr = *xtalk_intr_p; -#if PARANOID - /* once xtalk_intr is set, we never clear it, - * so if the CAS fails above, this condition - * can "never happen" ... - */ - if (!xtalk_intr) { - printk(KERN_ALERT - "pcibr_intr_alloc %v: unable to set xtalk interrupt resources", - xconn_vhdl); - /* yes, we leak resources here. */ - return 0; - } -#endif - } - } - - pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; - - NEW(intr_entry); - intr_entry->il_next = NULL; - intr_entry->il_intr = pcibr_intr; - intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg); - intr_list_p = - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; -#if DEBUG && INTR_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk("0x%x: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#else - printk("%v: Bridge bit %d wrap=0x%x\n", - pconn_vhdl, pcibr_int_bit, - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap); -#endif -#endif - - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the first interrupt on this bridge bit. - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list = *intr_list_p; - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* first entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased first\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the new second interrupt on this bit. - */ - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new SECOND\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - continue; - } - while (1) { - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* an entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - DEL(intr_entry); -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* entry appended to share list - */ -#if DEBUG && INTR_DEBUG - printk("%v INT 0x%x (bridge bit %d) is new Nth\n", - pconn_vhdl, pcibr_int_bits, pcibr_int_bit); -#endif - break; - } - /* step to next record in chain - */ - intr_list = *intr_list_p; - } - } - } - -#if DEBUG && INTR_DEBUG - printk("%v pcibr_intr_alloc complete\n", pconn_vhdl); -#endif - hub_intr = (hub_intr_t)xtalk_intr; - pcibr_intr->bi_irq = hub_intr->i_bit; - pcibr_intr->bi_cpu = hub_intr->i_cpuid; - return pcibr_intr; -} - -/*ARGSUSED */ -void -pcibr_intr_free(pcibr_intr_t pcibr_intr) -{ - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bit; - pcibr_intr_list_t intr_list; - int intr_shared; - xtalk_intr_t *xtalk_intrp; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; - intr_list != NULL; - intr_list = intr_list->il_next) - if (compare_and_swap_ptr((void **) &intr_list->il_intr, - pcibr_intr, - NULL)) { -#if DEBUG && INTR_DEBUG - printk("%s: cleared a handler from bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - } - /* If this interrupt line is not being shared between multiple - * devices release the xtalk interrupt resources. - */ - intr_shared = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; - xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - if ((!intr_shared) && (*xtalk_intrp)) { - - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t int_dev; - - xtalk_intr_free(*xtalk_intrp); - *xtalk_intrp = 0; - - /* Clear the PCI device interrupt to bridge interrupt pin - * mapping. - */ - int_dev = bridge->b_int_device; - int_dev &= ~BRIDGE_INT_DEV_MASK(pcibr_int_bit); - bridge->b_int_device = int_dev; - - } - } - } - DEL(pcibr_intr); -} - -LOCAL void -pcibr_setpciint(xtalk_intr_t xtalk_intr) -{ - iopaddr_t addr = xtalk_intr_addr_get(xtalk_intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(xtalk_intr); - bridgereg_t *int_addr = (bridgereg_t *) - xtalk_intr_sfarg_get(xtalk_intr); - - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); -} - -/*ARGSUSED */ -int -pcibr_intr_connect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - bridgereg_t b_int_enable; - unsigned long s; - - if (pcibr_intr == NULL) - return -1; - -#if DEBUG && INTR_DEBUG - printk("%v: pcibr_intr_connect\n", - pcibr_intr->bi_dev); -#endif - - *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_t xtalk_intr; - - xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - /* - * If this interrupt line is being shared and the connect has - * already been done, no need to do it again. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) - continue; - - - /* - * Use the pcibr wrapper function to handle all Bridge interrupts - * regardless of whether the interrupt line is shared or not. - */ - xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint, - (void *)&(bridge->b_int_addr[pcibr_int_bit].addr)); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; - -#if DEBUG && INTR_DEBUG - printk("%v bridge bit %d wrapper connected\n", - pcibr_intr->bi_dev, pcibr_int_bit); -#endif - } - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable |= pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - return 0; -} - -/*ARGSUSED */ -void -pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - bridge_t *bridge = pcibr_soft->bs_base; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - bridgereg_t b_int_enable; - unsigned long s; - - /* Stop calling the function. Now. - */ - *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and disconnect the interrupt. - */ - - /* don't disable interrupts for lines that - * are shared between devices. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) - pcibr_int_bits &= ~(1 << pcibr_int_bit); - if (!pcibr_int_bits) - return; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~pcibr_int_bits; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - /* if the interrupt line is now shared, - * do not disconnect it. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; - -#if DEBUG && INTR_DEBUG - printk("%s: xtalk disconnect done for Bridge bit %d\n", - pcibr_soft->bs_name, pcibr_int_bit); -#endif - - /* if we are sharing the interrupt line, - * connect us up; this closes the hole - * where the another pcibr_intr_alloc() - * was in progress as we disconnected. - */ - if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *) &(bridge->b_int_addr[pcibr_int_bit].addr)); - } -} - -/*ARGSUSED */ -devfs_handle_t -pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) - return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - return 0; -} - -/* ===================================================================== - * INTERRUPT HANDLING - */ -LOCAL void -pcibr_clearwidint(bridge_t *bridge) -{ - bridge->b_wid_int_upper = 0; - bridge->b_wid_int_lower = 0; -} - -LOCAL void -pcibr_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - widgetreg_t NEW_b_wid_int_upper, NEW_b_wid_int_lower; - widgetreg_t OLD_b_wid_int_upper, OLD_b_wid_int_lower; - - bridge_t *bridge = (bridge_t *)xtalk_intr_sfarg_get(intr); - - NEW_b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - NEW_b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - - OLD_b_wid_int_upper = bridge->b_wid_int_upper; - OLD_b_wid_int_lower = bridge->b_wid_int_lower; - - /* Verify that all interrupts from this Bridge are using a single PI */ - if ((OLD_b_wid_int_upper != 0) && (OLD_b_wid_int_lower != 0)) { - /* - * Once set, these registers shouldn't change; they should - * be set multiple times with the same values. - * - * If we're attempting to change these registers, it means - * that our heuristics for allocating interrupts in a way - * appropriate for IP35 have failed, and the admin needs to - * explicitly direct some interrupts (or we need to make the - * heuristics more clever). - * - * In practice, we hope this doesn't happen very often, if - * at all. - */ - if ((OLD_b_wid_int_upper != NEW_b_wid_int_upper) || - (OLD_b_wid_int_lower != NEW_b_wid_int_lower)) { - printk(KERN_WARNING "Interrupt allocation is too complex.\n"); - printk(KERN_WARNING "Use explicit administrative interrupt targetting.\n"); - printk(KERN_WARNING "bridge=0x%lx targ=0x%x\n", (unsigned long)bridge, targ); - printk(KERN_WARNING "NEW=0x%x/0x%x OLD=0x%x/0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, - OLD_b_wid_int_upper, OLD_b_wid_int_lower); - PRINT_PANIC("PCI Bridge interrupt targetting error\n"); - } - } - - bridge->b_wid_int_upper = NEW_b_wid_int_upper; - bridge->b_wid_int_lower = NEW_b_wid_int_lower; - bridge->b_int_host_err = vect; -} - -/* - * pcibr_intr_preset: called during mlreset time - * if the platform specific code needs to route - * one of the Bridge's xtalk interrupts before the - * xtalk infrastructure is available. - */ -void -pcibr_xintr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - bridge_t *bridge = (bridge_t *) which_widget; - - if (which_widget_intr == -1) { - /* bridge widget error interrupt */ - bridge->b_wid_int_upper = ( (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - bridge->b_int_host_err = vect; - - /* turn on all interrupts except - * the PCI interrupt requests, - * at least at heart. - */ - bridge->b_int_enable |= ~BRIDGE_IMR_INT_MSK; - - } else { - /* routing a PCI device interrupt. - * targ and low 38 bits of addr must - * be the same as the already set - * value for the widget error interrupt. - */ - bridge->b_int_addr[which_widget_intr].addr = - ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - /* - * now bridge can let it through; - * NB: still should be blocked at - * xtalk provider end, until the service - * function is set. - */ - bridge->b_int_enable |= 1 << vect; - } - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ -} - - -/* - * pcibr_intr_func() - * - * This is the pcibr interrupt "wrapper" function that is called, - * in interrupt context, to initiate the interrupt handler(s) registered - * (via pcibr_intr_alloc/connect) for the occurring interrupt. Non-threaded - * handlers will be called directly, and threaded handlers will have their - * thread woken up. - */ -void -pcibr_intr_func(intr_arg_t arg) -{ - pcibr_intr_wrap_t wrap = (pcibr_intr_wrap_t) arg; - reg_p wrbf; - pcibr_intr_t intr; - pcibr_intr_list_t list; - int clearit; - int do_nonthreaded = 1; - int is_threaded = 0; - int x = 0; - - /* - * If any handler is still running from a previous interrupt - * just return. If there's a need to call the handler(s) again, - * another interrupt will be generated either by the device or by - * pcibr_force_interrupt(). - */ - - if (wrap->iw_hdlrcnt) { - return; - } - - /* - * Call all interrupt handlers registered. - * First, the pcibr_intrd threads for any threaded handlers will be - * awoken, then any non-threaded handlers will be called sequentially. - */ - - clearit = 1; - while (do_nonthreaded) { - for (list = wrap->iw_list; list != NULL; list = list->il_next) { - if ((intr = list->il_intr) && - (intr->bi_flags & PCIIO_INTR_CONNECTED)) { - - /* - * This device may have initiated write - * requests since the bridge last saw - * an edge on this interrupt input; flushing - * the buffer prior to invoking the handler - * should help but may not be sufficient if we - * get more requests after the flush, followed - * by the card deciding it wants service, before - * the interrupt handler checks to see if things need - * to be done. - * - * There is a similar race condition if - * an interrupt handler loops around and - * notices further service is required. - * Perhaps we need to have an explicit - * call that interrupt handlers need to - * do between noticing that DMA to memory - * has completed, but before observing the - * contents of memory? - */ - - if ((do_nonthreaded) && (!is_threaded)) { - /* Non-threaded. - * Call the interrupt handler at interrupt level - */ - - /* Only need to flush write buffers if sharing */ - - if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) { - if ((x = *wrbf)) /* write request buffer flush */ -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_ALERT "pcibr_intr_func %v: \n" - "write buffer flush failed, wrbf=0x%x\n", - list->il_intr->bi_dev, wrbf); -#else - printk(KERN_ALERT "pcibr_intr_func %p: \n" - "write buffer flush failed, wrbf=0x%lx\n", - (void *)list->il_intr->bi_dev, (long) wrbf); -#endif - } - } - - clearit = 0; - } - } - - do_nonthreaded = 0; - /* - * If the non-threaded handler was the last to complete, - * (i.e., no threaded handlers still running) force an - * interrupt to avoid a potential deadlock situation. - */ - if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); - } - } - - /* If there were no handlers, - * disable the interrupt and return. - * It will get enabled again after - * a handler is connected. - * If we don't do this, we would - * sit here and spin through the - * list forever. - */ - if (clearit) { - pcibr_soft_t pcibr_soft = wrap->iw_soft; - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t b_int_enable; - bridgereg_t mask = 1 << wrap->iw_intr; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - b_int_enable = bridge->b_int_enable; - b_int_enable &= ~mask; - bridge->b_int_enable = b_int_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - return; - } -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ -/*ARGSUSED */ -void -pcibr_provider_startup(devfs_handle_t pcibr) -{ -} - -/*ARGSUSED */ -void -pcibr_provider_shutdown(devfs_handle_t pcibr) -{ -} - -int -pcibr_reset(devfs_handle_t conn) -{ - pciio_info_t pciio_info = pciio_info_get(conn); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - bridgereg_t ctlreg; - unsigned cfgctl[8]; - unsigned long s; - int f, nf; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int win; - - if (pcibr_soft->bs_slot[pciio_slot].has_host) { - pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0]; - } - if (pciio_slot < 4) { - s = pcibr_lock(pcibr_soft); - nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4]; - - ctlreg = bridge->b_wid_control; - bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot); - /* XXX delay? */ - bridge->b_wid_control = ctlreg; - /* XXX delay? */ - - for (f = 0; f < nf; ++f) - if ((pcibr_info = pcibr_infoh[f])) - for (win = 0; win < 6; ++win) - if (pcibr_info->f_window[win].w_base != 0) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] = - pcibr_info->f_window[win].w_base; - for (f = 0; f < nf; ++f) - if (pcibr_infoh[f]) - bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f]; - pcibr_unlock(pcibr_soft, s); - - return 0; - } -#ifdef SUPPORT_PRINTING_V_FORMAT - printk(KERN_WARNING "%v: pcibr_reset unimplemented for slot %d\n", - conn, pciio_slot); -#endif - return -1; -} - -pciio_endian_t -pcibr_endian_set(devfs_handle_t pconn_vhdl, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t devreg; - unsigned long s; - - /* - * Bridge supports hardware swapping; so we can always - * arrange for the caller's desired endianness. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_end != desired_end) - devreg |= BRIDGE_DEV_SWAP_BITS; - else - devreg &= ~BRIDGE_DEV_SWAP_BITS; - - /* NOTE- if we ever put SWAP bits - * onto the disabled list, we will - * have to change the logic here. - */ - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg); -#endif - - return desired_end; -} - -/* This (re)sets the GBR and REALTIME bits and also keeps track of how - * many sets are outstanding. Reset succeeds only if the number of outstanding - * sets == 1. - */ -int -pcibr_priority_bits_set(pcibr_soft_t pcibr_soft, - pciio_slot_t pciio_slot, - pciio_priority_t device_prio) -{ - unsigned long s; - int *counter; - bridgereg_t rtbits = 0; - bridgereg_t devreg; - int rc = PRIO_SUCCESS; - - /* in dual-slot configurations, the host and the - * guest have separate DMA resources, so they - * have separate requirements for priority bits. - */ - - counter = &(pcibr_soft->bs_slot[pciio_slot].bss_pri_uctr); - - /* - * Bridge supports PCI notions of LOW and HIGH priority - * arbitration rings via a "REAL_TIME" bit in the per-device - * Bridge register. The "GBR" bit controls access to the GBR - * ring on the xbow. These two bits are (re)set together. - * - * XXX- Bug in Rev B Bridge Si: - * Symptom: Prefetcher starts operating incorrectly. This happens - * due to corruption of the address storage ram in the prefetcher - * when a non-real time PCI request is pulled and a real-time one is - * put in it's place. Workaround: Use only a single arbitration ring - * on PCI bus. GBR and RR can still be uniquely used per - * device. NETLIST MERGE DONE, WILL BE FIXED IN REV C. - */ - - if (pcibr_soft->bs_rev_num != BRIDGE_PART_REV_B) - rtbits |= BRIDGE_DEV_RT; - - /* NOTE- if we ever put DEV_RT or DEV_GBR on - * the disabled list, we will have to take - * it into account here. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_prio == PCI_PRIO_HIGH) { - if ((++*counter == 1)) { - if (rtbits) - devreg |= rtbits; - else - rc = PRIO_FAIL; - } - } else if (device_prio == PCI_PRIO_LOW) { - if (*counter <= 0) - rc = PRIO_FAIL; - else if (--*counter == 0) - if (rtbits) - devreg &= ~rtbits; - } - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); - - return rc; -} - -pciio_priority_t -pcibr_priority_set(devfs_handle_t pconn_vhdl, - pciio_priority_t device_prio) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio); - - return device_prio; -} - -/* - * Interfaces to allow special (e.g. SGI) drivers to set/clear - * Bridge-specific device flags. Many flags are modified through - * PCI-generic interfaces; we don't allow them to be directly - * manipulated here. Only flags that at this point seem pretty - * Bridge-specific can be set through these special interfaces. - * We may add more flags as the need arises, or remove flags and - * create PCI-generic interfaces as the need arises. - * - * Returns 0 on failure, 1 on success - */ -int -pcibr_device_flags_set(devfs_handle_t pconn_vhdl, - pcibr_device_flags_t flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridgereg_t set = 0; - bridgereg_t clr = 0; - - ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_PMU_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_PMU_WRGA_EN; - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_DIR_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_DIR_WRGA_EN; - - if (flags & PCIBR_PREFETCH) - set |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - clr |= BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - set |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - clr |= BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - set |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - clr |= BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - set |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - clr |= BRIDGE_DEV_DEV_SIZE; - - if (set || clr) { - bridgereg_t devreg; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - devreg = (devreg & ~clr) | set; - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - bridge_t *bridge = pcibr_soft->bs_base; - - bridge->b_device[pciio_slot].reg = devreg; - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - pcibr_unlock(pcibr_soft, s); -#if DEBUG && PCIBR_DEV_DEBUG - printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits); -#endif - } - return (1); -} - -#ifdef LITTLE_ENDIAN -/* - * on sn-ia we need to twiddle the the addresses going out - * the pci bus because we use the unswizzled synergy space - * (the alternative is to use the swizzled synergy space - * and byte swap the data) - */ -#define CB(b,r) (((volatile uint8_t *) b)[((r)^4)]) -#define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) -#define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#else -#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) -#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) -#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) -#endif /* LITTLE_ENDIAN */ - - -LOCAL cfg_p -pcibr_config_addr(devfs_handle_t conn, - unsigned reg) -{ - pcibr_info_t pcibr_info; - pciio_slot_t pciio_slot; - pciio_function_t pciio_func; - pcibr_soft_t pcibr_soft; - bridge_t *bridge; - cfg_p cfgbase = (cfg_p)0; - - pcibr_info = pcibr_info_get(conn); - - pciio_slot = pcibr_info->f_slot; - if (pciio_slot == PCIIO_SLOT_NONE) - pciio_slot = PCI_TYPE1_SLOT(reg); - - pciio_func = pcibr_info->f_func; - if (pciio_func == PCIIO_FUNC_NONE) - pciio_func = PCI_TYPE1_FUNC(reg); - - pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - - bridge = pcibr_soft->bs_base; - - cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l; - - return cfgbase; -} - -uint64_t -pcibr_config_get(devfs_handle_t conn, - unsigned reg, - unsigned size) -{ - return do_pcibr_config_get(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); -} - -LOCAL uint64_t -do_pcibr_config_get( - cfg_p cfgbase, - unsigned reg, - unsigned size) -{ - unsigned value; - - - value = CW(cfgbase, reg); - - if (reg & 3) - value >>= 8 * (reg & 3); - if (size < 4) - value &= (1 << (8 * size)) - 1; - - return value; -} - -void -pcibr_config_set(devfs_handle_t conn, - unsigned reg, - unsigned size, - uint64_t value) -{ - do_pcibr_config_set(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); -} - -LOCAL void -do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - switch (size) { - case 1: - CB(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; - - case 4: - CW(cfgbase, reg) = value; - break; - } -} - -pciio_provider_t pcibr_provider = -{ - (pciio_piomap_alloc_f *) pcibr_piomap_alloc, - (pciio_piomap_free_f *) pcibr_piomap_free, - (pciio_piomap_addr_f *) pcibr_piomap_addr, - (pciio_piomap_done_f *) pcibr_piomap_done, - (pciio_piotrans_addr_f *) pcibr_piotrans_addr, - (pciio_piospace_alloc_f *) pcibr_piospace_alloc, - (pciio_piospace_free_f *) pcibr_piospace_free, - - (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, - (pciio_dmamap_free_f *) pcibr_dmamap_free, - (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, - (pciio_dmamap_done_f *) pcibr_dmamap_done, - (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, - (pciio_dmamap_drain_f *) pcibr_dmamap_drain, - (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - (pciio_dmalist_drain_f *) pcibr_dmalist_drain, - - (pciio_intr_alloc_f *) pcibr_intr_alloc, - (pciio_intr_free_f *) pcibr_intr_free, - (pciio_intr_connect_f *) pcibr_intr_connect, - (pciio_intr_disconnect_f *) pcibr_intr_disconnect, - (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, - - (pciio_provider_startup_f *) pcibr_provider_startup, - (pciio_provider_shutdown_f *) pcibr_provider_shutdown, - (pciio_reset_f *) pcibr_reset, - (pciio_write_gather_flush_f *) pcibr_write_gather_flush, - (pciio_endian_set_f *) pcibr_endian_set, - (pciio_priority_set_f *) pcibr_priority_set, - (pciio_config_get_f *) pcibr_config_get, - (pciio_config_set_f *) pcibr_config_set, - - (pciio_error_devenable_f *) 0, - (pciio_error_extract_f *) 0, - -#ifdef LATER - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, -#else - (pciio_driver_reg_callback_f *) 0, - (pciio_driver_unreg_callback_f *) 0, -#endif - (pciio_device_unregister_f *) pcibr_device_unregister, - (pciio_dma_enabled_f *) pcibr_dma_enabled, -}; - -LOCAL pcibr_hints_t -pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) -{ - arbitrary_info_t ainfo = 0; - graph_error_t rv; - pcibr_hints_t hint; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (alloc && (rv != GRAPH_SUCCESS)) { - - NEW(hint); - hint->rrb_alloc_funct = NULL; - hint->ph_intr_bits = NULL; - rv = hwgraph_info_add_LBL(xconn_vhdl, - INFO_LBL_PCIBR_HINTS, - (arbitrary_info_t) hint); - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - if (ainfo != (arbitrary_info_t) hint) - goto abnormal_exit; - } - return (pcibr_hints_t) ainfo; - -abnormal_exit: -#ifdef LATER - printf("SHOULD NOT BE HERE\n"); -#endif - DEL(hint); - return(NULL); - -} - -void -pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_rrb_fixed = mask; -#if DEBUG - else - printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); -} - -void -pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, - pciio_slot_t host, - pciio_slot_t guest) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_host_slot[guest] = host + 1; -#if DEBUG - else - printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, - pcibr_intr_bits_f *xxx_intr_bits) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_intr_bits = xxx_intr_bits; -#if DEBUG - else - printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->rrb_alloc_funct = rrb_alloc_funct; -} - -void -pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_hands_off = 1; -#if DEBUG - else - printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n" - "\t%p\n", xconn_vhdl); -#endif -} - -void -pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, - pciio_slot_t slot, - uint64_t subdevs) -{ - arbitrary_info_t ainfo = 0; - char sdname[16]; - devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; - - sprintf(sdname, "pci/%d", slot); - (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); - if (pconn_vhdl == GRAPH_VERTEX_NONE) { -#if DEBUG - printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n" - "\t%p (seeking %s)\n", xconn_vhdl, sdname); -#endif - return; - } - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == 0) { - uint64_t *subdevp; - - NEW(subdevp); - if (!subdevp) { -#if DEBUG - printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } - *subdevp = subdevs; - hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == (arbitrary_info_t) subdevp) - return; - DEL(subdevp); - if (ainfo == (arbitrary_info_t) NULL) { -#if DEBUG - printk("pcibr_hints_subdevs: null subdevs ptr at\n" - "\t%p\n", pconn_vhdl); -#endif - return; - } -#if DEBUG - printk("pcibr_subdevs_get: dup subdev add_LBL at\n" - "\t%p\n", pconn_vhdl); -#endif - } - *(uint64_t *) ainfo = subdevs; -} - - -#ifdef LATER - -#include -#include - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_vertex); -#endif - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); -#ifdef SUPPORT_PRINTING_V_FORMAT - sprintf(name, "%v", pcibr_info->f_master); -#endif - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - atomic_read(&pss->bss_ext_ates_active) ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} - -#endif /* LATER */ - -int -pcibr_dma_enabled(devfs_handle_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - - return xtalk_dma_enabled(pcibr_soft->bs_conn); -} diff -Nru a/arch/ia64/sn/io/sn2/Makefile b/arch/ia64/sn/io/sn2/Makefile --- a/arch/ia64/sn/io/sn2/Makefile Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/io/sn2/Makefile Fri May 16 04:18:19 2003 @@ -11,10 +11,9 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += pcibr/ bte_error.o geo_op.o klconflib.o klgraph.o l1.o \ - l1_command.o ml_iograph.o ml_SN_init.o ml_SN_intr.o module.o \ - pci_bus_cvlink.o pciio.o pic.o sgi_io_init.o shub.o shuberror.o \ - shub_intr.o shubio.o xbow.o xtalk.o +obj-y += pcibr/ ml_SN_intr.o shub_intr.o shuberror.o shub.o bte_error.o \ + pic.o geo_op.o l1.o l1_command.o klconflib.o klgraph.o ml_SN_init.o \ + ml_iograph.o module.o pciio.o xbow.o xtalk.o shubio.o obj-$(CONFIG_KDB) += kdba_io.o obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o diff -Nru a/arch/ia64/sn/io/sn2/bte_error.c b/arch/ia64/sn/io/sn2/bte_error.c --- a/arch/ia64/sn/io/sn2/bte_error.c Tue Dec 3 10:07:26 2002 +++ b/arch/ia64/sn/io/sn2/bte_error.c Fri May 16 04:18:18 2003 @@ -1,10 +1,35 @@ -/* $Id: bte_error.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ +/* * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ @@ -29,121 +54,208 @@ #include #include -/************************************************************************ - * * - * BTE ERROR RECOVERY * - * * - * Given a BTE error, the node causing the error must do the following: * - * a) Clear all crbs relating to that BTE * - * 1) Read CRBA value for crb in question * - * 2) Mark CRB as VALID, store local physical * - * address known to be good in the address field * - * (bte_notification_targ is a known good local * - * address). * - * 3) Write CRBA * - * 4) Using ICCR, FLUSH the CRB, and wait for it to * - * complete. * - * ... BTE BUSY bit should now be clear (or at least * - * should be after ALL CRBs associated with the * - * transfer are complete. * - * * - * b) Re-enable BTE * - * 1) Write IMEM with BTE Enable + XXX bits - * 2) Write IECLR with BTE clear bits - * 3) Clear IIDSR INT_SENT bits. - * * - ************************************************************************/ - -/* - * >>> bte_crb_error_handler needs to be broken into two parts. The - * first should cleanup the CRB. The second should wait until all bte - * related CRB's are complete and then do the error reset. + +/* + * Bte error handling is done in two parts. The first captures + * any crb related errors. Since there can be multiple crbs per + * interface and multiple interfaces active, we need to wait until + * all active crbs are completed. This is the first job of the + * second part error handler. When all bte related CRBs are cleanly + * completed, it resets the interfaces and gets them ready for new + * transfers to be queued. */ -void -bte_crb_error_handler(devfs_handle_t hub_v, int btenum, - int crbnum, ioerror_t *ioe, int bteop) + + +void bte_error_handler(unsigned long); + + /* - * Function: bte_crb_error_handler - * Purpose: Process a CRB for a specific HUB/BTE - * Parameters: hub_v - vertex of hub in HW graph - * btenum - bte number on hub (0 == a, 1 == b) - * crbnum - crb number being processed - * Notes: - * This routine assumes serialization at a higher level. A CRB - * should not be processed more than once. The error recovery - * follows the following sequence - if you change this, be real - * sure about what you are doing. - * + * First part error handler. This is called whenever any error CRB interrupt + * is generated by the II. */ +void +bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, + int crbnum, ioerror_t * ioe, int bteop) { - hubinfo_t hinfo; - icrba_t crba; - icrbb_t crbb; - nasid_t n; - hubreg_t iidsr, imem, ieclr; + hubinfo_t hinfo; + struct bteinfo_s *bte; + hubinfo_get(hub_v, &hinfo); + bte = &hinfo->h_nodepda->bte_if[btenum]; + + /* + * The caller has already figured out the error type, we save that + * in the bte handle structure for the thread excercising the + * interface to consume. + */ + switch (ioe->ie_errortype) { + case IIO_ICRB_ECODE_PERR: + bte->bh_error = BTEFAIL_POISON; + break; + case IIO_ICRB_ECODE_WERR: + bte->bh_error = BTEFAIL_PROT; + break; + case IIO_ICRB_ECODE_AERR: + bte->bh_error = BTEFAIL_ACCESS; + break; + case IIO_ICRB_ECODE_TOUT: + bte->bh_error = BTEFAIL_TOUT; + break; + case IIO_ICRB_ECODE_XTERR: + bte->bh_error = BTEFAIL_XTERR; + break; + case IIO_ICRB_ECODE_DERR: + bte->bh_error = BTEFAIL_DIR; + break; + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_PRERR: + /* NO BREAK */ + default: + bte->bh_error = BTEFAIL_ERROR; + } + + bte->bte_error_count++; + BTE_PRINTK(("Got an error on cnode %d bte %d\n", + bte->bte_cnode, bte->bte_num)); + bte_error_handler((unsigned long) hinfo->h_nodepda); +} - n = hinfo->h_nasid; - +/* + * Second part error handler. Wait until all BTE related CRBs are completed + * and then reset the interfaces. + */ +void +bte_error_handler(unsigned long _nodepda) +{ + struct nodepda_s *err_nodepda = (struct nodepda_s *) _nodepda; + spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; + struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; + nasid_t nasid; + int i; + int valid_crbs; + unsigned long irq_flags; + volatile u64 *notify; + bte_result_t bh_error; + ii_imem_u_t imem; /* II IMEM Register */ + ii_icrb0_d_u_t icrbd; /* II CRB Register D */ + ii_ibcr_u_t ibcr; + ii_icmr_u_t icmr; + + + BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, + smp_processor_id())); + + spin_lock_irqsave(recovery_lock, irq_flags); + + if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && + (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { + BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, + smp_processor_id())); + spin_unlock_irqrestore(recovery_lock, irq_flags); + return; + } /* - * The following 10 lines (or so) are adapted from IRIXs - * bte_crb_error function. No clear documentation tells - * why the crb needs to complete normally in order for - * the BTE to resume normal operations. This first step - * appears vital! + * Lock all interfaces on this node to prevent new transfers + * from being queued. */ + for (i = 0; i < BTES_PER_NODE; i++) { + if (err_nodepda->bte_if[i].cleanup_active) { + continue; + } + spin_lock(&err_nodepda->bte_if[i].spinlock); + BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, + smp_processor_id(), i)); + err_nodepda->bte_if[i].cleanup_active = 1; + } + + /* Determine information about our hub */ + nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); + /* - * Zero error and error code to prevent error_dump complaining - * about these CRBs. Copy the CRB to the notification line. - * The crb address is in shub format (physical address shifted - * right by cacheline size). + * A BTE transfer can use multiple CRBs. We need to make sure + * that all the BTE CRBs are complete (or timed out) before + * attempting to clean up the error. Resetting the BTE while + * there are still BTE CRBs active will hang the BTE. + * We should look at all the CRBs to see if they are allocated + * to the BTE and see if they are still active. When none + * are active, we can continue with the cleanup. + * + * We also want to make sure that the local NI port is up. + * When a router resets the NI port can go down, while it + * goes through the LLP handshake, but then comes back up. */ - crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); - crbb.b_error=0; - crbb.b_ecode=0; - REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval); - - crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); - crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3; - crba.a_valid = 1; - REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); - - REMOTE_HUB_S(n, IIO_ICCR, - IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); - - while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) - ; - - - /* Terminate the BTE. */ - /* >>> The other bte transfer will need to be restarted. */ - HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr + - IIO_IBCT0 - IIO_IBLS0))); - - imem = REMOTE_HUB_L(n, IIO_IMEM); - ieclr = REMOTE_HUB_L(n, IIO_IECLR); - if (btenum == 0) { - imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; - ieclr|= IECLR_BTE0; - } else { - imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; - ieclr|= IECLR_BTE1; - } - REMOTE_HUB_S(n, IIO_IMEM, imem); - REMOTE_HUB_S(n, IIO_IECLR, ieclr); - - iidsr = REMOTE_HUB_L(n, IIO_IIDSR); - iidsr &= ~IIO_IIDSR_SENT_MASK; - iidsr |= IIO_IIDSR_ENB_MASK; - REMOTE_HUB_S(n, IIO_IIDSR, iidsr); + icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); + if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { + /* + * There are errors which still need to be cleaned up by + * hubiio_crb_error_handler + */ + mod_timer(recovery_timer, HZ * 5); + BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, + smp_processor_id())); + spin_unlock_irqrestore(recovery_lock, irq_flags); + return; + } + if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { + valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; - bte_reset_nasid(n); + for (i = 0; i < IIO_NUM_CRBS; i++) { + if (!((1 << i) & valid_crbs)) { + /* This crb was not marked as valid, ignore */ + continue; + } + icrbd.ii_icrb0_d_regval = + REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); + if (icrbd.d_bteop) { + mod_timer(recovery_timer, HZ * 5); + BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", + err_nodepda, smp_processor_id(), i)); + spin_unlock_irqrestore(recovery_lock, + irq_flags); + return; + } + } + } - *nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR; -} + BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, + smp_processor_id())); + /* Reenable both bte interfaces */ + imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); + imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; + REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); + + /* Reinitialize both BTE state machines. */ + ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); + ibcr.ii_ibcr_fld_s.i_soft_reset = 1; + REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); + + + for (i = 0; i < BTES_PER_NODE; i++) { + bh_error = err_nodepda->bte_if[i].bh_error; + if (bh_error != BTE_SUCCESS) { + /* There is an error which needs to be notified */ + notify = err_nodepda->bte_if[i].most_rcnt_na; + BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", + err_nodepda->bte_if[i].bte_cnode, + err_nodepda->bte_if[i].bte_num, + IBLS_ERROR | (u64) bh_error)); + *notify = IBLS_ERROR | bh_error; + err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; + } + + err_nodepda->bte_if[i].cleanup_active = 0; + BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, + smp_processor_id(), i)); + spin_unlock(&pda->cpu_bte_if[i]->spinlock); + } + + del_timer(recovery_timer); + + spin_unlock_irqrestore(recovery_lock, irq_flags); +} diff -Nru a/arch/ia64/sn/io/sn2/kdba_io.c b/arch/ia64/sn/io/sn2/kdba_io.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/io/sn2/kdba_io.c Fri May 16 11:50:50 2003 @@ -0,0 +1,76 @@ +/* + * Kernel Debugger Architecture Dependent POD functions. + * + * Copyright (C) 1999-2003 Silicon Graphics, Inc. All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include +#include +//#include + +/** + * kdba_io - enter POD mode from kdb + * @argc: arg count + * @argv: arg values + * @envp: kdb env. vars + * @regs: current register state + * + * Enter POD mode from kdb using SGI SN specific SAL function call. + */ +static int +kdba_io(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_printf("kdba_io entered with addr 0x%p\n", (void *) regs); + + return(0); +} + +/** + * kdba_io_init - register 'io' command with kdb + * + * Register the 'io' command with kdb at load time. + */ +void +kdba_io_init(void) +{ + kdb_register("io", kdba_io, "", "Display IO Contents", 0); +} + +/** + * kdba_io_exit - unregister the 'io' command + * + * Tell kdb that the 'io' command is no longer available. + */ +static void __exit +kdba_exit(void) +{ + kdb_unregister("io"); +} diff -Nru a/arch/ia64/sn/io/sn2/klconflib.c b/arch/ia64/sn/io/sn2/klconflib.c --- a/arch/ia64/sn/io/sn2/klconflib.c Sun May 25 17:00:00 2003 +++ b/arch/ia64/sn/io/sn2/klconflib.c Mon Jun 16 17:15:40 2003 @@ -24,8 +24,6 @@ #include #include -#define printf printk -int hasmetarouter; #define LDEBUG 0 #define NIC_UNKNOWN ((nic_t) -1) @@ -37,10 +35,11 @@ #define DBG(x...) #endif /* DEBUG_KLGRAPH */ -static void sort_nic_names(lboard_t *) ; - u64 klgraph_addr[MAX_COMPACT_NODES]; -int module_number = 0; +static int hasmetarouter; + + +char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#=012345"; lboard_t * find_lboard(lboard_t *start, unsigned char brd_type) @@ -135,23 +134,6 @@ return (lboard_t *)NULL; } -lboard_t * -find_lboard_module_class(lboard_t *start, geoid_t geoid, - unsigned char brd_type) -{ - while (start) { - DBG("find_lboard_module_class: lboard 0x%p, start->brd_geoid 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_geoid, geoid, start->brd_type, brd_type); - - if (geo_cmp(start->brd_geoid, geoid) && - (KLCLASS(start->brd_type) == KLCLASS(brd_type))) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - /* * Convert a NIC name to a name for use in the hardware graph. */ @@ -205,63 +187,6 @@ } /* - * Find the lboard structure and get the board name. - * If we can't find the structure or it's too low a revision, - * use default name. - */ -lboard_t * -get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name) -{ - lboard_t *brd; - - brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), - geoid); - -#ifndef _STANDALONE - { - cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); - - if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID)) - brd = find_lboard_modslot((lboard_t *) - KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer), - geoid); - } -#endif - - if (!brd || (brd->brd_sversion < 2)) { - strcpy(name, EDGE_LBL_XWIDGET); - } else { - nic_name_convert(brd->brd_name, name); - } - - /* - * PV # 540860 - * If the name is not 'baseio' - * get the lowest of all the names in the nic string. - * This is needed for boards like divo, which can have - * a bunch of daughter cards, but would like to be called - * divo. We could do this for baseio - * but it has some special case names that we would not - * like to disturb at this point. - */ - - /* gfx boards don't need any of this name scrambling */ - if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) { - return(brd); - } - - if (!(!strcmp(name, "baseio") )) { - if (brd) { - sort_nic_names(brd) ; - /* Convert to small case, '-' to '_' etc */ - nic_name_convert(brd->brd_name, name) ; - } - } - - return(brd); -} - -/* * get_actual_nasid * * Completely disabled brds have their klconfig on @@ -341,12 +266,20 @@ board_name = EDGE_LBL_IO; break; case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PBRICK) + if (brd->brd_type == KLTYPE_PXBRICK) + board_name = EDGE_LBL_PXBRICK; + else if (brd->brd_type == KLTYPE_IXBRICK) + board_name = EDGE_LBL_IXBRICK; + else if (brd->brd_type == KLTYPE_PBRICK) board_name = EDGE_LBL_PBRICK; else if (brd->brd_type == KLTYPE_IBRICK) board_name = EDGE_LBL_IBRICK; else if (brd->brd_type == KLTYPE_XBRICK) board_name = EDGE_LBL_XBRICK; + else if (brd->brd_type == KLTYPE_PEBRICK) + board_name = EDGE_LBL_PEBRICK; + else if (brd->brd_type == KLTYPE_CGBRICK) + board_name = EDGE_LBL_CGBRICK; else board_name = EDGE_LBL_IOBRICK; break; @@ -623,182 +556,6 @@ #include "asm/sn/sn_private.h" -xwidgetnum_t -nodevertex_widgetnum_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - return(hubinfo_p->h_widgetid); -} - -devfs_handle_t -nodevertex_xbow_peer_get(devfs_handle_t node_vtx) -{ - hubinfo_t hubinfo_p; - nasid_t xbow_peer_nasid; - cnodeid_t xbow_peer; - - hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, - (arbitrary_info_t *) &hubinfo_p); - xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer; - if(xbow_peer_nasid == INVALID_NASID) - return ( (devfs_handle_t)-1); - xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid); - return(NODEPDA(xbow_peer)->node_vertex); -} - -/* NIC Sorting Support */ - -#define MAX_NICS_PER_STRING 32 -#define MAX_NIC_NAME_LEN 32 - -static char * -get_nic_string(lboard_t *lb) -{ - int i; - klinfo_t *k = NULL ; - klconf_off_t mfg_off = 0 ; - char *mfg_nic = NULL ; - - for (i = 0; i < KLCF_NUM_COMPS(lb); i++) { - k = KLCF_COMP(lb, i) ; - switch(k->struct_type) { - case KLSTRUCT_BRI: - mfg_off = ((klbri_t *)k)->bri_mfg_nic ; - break ; - - case KLSTRUCT_HUB: - mfg_off = ((klhub_t *)k)->hub_mfg_nic ; - break ; - - case KLSTRUCT_ROU: - mfg_off = ((klrou_t *)k)->rou_mfg_nic ; - break ; - - case KLSTRUCT_GFX: - mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ; - break ; - - case KLSTRUCT_TPU: - mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ; - break ; - - case KLSTRUCT_GSN_A: - case KLSTRUCT_GSN_B: - mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ; - break ; - - case KLSTRUCT_XTHD: - mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ; - break; - - default: - mfg_off = 0 ; - break ; - } - if (mfg_off) - break ; - } - - if ((mfg_off) && (k)) - mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ; - - return mfg_nic ; -} - -char * -get_first_string(char **ptrs, int n) -{ - int i ; - char *tmpptr ; - - if ((ptrs == NULL) || (n == 0)) - return NULL ; - - tmpptr = ptrs[0] ; - - if (n == 1) - return tmpptr ; - - for (i = 0 ; i < n ; i++) { - if (strcmp(tmpptr, ptrs[i]) > 0) - tmpptr = ptrs[i] ; - } - - return tmpptr ; -} - -int -get_ptrs(char *idata, char **ptrs, int n, char *label) -{ - int i = 0 ; - char *tmp = idata ; - - if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0)) - return 0 ; - - while ( (tmp = strstr(tmp, label)) ){ - tmp += strlen(label) ; - /* check for empty name field, and last NULL ptr */ - if ((i < (n-1)) && (*tmp != ';')) { - ptrs[i++] = tmp ; - } - } - - ptrs[i] = NULL ; - - return i ; -} - -/* - * sort_nic_names - * - * Does not really do sorting. Find the alphabetically lowest - * name among all the nic names found in a nic string. - * - * Return: - * Nothing - * - * Side Effects: - * - * lb->brd_name gets the new name found - */ - -static void -sort_nic_names(lboard_t *lb) -{ - char *nic_str ; - char *ptrs[MAX_NICS_PER_STRING] ; - char name[MAX_NIC_NAME_LEN] ; - char *tmp, *tmp1 ; - - *name = 0 ; - - /* Get the nic pointer from the lb */ - - if ((nic_str = get_nic_string(lb)) == NULL) - return ; - - tmp = get_first_string(ptrs, - get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ; - - if (tmp == NULL) - return ; - - if ( (tmp1 = strchr(tmp, ';')) ) - strlcpy(name, tmp, tmp1-tmp); - else - strlcpy(name, tmp, (sizeof(name))); - - strlcpy(lb->brd_name, name, sizeof(lb->brd_name)) ; -} - - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345"; - /* * Format a module id for printing. */ @@ -811,6 +568,7 @@ rack = MODULE_GET_RACK(m); ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); brickchar = MODULE_GET_BTCHAR(m); + position = MODULE_GET_BPOS(m); if (fmt == MODULE_FORMAT_BRIEF) { diff -Nru a/arch/ia64/sn/io/sn2/klgraph.c b/arch/ia64/sn/io/sn2/klgraph.c --- a/arch/ia64/sn/io/sn2/klgraph.c Mon Feb 24 05:24:10 2003 +++ b/arch/ia64/sn/io/sn2/klgraph.c Mon May 19 05:42:35 2003 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -42,7 +41,7 @@ extern char arg_maxnodes[]; extern u64 klgraph_addr[]; -void mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid); +void mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid); /* @@ -69,7 +68,7 @@ * Add detailed disabled cpu inventory info to the hardware graph. */ void -klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv, +klhwg_disabled_cpu_invent_info(vertex_hdl_t cpuv, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) { @@ -118,7 +117,7 @@ * Add detailed cpu inventory info to the hardware graph. */ void -klhwg_cpu_invent_info(devfs_handle_t cpuv, +klhwg_cpu_invent_info(vertex_hdl_t cpuv, cnodeid_t cnode, klcpu_t *cpu) { @@ -153,7 +152,7 @@ * as a part of detailed inventory info in the hwgraph. */ void -klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode) +klhwg_baseio_inventory_add(vertex_hdl_t baseio_vhdl,cnodeid_t cnode) { invent_miscinfo_t *baseio_inventory; unsigned char version = 0,revision = 0; @@ -177,20 +176,11 @@ sizeof(invent_miscinfo_t)); } -char *hub_rev[] = { - "0.0", - "1.0", - "2.0", - "2.1", - "2.2", - "2.3" -}; - /* * Add detailed cpu inventory info to the hardware graph. */ void -klhwg_hub_invent_info(devfs_handle_t hubv, +klhwg_hub_invent_info(vertex_hdl_t hubv, cnodeid_t cnode, klhub_t *hub) { @@ -215,10 +205,10 @@ /* ARGSUSED */ void -klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode) +klhwg_add_hub(vertex_hdl_t node_vertex, klhub_t *hub, cnodeid_t cnode) { - devfs_handle_t myhubv; - devfs_handle_t hub_mon; + vertex_hdl_t myhubv; + vertex_hdl_t hub_mon; int rc; extern struct file_operations shub_mon_fops; @@ -226,7 +216,7 @@ (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); rc = device_master_set(myhubv, node_vertex); hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, DEVFS_FL_AUTO_DEVNUM, + 0, 0, 0, 0, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, &shub_mon_fops, (void *)(long)cnode); @@ -234,9 +224,9 @@ /* ARGSUSED */ void -klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) +klhwg_add_disabled_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) { - devfs_handle_t my_cpu; + vertex_hdl_t my_cpu; char name[120]; cpuid_t cpu_id; nasid_t nasid; @@ -257,9 +247,9 @@ /* ARGSUSED */ void -klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) +klhwg_add_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) { - devfs_handle_t my_cpu, cpu_dir; + vertex_hdl_t my_cpu, cpu_dir; char name[120]; cpuid_t cpu_id; nasid_t nasid; @@ -295,7 +285,7 @@ nasid_t hub_nasid; cnodeid_t hub_cnode; int widgetnum; - devfs_handle_t xbow_v, hubv; + vertex_hdl_t xbow_v, hubv; /*REFERENCED*/ graph_error_t err; @@ -363,12 +353,12 @@ /* ARGSUSED */ void -klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap) +klhwg_add_node(vertex_hdl_t hwgraph_root, cnodeid_t cnode) { nasid_t nasid; lboard_t *brd; klhub_t *hub; - devfs_handle_t node_vertex = NULL; + vertex_hdl_t node_vertex = NULL; char path_buffer[100]; int rv; char *s; @@ -382,7 +372,7 @@ ASSERT(brd); do { - devfs_handle_t cpu_dir; + vertex_hdl_t cpu_dir; /* Generate a hardware graph path for this board. */ board_to_path(brd, path_buffer); @@ -443,7 +433,7 @@ while (cpu) { cpuid_t cpu_id; cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid); - if (cpu_enabled(cpu_id)) + if (cpu_online(cpu_id)) klhwg_add_cpu(node_vertex, cnode, cpu); else klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot); @@ -466,12 +456,12 @@ /* ARGSUSED */ void -klhwg_add_all_routers(devfs_handle_t hwgraph_root) +klhwg_add_all_routers(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; lboard_t *brd; - devfs_handle_t node_vertex; + vertex_hdl_t node_vertex; char path_buffer[100]; int rv; @@ -525,14 +515,14 @@ /* ARGSUSED */ void -klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd, +klhwg_connect_one_router(vertex_hdl_t hwgraph_root, lboard_t *brd, cnodeid_t cnode, nasid_t nasid) { klrou_t *router; char path_buffer[50]; char dest_path[50]; - devfs_handle_t router_hndl; - devfs_handle_t dest_hndl; + vertex_hdl_t router_hndl; + vertex_hdl_t dest_hndl; int rc; int port; lboard_t *dest_brd; @@ -619,7 +609,7 @@ void -klhwg_connect_routers(devfs_handle_t hwgraph_root) +klhwg_connect_routers(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; @@ -652,15 +642,15 @@ void -klhwg_connect_hubs(devfs_handle_t hwgraph_root) +klhwg_connect_hubs(vertex_hdl_t hwgraph_root) { nasid_t nasid; cnodeid_t cnode; lboard_t *brd; klhub_t *hub; lboard_t *dest_brd; - devfs_handle_t hub_hndl; - devfs_handle_t dest_hndl; + vertex_hdl_t hub_hndl; + vertex_hdl_t dest_hndl; char path_buffer[50]; char dest_path[50]; graph_error_t rc; @@ -796,12 +786,12 @@ } void -klhwg_add_all_modules(devfs_handle_t hwgraph_root) +klhwg_add_all_modules(vertex_hdl_t hwgraph_root) { cmoduleid_t cm; char name[128]; - devfs_handle_t vhdl; - devfs_handle_t module_vhdl; + vertex_hdl_t vhdl; + vertex_hdl_t module_vhdl; int rc; char buffer[16]; @@ -837,12 +827,12 @@ } void -klhwg_add_all_nodes(devfs_handle_t hwgraph_root) +klhwg_add_all_nodes(vertex_hdl_t hwgraph_root) { cnodeid_t cnode; for (cnode = 0; cnode < numnodes; cnode++) { - klhwg_add_node(hwgraph_root, cnode, NULL); + klhwg_add_node(hwgraph_root, cnode); } for (cnode = 0; cnode < numnodes; cnode++) { diff -Nru a/arch/ia64/sn/io/sn2/l1.c b/arch/ia64/sn/io/sn2/l1.c --- a/arch/ia64/sn/io/sn2/l1.c Mon Feb 24 05:24:28 2003 +++ b/arch/ia64/sn/io/sn2/l1.c Mon May 19 05:42:56 2003 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -50,6 +51,9 @@ #define UART_BAUD_RATE 57600 +static int L1_connected; /* non-zero when interrupts are enabled */ + + int get_L1_baud(void) { @@ -62,7 +66,23 @@ int l1_get_intr_value( void ) { - return(0); + cpuid_t intr_cpuid; + nasid_t console_nasid; + int major, minor; + extern nasid_t get_console_nasid(void); + + /* if it is an old prom, run in poll mode */ + + major = sn_sal_rev_major(); + minor = sn_sal_rev_minor(); + if ( (major < 1) || ((major == 1) && (minor < 10)) ) { + /* before version 1.10 doesn't work */ + return (0); + } + + console_nasid = get_console_nasid(); + intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; + return CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); } /* Disconnect the callup functions - throw away interrupts */ @@ -74,19 +94,45 @@ /* Set up uart interrupt handling for this node's uart */ -void -l1_connect_intr(void *rx_notify, void *tx_notify) +int +l1_connect_intr(void *intr_func, void *arg, struct pt_regs *ep) { -#if 0 - // Will need code here for sn2 - something like this - console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()); - intr_connect_level(console_nodepda->node_first_cpu, - SGI_UART_VECTOR, INTPEND0_MAXMASK, - dummy_intr_func); - request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8), - intr_func, SA_INTERRUPT | SA_SHIRQ, - "l1_protocol_driver", (void *)sc); -#endif + cpuid_t intr_cpuid; + nasid_t console_nasid; + unsigned int console_irq; + int result; + extern int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t); + extern nasid_t get_console_nasid(void); + + + /* don't call to connect multiple times - we DON'T support changing the handler */ + + if ( !L1_connected ) { + L1_connected++; + console_nasid = get_console_nasid(); + intr_cpuid = NODEPDA(NASID_TO_COMPACT_NODEID(console_nasid))->node_first_cpu; + console_irq = CPU_VECTOR_TO_IRQ(intr_cpuid, SGI_UART_VECTOR); + result = intr_connect_level(intr_cpuid, SGI_UART_VECTOR, + 0 /*not used*/, 0 /*not used*/); + if (result != SGI_UART_VECTOR) { + if (result < 0) + printk(KERN_WARNING "L1 console driver : intr_connect_level failed %d\n", result); + else + printk(KERN_WARNING "L1 console driver : intr_connect_level returns wrong bit %d\n", result); + return (-1); + } + + result = request_irq(console_irq, intr_func, SA_INTERRUPT, + "SGI L1 console driver", (void *)arg); + if (result < 0) { + printk(KERN_WARNING "L1 console driver : request_irq failed %d\n", result); + return (-1); + } + + /* ask SAL to turn on interrupts in the UART itself */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + } + return (0); } @@ -195,7 +241,7 @@ int l1_serial_out( char *str, int len ) { - int counter = len; + int tmp; /* Ignore empty messages */ if ( len == 0 ) @@ -216,6 +262,8 @@ if ( IS_RUNNING_ON_SIMULATOR() ) { extern u64 master_node_bedrock_address; void early_sn_setup(void); + int counter = len; + if (!master_node_bedrock_address) early_sn_setup(); if ( master_node_bedrock_address != (u64)0 ) { @@ -237,8 +285,9 @@ } /* Attempt to write things out thru the sal */ - if ( ia64_sn_console_putb(str, len) ) - return(0); - - return((counter <= 0) ? 0 : (len - counter)); + if ( L1_connected ) + tmp = ia64_sn_console_xmit_chars(str, len); + else + tmp = ia64_sn_console_putb(str, len); + return ((tmp < 0) ? 0 : tmp); } diff -Nru a/arch/ia64/sn/io/sn2/l1_command.c b/arch/ia64/sn/io/sn2/l1_command.c --- a/arch/ia64/sn/io/sn2/l1_command.c Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/io/sn2/l1_command.c Fri May 16 04:18:17 2003 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -26,37 +25,6 @@ #include #include -#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */ -#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */ - -#define hub_cpu_get() 0 - -#define LBYTE(caddr) (*(char *) caddr) - -extern char *bcopy(const char * src, char * dest, int count); - -#define LDEBUG 0 - -/* - * ELSC data is in NVRAM page 7 at the following offsets. - */ - -#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */ -#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */ -#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */ -#define NVRAM_DBG2 0x706 /* physical XOR debug switches */ -#define NVRAM_CFG 0x707 /* ELSC Configuration info */ -#define NVRAM_MODULE 0x708 /* system module number */ -#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */ -#define NVRAM_PARTITION 0x70a /* module's partition id */ -#define NVRAM_DOMAIN 0x70b /* module's domain id */ -#define NVRAM_CLUSTER 0x70c /* module's cluster id */ -#define NVRAM_CELL 0x70d /* module's cellid */ - -#define NVRAM_MAGIC_NO 0x37 /* value of magic number */ -#define NVRAM_SIZE 16 /* 16 bytes in nvram */ - - /* elsc_display_line writes up to 12 characters to either the top or bottom * line of the L1 display. line points to a buffer containing the message * to be displayed. The zero-based line number is specified by lnum (so @@ -69,6 +37,7 @@ return 0; } + /* * iobrick routines */ @@ -88,9 +57,9 @@ if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) return( ELSC_ERROR_CMD_SEND ); - *rack = (result & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; - *bay = (result & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; - *brick_type = (result & L1_ADDR_TYPE_MASK) >> L1_ADDR_TYPE_SHFT; + *rack = (result & MODULE_RACK_MASK) >> MODULE_RACK_SHFT; + *bay = (result & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT; + *brick_type = (result & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT; *brick_type = toupper(*brick_type); return 0; @@ -99,14 +68,12 @@ int iomoduleid_get(nasid_t nasid) { - int result = 0; if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) return( ELSC_ERROR_CMD_SEND ); return result; - } int iobrick_module_get(nasid_t nasid) @@ -142,11 +109,15 @@ RACK_ADD_NUM(rack, t); switch( brick_type ) { - case 'I': + case L1_BRICKTYPE_IX: + brick_type = MODULE_IXBRICK; break; + case L1_BRICKTYPE_PX: + brick_type = MODULE_PXBRICK; break; + case L1_BRICKTYPE_I: brick_type = MODULE_IBRICK; break; - case 'P': + case L1_BRICKTYPE_P: brick_type = MODULE_PBRICK; break; - case 'X': + case L1_BRICKTYPE_X: brick_type = MODULE_XBRICK; break; } @@ -154,7 +125,7 @@ return ret; } -#ifdef CONFIG_PCI + /* * iobrick_module_get_nasid() returns a module_id which has the brick * type encoded in bits 15-12, but this is not the true brick type... @@ -179,29 +150,54 @@ /* convert to a module.h brick type */ for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == type ) + if( brick_types[t] == type ) { return t; + } } return -1; /* unknown brick */ } -#endif + int iobrick_module_get_nasid(nasid_t nasid) { int io_moduleid; -#ifdef PIC_LATER - uint rack, bay; + io_moduleid = iobrick_module_get(nasid); + return io_moduleid; +} + +/* + * given a L1 bricktype, return a bricktype string. This string is the + * string that will be used in the hwpath for I/O bricks + */ +char * +iobrick_L1bricktype_to_name(int type) +{ + switch (type) + { + default: + return("Unknown"); + + case L1_BRICKTYPE_X: + return("Xbrick"); - if (PEBRICK_NODE(nasid)) { - if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) { - printf("Could not read rack and bay location " - "of PEBrick at nasid %d\n", nasid); - } + case L1_BRICKTYPE_I: + return("Ibrick"); - io_moduleid = peer_iobrick_module_get(sc, rack, bay); + case L1_BRICKTYPE_P: + return("Pbrick"); + + case L1_BRICKTYPE_PX: + return("PXbrick"); + + case L1_BRICKTYPE_IX: + return("IXbrick"); + + case L1_BRICKTYPE_C: + return("Cbrick"); + + case L1_BRICKTYPE_R: + return("Rbrick"); } -#endif /* PIC_LATER */ - io_moduleid = iobrick_module_get(nasid); - return io_moduleid; } + diff -Nru a/arch/ia64/sn/io/sn2/ml_SN_init.c b/arch/ia64/sn/io/sn2/ml_SN_init.c --- a/arch/ia64/sn/io/sn2/ml_SN_init.c Mon Feb 24 05:21:39 2003 +++ b/arch/ia64/sn/io/sn2/ml_SN_init.c Mon May 19 05:42:20 2003 @@ -19,25 +19,12 @@ #include #include #include -#include -extern int numcpus; -extern char arg_maxnodes[]; extern cpuid_t master_procid; - -extern int hasmetarouter; - int maxcpus; -cpumask_t boot_cpumask; -hubreg_t region_mask = 0; - extern xwidgetnum_t hub_widget_id(nasid_t); -extern int valid_icache_reasons; /* Reasons to flush the icache */ -extern int valid_dcache_reasons; /* Reasons to flush the dcache */ -extern u_char miniroot; -extern volatile int need_utlbmiss_patch; extern void iograph_early_init(void); nasid_t master_nasid = INVALID_NASID; /* This is the partition master nasid */ @@ -75,9 +62,6 @@ /* early initialization of iograph */ iograph_early_init(); - - /* Initialize Hub Pseudodriver Management */ - hubdev_init(); } @@ -121,16 +105,6 @@ npda->geoid.any.type = GEO_TYPE_INVALID; mutex_init_locked(&npda->xbow_sema); /* init it locked? */ -} - -/* XXX - Move the interrupt stuff to intr.c ? */ -/* - * Set up the platform-dependent fields in the processor pda. - * Must be done _after_ init_platform_nodepda(). - * If we need a lock here, something else is wrong! - */ -void init_platform_pda(cpuid_t cpu) -{ } void diff -Nru a/arch/ia64/sn/io/sn2/ml_SN_intr.c b/arch/ia64/sn/io/sn2/ml_SN_intr.c --- a/arch/ia64/sn/io/sn2/ml_SN_intr.c Tue Dec 3 10:07:27 2002 +++ b/arch/ia64/sn/io/sn2/ml_SN_intr.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ /* @@ -40,11 +40,14 @@ #include #include -extern irqpda_t *irqpdaindr[]; -extern cnodeid_t master_node_get(devfs_handle_t vhdl); +extern irqpda_t *irqpdaindr; +extern cnodeid_t master_node_get(vertex_hdl_t vhdl); extern nasid_t master_nasid; // Initialize some shub registers for interrupts, both IO and error. +// + + void intr_init_vecblk( nodepda_t *npda, @@ -58,6 +61,8 @@ nodepda_t *lnodepda; sh_ii_int0_enable_u_t ii_int_enable; sh_int_node_id_config_u_t node_id_config; + sh_local_int5_config_u_t local5_config; + sh_local_int5_enable_u_t local5_enable; extern void sn_init_cpei_timer(void); static int timer_added = 0; @@ -93,6 +98,19 @@ HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); + // Config and enable UART interrupt, all nodes. + + local5_config.sh_local_int5_config_regval = 0; + local5_config.sh_local_int5_config_s.idx = SGI_UART_VECTOR; + local5_config.sh_local_int5_config_s.pid = cpu0; + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_CONFIG), + local5_config.sh_local_int5_config_regval); + + local5_enable.sh_local_int5_enable_regval = 0; + local5_enable.sh_local_int5_enable_s.uart_int = 1; + HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), + local5_enable.sh_local_int5_enable_regval); + // The II_INT_CONFIG register for cpu 0. ii_int_config.sh_ii_int0_config_regval = 0; @@ -119,13 +137,6 @@ // Enable interrupts for II_INT0 and 1. ii_int_enable.sh_ii_int0_enable_regval = 0; ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; -#ifdef BUS_INT_WAR - /* Dont enable any ints from II. We will poll for interrupts. */ - ii_int_enable.sh_ii_int0_enable_s.ii_enable = 0; - - /* Enable IPIs. We use them ONLY for send INITs to hung cpus */ - *(volatile long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT_ENABLE) = 1; -#endif HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), ii_int_enable.sh_ii_int0_enable_regval); @@ -147,7 +158,8 @@ int reserve) { int i; - irqpda_t *irqs = irqpdaindr[cpu]; + irqpda_t *irqs = irqpdaindr; + int min_shared; if (reserve) { if (bit < 0) { @@ -158,8 +170,32 @@ } } } - if (bit < 0) { - return -1; + if (bit < 0) { /* ran out of irqs. Have to share. This will be rare. */ + min_shared = 256; + for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { + /* Share with the same device class */ + if (irqpdaindr->current->vendor == irqpdaindr->device_dev[i]->vendor && + irqpdaindr->current->device == irqpdaindr->device_dev[i]->device && + irqpdaindr->share_count[i] < min_shared) { + min_shared = irqpdaindr->share_count[i]; + bit = i; + } + } + min_shared = 256; + if (bit < 0) { /* didn't find a matching device, just pick one. This will be */ + /* exceptionally rare. */ + for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { + if (irqpdaindr->share_count[i] < min_shared) { + min_shared = irqpdaindr->share_count[i]; + bit = i; + } + } + } + irqpdaindr->share_count[bit]++; + } + if (irqs->irq_flags[bit] & SN2_IRQ_SHARED) { + irqs->irq_flags[bit] |= SN2_IRQ_RESERVED; + return bit; } if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) { return -1; @@ -183,7 +219,7 @@ intr_reserve_level(cpuid_t cpu, int bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name) { return(do_intr_reserve_level(cpu, bit, 1)); @@ -203,9 +239,13 @@ int bit, int connect) { - irqpda_t *irqs = irqpdaindr[cpu]; + irqpda_t *irqs = irqpdaindr; if (connect) { + if (irqs->irq_flags[bit] & SN2_IRQ_SHARED) { + irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED; + return bit; + } if (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED) { return -1; } else { @@ -248,24 +288,29 @@ int slice, min_count = 1000; irqpda_t *irqs; - for (slice = 0; slice < CPUS_PER_NODE; slice++) { + for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) { int intrs; cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == CPU_NONE) { + if (cpu == num_online_cpus()) { continue; } - if (!cpu_enabled(cpu)) { + if (!cpu_online(cpu)) { continue; } - irqs = irqpdaindr[cpu]; + irqs = irqpdaindr; intrs = irqs->num_irq_used; if (min_count > intrs) { min_count = intrs; best_cpu = cpu; + if ( enable_shub_wars_1_1() ) { + /* Rather than finding the best cpu, always return the first cpu*/ + /* This forces all interrupts to the same cpu */ + break; + } } } return best_cpu; @@ -285,7 +330,7 @@ cnodeid_t cnode, int req_bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name, int *resp_bit) { @@ -307,18 +352,18 @@ // Find the node to assign for this interrupt. cpuid_t -intr_heuristic(devfs_handle_t dev, +intr_heuristic(vertex_hdl_t dev, device_desc_t dev_desc, int req_bit, int resflags, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, char *name, int *resp_bit) { cpuid_t cpuid; cpuid_t candidate = CPU_NONE; cnodeid_t candidate_node; - devfs_handle_t pconn_vhdl; + vertex_hdl_t pconn_vhdl; pcibr_soft_t pcibr_soft; int bit; @@ -369,8 +414,8 @@ if (candidate != CPU_NONE) { printk("Cannot target interrupt to target node (%ld).\n",candidate); return CPU_NONE; } else { - printk("Cannot target interrupt to closest node (%d) 0x%p\n", - master_node_get(dev), (void *)owner_dev); + /* printk("Cannot target interrupt to closest node (%d) 0x%p\n", + master_node_get(dev), (void *)owner_dev); */ } // We couldn't put it on the closest node. Try to find another one. diff -Nru a/arch/ia64/sn/io/sn2/ml_iograph.c b/arch/ia64/sn/io/sn2/ml_iograph.c --- a/arch/ia64/sn/io/sn2/ml_iograph.c Mon Feb 24 05:24:56 2003 +++ b/arch/ia64/sn/io/sn2/ml_iograph.c Mon May 19 05:42:20 2003 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -43,8 +42,6 @@ /* At most 2 hubs can be connected to an xswitch */ #define NUM_XSWITCH_VOLUNTEER 2 -extern unsigned char Is_pic_on_this_nasid[512]; - /* * Track which hubs have volunteered to manage devices hanging off of * a Crosstalk Switch (e.g. xbow). This structure is allocated, @@ -54,11 +51,11 @@ typedef struct xswitch_vol_s { mutex_t xswitch_volunteer_mutex; int xswitch_volunteer_count; - devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; + vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; } *xswitch_vol_t; void -xswitch_vertex_init(devfs_handle_t xswitch) +xswitch_vertex_init(vertex_hdl_t xswitch) { xswitch_vol_t xvolinfo; int rc; @@ -78,7 +75,7 @@ * xswitch volunteer structure hanging around. Destroy it. */ static void -xswitch_volunteer_delete(devfs_handle_t xswitch) +xswitch_volunteer_delete(vertex_hdl_t xswitch) { xswitch_vol_t xvolinfo; int rc; @@ -94,10 +91,10 @@ */ /* ARGSUSED */ static void -volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) +volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master) { xswitch_vol_t xvolinfo = NULL; - devfs_handle_t hubv; + vertex_hdl_t hubv; hubinfo_t hubinfo; (void)hwgraph_info_get_LBL(xswitch, @@ -140,7 +137,7 @@ */ /* ARGSUSED */ static void -assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) +assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv) { xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; @@ -223,18 +220,6 @@ bt = iobrick_type_get_nasid(nasid); if (bt >= 0) { - /* - * PXBRICK has two busses per widget so this - * algorithm wouldn't work (all busses would - * be assigned to one volunteer). Change the - * bricktype to PBRICK whose mapping is setup - * suchthat 2 of the PICs will be assigned to - * one volunteer and the other one will be - * assigned to the other volunteer. - */ - if (bt == MODULE_PXBRICK) - bt = MODULE_PBRICK; - i = io_brick_map_widget(bt, widgetnum) & 1; } } @@ -281,8 +266,6 @@ DBG("iograph_early_init: Found board 0x%p\n", board); } } - - hubio_init(); } /* @@ -307,7 +290,7 @@ * hwid for our use. */ static void -early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) +early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) { hubreg_t llp_csr_reg; nasid_t nasid; @@ -351,7 +334,7 @@ * added as inventory information. */ static void -xwidget_inventory_add(devfs_handle_t widgetv, +xwidget_inventory_add(vertex_hdl_t widgetv, lboard_t *board, struct xwidget_hwid_s hwid) { @@ -374,14 +357,13 @@ */ void -io_xswitch_widget_init(devfs_handle_t xswitchv, - devfs_handle_t hubv, - xwidgetnum_t widgetnum, - async_attach_t aa) +io_xswitch_widget_init(vertex_hdl_t xswitchv, + vertex_hdl_t hubv, + xwidgetnum_t widgetnum) { xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; - devfs_handle_t widgetv; + vertex_hdl_t widgetv; cnodeid_t cnode; widgetreg_t widget_id; nasid_t nasid, peer_nasid; @@ -427,6 +409,7 @@ char name[4]; lboard_t dummy; + /* * If the current hub is not supposed to be the master * for this widgetnum, then skip this widget. @@ -470,12 +453,15 @@ memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%cbrick" "/%s/%d", + + sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d", buffer, geo_slab(board->brd_geoid), - (board->brd_type == KLTYPE_IBRICK) ? 'I' : - (board->brd_type == KLTYPE_PBRICK) ? 'P' : - (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', + (board->brd_type == KLTYPE_IBRICK) ? EDGE_LBL_IBRICK : + (board->brd_type == KLTYPE_PBRICK) ? EDGE_LBL_PBRICK : + (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK : + (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK : + (board->brd_type == KLTYPE_XBRICK) ? EDGE_LBL_XBRICK : "?brick", EDGE_LBL_XTALK, widgetnum); DBG("io_xswitch_widget_init: path= %s\n", pathname); @@ -514,36 +500,46 @@ xwidget_inventory_add(widgetv,board,hwid); (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid, - aa); + hubv, hub_widgetid); ia64_sn_sysctl_iobrick_module_get(nasid, &io_module); if (io_module >= 0) { char buffer[16]; - devfs_handle_t to, from; + vertex_hdl_t to, from; + char *brick_name; + extern char *iobrick_L1bricktype_to_name(int type); + memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - bt = toupper(MODULE_GET_BTCHAR(io_module)); + if ( islower(MODULE_GET_BTCHAR(io_module)) ) { + bt = toupper(MODULE_GET_BTCHAR(io_module)); + } + else { + bt = MODULE_GET_BTCHAR(io_module); + } + + brick_name = iobrick_L1bricktype_to_name(bt); + /* Add a helper vertex so xbow monitoring * can identify the brick type. It's simply * an edge from the widget 0 vertex to the * brick vertex. */ - sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/" "0", buffer, geo_slab(board->brd_geoid)); from = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(from); - sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/" + sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" - "%cbrick", - buffer, geo_slab(board->brd_geoid), bt); + "%s", + buffer, geo_slab(board->brd_geoid), brick_name); to = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(to); @@ -566,12 +562,9 @@ static void -io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode) +io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode) { xwidgetnum_t widgetnum; - async_attach_t aa; - - aa = async_attach_new(); DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); @@ -579,13 +572,8 @@ widgetnum++) { io_xswitch_widget_init(xswitchv, cnodeid_to_vertex(cnode), - widgetnum, aa); + widgetnum); } - /* - * Wait for parallel attach threads, if any, to complete. - */ - async_attach_waitall(aa); - async_attach_free(aa); } /* @@ -595,11 +583,11 @@ * graph and risking hangs. */ static void -io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid) +io_link_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnodeid) { xwidgetnum_t widgetnum; char pathname[128]; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; nasid_t nasid, peer_nasid; lboard_t *board; @@ -638,21 +626,12 @@ return; } - if ( Is_pic_on_this_nasid[nasid] ) { - /* Check both buses */ - sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else { - sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); - if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) - board->brd_graph_link = vhdl; - else - board->brd_graph_link = GRAPH_VERTEX_NONE; - } - } + /* Check both buses */ + sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); + if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) + board->brd_graph_link = vhdl; else { - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); + sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS) board->brd_graph_link = vhdl; else @@ -668,16 +647,14 @@ io_init_node(cnodeid_t cnodeid) { /*REFERENCED*/ - devfs_handle_t hubv, switchv, widgetv; + vertex_hdl_t hubv, switchv, widgetv; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; int is_xswitch; nodepda_t *npdap; struct semaphore *peer_sema = 0; uint32_t widget_partnum; - nodepda_router_info_t *npda_rip; cpu_cookie_t c = 0; - extern int hubdev_docallouts(devfs_handle_t); npdap = NODEPDA(cnodeid); @@ -693,23 +670,6 @@ ASSERT(hubv != GRAPH_VERTEX_NONE); - hubdev_docallouts(hubv); - - /* - * Set up the dependent routers if we have any. - */ - npda_rip = npdap->npda_rip_first; - - while(npda_rip) { - /* If the router info has not been initialized - * then we need to do the router initialization - */ - if (!npda_rip->router_infop) { - router_init(cnodeid,0,npda_rip); - } - npda_rip = npda_rip->router_next; - } - /* * Read mfg info on this hub */ @@ -833,7 +793,7 @@ */ hubinfo_get(hubv, &hubinfo); - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL); + (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid); if (!is_xswitch) { /* io_init_done takes cpu cookie as 2nd argument @@ -915,231 +875,9 @@ * XXX Irix legacy..controller numbering should be part of devfsd's job */ int num_base_io_scsi_ctlr = 2; /* used by syssgi */ -devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR]; -static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl; - -/* - * Put the logical controller number information in the - * scsi controller vertices for each scsi controller that - * is in a "fixed position". - */ -static void -scsi_ctlr_nums_add(devfs_handle_t pci_vhdl) -{ - { - int i; - - num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR; - - /* Initialize base_io_scsi_ctlr_vhdl array */ - for (i=0; i -devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE; - -/* Define the system critical vertices and connect them through - * a canonical parent-child relationships for easy traversal - * during io error handling. - */ -static void -sys_critical_graph_init(void) -{ - devfs_handle_t bridge_vhdl,master_node_vhdl; - devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE; - extern devfs_handle_t hwgraph_root; - devfs_handle_t pci_slot_conn; - int slot; - devfs_handle_t baseio_console_conn; - - DBG("sys_critical_graph_init: FIXME.\n"); - baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl); - - if (baseio_console_conn == NULL) { - return; - } - - /* Get the vertex handle for the baseio bridge */ - bridge_vhdl = device_master_get(baseio_console_conn); - - /* Get the master node of the baseio card */ - master_node_vhdl = cnodeid_to_vertex( - master_node_get(baseio_console_vhdl)); - - /* Add the "root->node" part of the system critical graph */ - - sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl); - - /* Check if we have a crossbow */ - if (hwgraph_traverse(master_node_vhdl, - EDGE_LBL_XTALK"/0", - &xbow_vhdl) == GRAPH_SUCCESS) { - /* We have a crossbow.Add "node->xbow" part of the system - * critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl); - - /* Add "xbow->baseio bridge" of the system critical graph */ - sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl); - - hwgraph_vertex_unref(xbow_vhdl); - } else - /* We donot have a crossbow. Add "node->baseio_bridge" - * part of the system critical graph. - */ - sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl); - - /* Add all the populated PCI slot vertices to the system critical - * graph with the bridge vertex as the parent. - */ - for (slot = 0 ; slot < 8; slot++) { - char slot_edge[10]; - - sprintf(slot_edge,"%d",slot); - if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn) - != GRAPH_SUCCESS) - continue; - sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn); - hwgraph_vertex_unref(pci_slot_conn); - } - - hwgraph_vertex_unref(bridge_vhdl); - - /* Add the "ioc3 pci connection point -> console ioc3" part - * of the system critical graph - */ - - if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_console_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "ethernet pci connection point -> base ethernet" part of - * the system critical graph - */ - if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) == - GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - baseio_enet_vhdl); - hwgraph_vertex_unref(pci_slot_conn); - } - - /* Add the "scsi controller pci connection point -> base scsi - * controller" part of the system critical graph - */ - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[0]); - hwgraph_vertex_unref(pci_slot_conn); - } - if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1], - "../..",&pci_slot_conn) == GRAPH_SUCCESS) { - sys_critical_graph_vertex_add(pci_slot_conn, - base_io_scsi_ctlr_vhdl[1]); - hwgraph_vertex_unref(pci_slot_conn); - } - hwgraph_vertex_unref(baseio_console_conn); - -} - -static void -baseio_ctlr_num_set(void) -{ - char name[MAXDEVNAME]; - devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl; - devfs_handle_t ioc3_console_vhdl_get(void); - - - DBG("baseio_ctlr_num_set; FIXME\n"); - console_vhdl = ioc3_console_vhdl_get(); - if (console_vhdl == GRAPH_VERTEX_NONE) - return; - /* Useful for setting up the system critical graph */ - baseio_console_vhdl = console_vhdl; - - vertex_to_name(console_vhdl,name,MAXDEVNAME); - - strcat(name,__DEVSTR1); - pci_vhdl = hwgraph_path_to_vertex(name); - scsi_ctlr_nums_add(pci_vhdl); - /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(pci_vhdl); - - vertex_to_name(console_vhdl, name, MAXDEVNAME); - strcat(name, __DEVSTR4); - enet_vhdl = hwgraph_path_to_vertex(name); - - /* Useful for setting up the system critical graph */ - baseio_enet_vhdl = enet_vhdl; - - device_controller_num_set(enet_vhdl, 0); - /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex - */ - hwgraph_vertex_unref(enet_vhdl); -} /* #endif */ /* @@ -1168,13 +906,6 @@ */ update_node_information(cnodeid); - baseio_ctlr_num_set(); - /* Setup the system critical graph (which is a subgraph of the - * main hwgraph). This information is useful during io error - * handling. - */ - sys_critical_graph_init(); - #if HWG_PRINT hwgraph_print(); #endif @@ -1300,6 +1031,20 @@ } }, +/* IXbrick widget number to PCI bus number map */ + { MODULE_IXBRICK, /* IXbrick type */ + /* PCI Bus # Widget # */ + { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ + 0, /* 0x8 */ + 0, /* 0x9 */ + 0, 0, /* 0xa - 0xb */ + 1, /* 0xc */ + 5, /* 0xd */ + 0, /* 0xe */ + 3 /* 0xf */ + } + }, + /* Xbrick widget to XIO slot map */ { MODULE_XBRICK, /* Xbrick type */ /* XIO Slot # Widget # */ @@ -1333,63 +1078,5 @@ } return 0; - -} - -/* - * Use the device's vertex to map the device's widget to a meaningful int - */ -int -io_path_map_widget(devfs_handle_t vertex) -{ - char hw_path_name[MAXDEVNAME]; - char *wp, *bp, *sp = NULL; - int widget_num; - long atoi(char *); - int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); - - - /* Get the full path name of the vertex */ - if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name, - MAXDEVNAME)) - return 0; - - /* Find the widget number in the path name */ - wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/"); - if (wp == NULL) - return 0; - widget_num = atoi(wp+7); - if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F) - return 0; - - /* Find "brick" in the path name */ - bp = strstr(hw_path_name, "brick"); - if (bp == NULL) - return 0; - - /* Find preceding slash */ - sp = bp; - while (sp > hw_path_name) { - sp--; - if (*sp == '/') - break; - } - - /* Invalid if no preceding slash */ - if (!sp) - return 0; - - /* Bump slash pointer to "brick" prefix */ - sp++; - /* - * Verify "brick" prefix length; valid exaples: - * 'I' from "/Ibrick" - * 'P' from "/Pbrick" - * 'X' from "/Xbrick" - */ - if ((bp - sp) != 1) - return 0; - - return (io_brick_map_widget((int)*sp, widget_num)); } diff -Nru a/arch/ia64/sn/io/sn2/module.c b/arch/ia64/sn/io/sn2/module.c --- a/arch/ia64/sn/io/sn2/module.c Mon Feb 24 05:25:25 2003 +++ b/arch/ia64/sn/io/sn2/module.c Fri May 16 04:18:17 2003 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c b/arch/ia64/sn/io/sn2/pci_bus_cvlink.c --- a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Wed Jun 4 07:34:30 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,719 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int bridge_rev_b_data_check_disable; - -devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; -nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; -void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; -unsigned char num_bridges; -static int done_probing = 0; - -static int pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid); -devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -extern unsigned char Is_pic_on_this_nasid[512]; - -extern void sn_init_irq_desc(void); -extern void register_pcibr_intr(int irq, pcibr_intr_t intr); - - -/* - * For the given device, initialize whether it is a PIC device. - */ -static void -set_isPIC(struct sn_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);; -} - -/* - * pci_bus_cvlink_init() - To be called once during initialization before - * SGI IO Infrastructure init is called. - */ -void -pci_bus_cvlink_init(void) -{ - - extern void ioconfig_bus_init(void); - - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET); - memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); - - memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); - - num_bridges = 0; - - ioconfig_bus_init(); -} - -/* - * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated - * pci bus vertex from the SGI IO Infrastructure. - */ -devfs_handle_t -pci_bus_to_vertex(unsigned char busnum) -{ - - devfs_handle_t pci_bus = NULL; - - - /* - * First get the xwidget vertex. - */ - pci_bus = busnum_to_pcibr_vhdl[busnum]; - return(pci_bus); -} - -/* - * devfn_to_vertex() - returns the vertex of the device given the bus, slot, - * and function numbers. - */ -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn) -{ - - int slot = 0; - int func = 0; - char name[16]; - devfs_handle_t pci_bus = NULL; - devfs_handle_t device_vertex = (devfs_handle_t)NULL; - - /* - * Go get the pci bus vertex. - */ - pci_bus = pci_bus_to_vertex(busnum); - if (!pci_bus) { - /* - * During probing, the Linux pci code invents non existant - * bus numbers and pci_dev structures and tries to access - * them to determine existance. Don't crib during probing. - */ - if (done_probing) - printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); - return(NULL); - } - - - /* - * Go get the slot&function vertex. - * Should call pciio_slot_func_to_name() when ready. - */ - slot = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); - - /* - * For a NON Multi-function card the name of the device looks like: - * ../pci/1, ../pci/2 .. - */ - if (func == 0) { - sprintf(name, "%d", slot); - if (hwgraph_traverse(pci_bus, name, &device_vertex) == - GRAPH_SUCCESS) { - if (device_vertex) { - return(device_vertex); - } - } - } - - /* - * This maybe a multifunction card. It's names look like: - * ../pci/1a, ../pci/1b, etc. - */ - sprintf(name, "%d%c", slot, 'a'+func); - if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { - if (!device_vertex) { - return(NULL); - } - } - - return(device_vertex); -} - -/* - * For the given device, initialize the addresses for both the Device(x) Flush - * Write Buffer register and the Xbow Flush Register for the port the PCI bus - * is connected. - */ -static void -set_flush_addresses(struct pci_dev *device_dev, - struct sn_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - bridge_t *bridge = pcibr_soft->bs_base; - nasid_t nasid; - - /* - * Get the nasid from the bridge. - */ - nasid = NASID_GET(device_sysdata->dma_buf_sync); - if (IS_PIC_DEVICE(device_dev)) { - device_sysdata->dma_buf_sync = (volatile unsigned int *) - &bridge->b_wr_req_buf[pciio_slot].reg; - device_sysdata->xbow_buf_sync = (volatile unsigned int *) - XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(nasid, 0), - pcibr_soft->bs_xid); - } else { - /* - * Accessing Xbridge and Xbow register when SHUB swapoper is on!. - */ - device_sysdata->dma_buf_sync = (volatile unsigned int *) - ((uint64_t)&(bridge->b_wr_req_buf[pciio_slot].reg)^4); - device_sysdata->xbow_buf_sync = (volatile unsigned int *) - ((uint64_t)(XBOW_PRIO_LINKREGS_PTR( - NODE_SWIN_BASE(nasid, 0), pcibr_soft->bs_xid)) ^ 4); - } - -#ifdef DEBUG - printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", - device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync); - -printk("set_flush_addresses: dma_buf_sync\n"); - while((volatile unsigned int )*device_sysdata->dma_buf_sync); -printk("set_flush_addresses: xbow_buf_sync\n"); - while((volatile unsigned int )*device_sysdata->xbow_buf_sync); -#endif - -} - -/* - * Most drivers currently do not properly tell the arch specific pci dma - * interfaces whether they can handle A64. Here is where we privately - * keep track of this. - */ -static void __init -set_sn_pci64(struct pci_dev *dev) -{ - unsigned short vendor = dev->vendor; - unsigned short device = dev->device; - - if (vendor == PCI_VENDOR_ID_QLOGIC) { - if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) || - (device == PCI_DEVICE_ID_QLOGIC_ISP2200)) { - SET_PCIA64(dev); - return; - } - } - - if (vendor == PCI_VENDOR_ID_SGI) { - if (device == PCI_DEVICE_ID_SGI_IOC3) { - SET_PCIA64(dev); - return; - } - } - -} - -/* - * sn_pci_fixup() - This routine is called when platform_pci_fixup() is - * invoked at the end of pcibios_init() to link the Linux pci - * infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c - * - * Other platform specific fixup can also be done here. - */ -void -sn_pci_fixup(int arg) -{ - struct list_head *ln; - struct pci_bus *pci_bus = NULL; - struct pci_dev *device_dev = NULL; - struct sn_widget_sysdata *widget_sysdata; - struct sn_device_sysdata *device_sysdata; - pciio_intr_t intr_handle; - int cpuid, bit; - devfs_handle_t device_vertex; - pciio_intr_line_t lines; - extern void sn_pci_find_bios(void); - extern int numnodes; - int cnode; - extern void io_sh_swapper(int, int); - - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 0); - } - - if (arg == 0) { -#ifdef CONFIG_PROC_FS - extern void register_sn_procfs(void); -#endif - - sn_init_irq_desc(); - sn_pci_find_bios(); - for (cnode = 0; cnode < numnodes; cnode++) { - extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); - intr_init_vecblk(NODEPDA(cnode), cnode, 0); - } - - /* - * When we return to generic Linux, Swapper is always on .. - */ - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 1); - } -#ifdef CONFIG_PROC_FS - register_sn_procfs(); -#endif - return; - } - - - done_probing = 1; - - /* - * Initialize the pci bus vertex in the pci_bus struct. - */ - for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - pci_bus = pci_bus_b(ln); - widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), - GFP_KERNEL); - widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number); - pci_bus->sysdata = (void *)widget_sysdata; - } - - /* - * set the root start and end so that drivers calling check_region() - * won't see a conflict - */ - ioport_resource.start = 0xc000000000000000; - ioport_resource.end = 0xcfffffffffffffff; - - /* - * Initialize the device vertex in the pci_dev struct. - */ - while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { - unsigned int irq; - int idx; - u16 cmd; - devfs_handle_t vhdl; - unsigned long size; - extern int bit_pos_to_irq(int); - - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3) { - extern void pci_fixup_ioc3(struct pci_dev *d); - pci_fixup_ioc3(device_dev); - } - - /* Set the device vertex */ - - device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), - GFP_KERNEL); - device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn); - device_sysdata->isa64 = 0; - /* - * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush - * register addresses. - */ - (void) set_flush_addresses(device_dev, device_sysdata); - - device_dev->sysdata = (void *) device_sysdata; - set_sn_pci64(device_dev); - set_isPIC(device_sysdata); - - pci_read_config_word(device_dev, PCI_COMMAND, &cmd); - - /* - * Set the resources address correctly. The assumption here - * is that the addresses in the resource structure has been - * read from the card and it was set in the card by our - * Infrastructure .. - */ - vhdl = device_sysdata->vhdl; - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - size = 0; - size = device_dev->resource[idx].end - - device_dev->resource[idx].start; - if (size) { - device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); - device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET; - } - else - continue; - - device_dev->resource[idx].end = - device_dev->resource[idx].start + size; - - if (device_dev->resource[idx].flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - - if (device_dev->resource[idx].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } -#if 0 - /* - * Software WAR for a Software BUG. - * This is only temporary. - * See PV 872791 - */ - - /* - * Now handle the ROM resource .. - */ - size = device_dev->resource[PCI_ROM_RESOURCE].end - - device_dev->resource[PCI_ROM_RESOURCE].start; - - if (size) { - device_dev->resource[PCI_ROM_RESOURCE].start = - (unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, - size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM); - device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET; - device_dev->resource[PCI_ROM_RESOURCE].end = - device_dev->resource[PCI_ROM_RESOURCE].start + size; - } -#endif - - /* - * Update the Command Word on the Card. - */ - cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ - /* bit gets dropped .. no harm */ - pci_write_config_word(device_dev, PCI_COMMAND, cmd); - - pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); - if (device_dev->vendor == PCI_VENDOR_ID_SGI && - device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) { - lines = 1; - } - - device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata; - device_vertex = device_sysdata->vhdl; - - intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex); - - bit = intr_handle->pi_irq; - cpuid = intr_handle->pi_cpu; - irq = bit; - irq = irq + (cpuid << 8); - pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0); - device_dev->irq = irq; - register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); -#ifdef ajmtestintr - { - int slot = PCI_SLOT(device_dev->devfn); - static int timer_set = 0; - pcibr_intr_t pcibr_intr = (pcibr_intr_t)intr_handle; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - extern void intr_test_handle_intr(int, void*, struct pt_regs *); - - if (!timer_set) { - intr_test_set_timer(); - timer_set = 1; - } - intr_test_register_irq(irq, pcibr_soft, slot); - request_irq(irq, intr_test_handle_intr,0,NULL, NULL); - } -#endif - - } - - for (cnode = 0; cnode < numnodes; cnode++) { - if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] ) - io_sh_swapper((cnodeid_to_nasid(cnode)), 1); - } -} - -/* - * linux_bus_cvlink() Creates a link between the Linux PCI Bus number - * to the actual hardware component that it represents: - * /dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci - * - * The bus vertex, when called to devfs_generate_path() returns: - * hw/module/001c01/slab/0/Ibrick/xtalk/15/pci - * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/0 - * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/1 - */ -void -linux_bus_cvlink(void) -{ - char name[8]; - int index; - - for (index=0; index < MAX_PCI_XWIDGET; index++) { - if (!busnum_to_pcibr_vhdl[index]) - continue; - - sprintf(name, "%x", index); - (void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], - name); - } -} - -/* - * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. - * - * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to - * HUB_WIDGET_ID_MIN: - * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. - * - * Given 2 modules 001c01 and 001c02 we get the following mappings: - * 001c01, widgetnum 15 = Bus number 0 - * 001c01, widgetnum 14 = Bus number 1 - * 001c02, widgetnum 15 = Bus number 3 - * 001c02, widgetnum 14 = Bus number 4 - * etc. - * - * The rational for starting Bus Number 0 with Widget number 15 is because - * the system boot disks are always connected via Widget 15 Slot 0 of the - * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 - * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest - * module id(Master Cnode) of the system. - * - */ -static int -pci_bus_map_create(devfs_handle_t xtalk, char * io_moduleid) -{ - - devfs_handle_t master_node_vertex = NULL; - devfs_handle_t xwidget = NULL; - devfs_handle_t pci_bus = NULL; - hubinfo_t hubinfo = NULL; - xwidgetnum_t widgetnum; - char pathname[128]; - graph_error_t rv; - int bus; - int basebus_num; - int bus_number; - - /* - * Loop throught this vertex and get the Xwidgets .. - */ - - - /* PCI devices */ - - for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) { - continue; - } - } - - sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) { - continue; -} - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - num_bridges++; - busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; - - /* - * Get the master node and from there get the NASID. - */ - master_node_vertex = device_master_get(xwidget); - if (!master_node_vertex) { - printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); - } - - hubinfo_get(master_node_vertex, &hubinfo); - if (!hubinfo) { - printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); - return(1); - } else { - busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; - } - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[num_bridges - 1]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); - - } - - /* - * PCIX devices - * We number busses differently for PCI-X devices. - * We start from Lowest Widget on up .. - */ - - (void) ioconfig_get_busnum((char *)io_moduleid, &basebus_num); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - - /* Do both buses */ - for ( bus = 0; bus < 2; bus++ ) { - sprintf(pathname, "%d", widgetnum); - xwidget = NULL; - - /* - * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget - * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus - * /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device - */ - rv = hwgraph_traverse(xtalk, pathname, &xwidget); - if ( (rv != GRAPH_SUCCESS) ) { - if (!xwidget) { - continue; - } - } - - if ( bus == 0 ) - sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum); - else - sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum); - pci_bus = NULL; - if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) - if (!pci_bus) { - continue; - } - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - * - * Should not be any race here ... - */ - bus_number = basebus_num + bus + io_brick_map_widget(MODULE_PXBRICK, widgetnum); -#ifdef DEBUG - printk("bus_number %d basebus_num %d bus %d io %d\n", - bus_number, basebus_num, bus, - io_brick_map_widget(MODULE_PXBRICK, widgetnum)); -#endif - busnum_to_pcibr_vhdl[bus_number] = pci_bus; - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[bus_number] = (void *) kmalloc( - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); - if (!busnum_to_atedmamaps[bus_number]) - printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); - - memset(busnum_to_atedmamaps[bus_number], 0x0, - sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); - } - } - - return(0); -} - -/* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between Xbridge - * and logical pci bus numbers. We also set up the NASID for each of these - * xbridges. - * - * Must be called before pci_init() is invoked. - */ -int -pci_bus_to_hcl_cvlink(void) -{ - - devfs_handle_t devfs_hdl = NULL; - devfs_handle_t xtalk = NULL; - int rv = 0; - char name[256]; - char tmp_name[256]; - int i, ii; - - /* - * Figure out which IO Brick is connected to the Compute Bricks. - */ - for (i = 0; i < nummodules; i++) { - extern int iomoduleid_get(nasid_t); - moduleid_t iobrick_id; - nasid_t nasid = -1; - int nodecnt; - int n = 0; - - nodecnt = modules[i]->nodecnt; - for ( n = 0; n < nodecnt; n++ ) { - nasid = cnodeid_to_nasid(modules[i]->nodes[n]); - iobrick_id = iomoduleid_get(nasid); - if ((int)iobrick_id > 0) { /* Valid module id */ - char name[12]; - memset(name, 0, 12); - format_module_id((char *)&(modules[i]->io[n].moduleid), iobrick_id, MODULE_FORMAT_BRIEF); - } - } - } - - devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module"); - for (i = 0; i < nummodules ; i++) { - for ( ii = 0; ii < 2 ; ii++ ) { - memset(name, 0, 256); - memset(tmp_name, 0, 256); - format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF); - sprintf(tmp_name, "/slab/%d/Pbrick/xtalk", geo_slab(modules[i]->geoid[ii])); - strcat(name, tmp_name); - xtalk = NULL; - rv = hwgraph_edge_get(devfs_hdl, name, &xtalk); - pci_bus_map_create(xtalk, (char *)&(modules[i]->io[ii].moduleid)); - } - } - - /* - * Create the Linux PCI bus number vertex link. - */ - (void)linux_bus_cvlink(); - (void)ioconfig_bus_new_entries(); - - return(0); -} diff -Nru a/arch/ia64/sn/io/sn2/pcibr/Makefile b/arch/ia64/sn/io/sn2/pcibr/Makefile --- a/arch/ia64/sn/io/sn2/pcibr/Makefile Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/Makefile Fri May 23 03:37:14 2003 @@ -11,11 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -ifdef CONFIG_IA64_SGI_SN2 -EXTRA_CFLAGS += -DSHUB_SWAP_WAR -endif - -obj-$(CONFIG_IA64_SGI_SN2) += pcibr_dvr.o pcibr_ate.o pcibr_config.o \ - pcibr_dvr.o pcibr_hints.o \ - pcibr_intr.o pcibr_rrb.o pcibr_slot.o \ - pcibr_error.o +obj-y += pcibr_ate.o pcibr_config.o pcibr_dvr.o pcibr_hints.o pcibr_intr.o pcibr_rrb.o \ + pcibr_slot.o pcibr_error.o diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Mon Feb 24 10:09:33 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -101,73 +100,26 @@ int i, j; bridgereg_t old_enable, new_enable; int s; - int this_is_pic = is_pic(bridge); /* Probe SSRAM to determine its size. */ - if ( this_is_pic ) { - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable)); - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable; - } - else { - old_enable = bridge->b_int_enable; - new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = new_enable; - } - } + old_enable = bridge->b_int_enable; + new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; + bridge->b_int_enable = new_enable; for (i = 1; i < ATE_NUM_SIZES; i++) { /* Try writing a value */ - if ( this_is_pic ) { - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE); - else - bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; - } + bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE; /* Guard against wrap */ for (j = 1; j < i; j++) bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0; /* See if value was written */ - if ( this_is_pic ) { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) + if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) largest_working_size = i; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE)) - largest_working_size = i; - else { - if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE) - largest_working_size = i; - } - } - } - } - if ( this_is_pic ) { - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable; - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */ - } - else { - bridge->b_int_enable = old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } } + bridge->b_int_enable = old_enable; + bridge->b_wid_tflush; /* wait until Bridge PIO complete */ /* * ensure that we write and read without any interruption. @@ -175,26 +127,10 @@ */ s = splhi(); - if ( this_is_pic ) { - bridge->b_wid_control = (bridge->b_wid_control + bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&(bridge->b_wid_control))) = - __swab32((BRIDGE_REG_GET32((&bridge->b_wid_control)) - & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size)); - BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */ - } - else { - bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK) - | BRIDGE_CTRL_SSRAM_SIZE(largest_working_size); - bridge->b_wid_control; /* inval addr bug war */ - } - } + bridge->b_wid_control; /* inval addr bug war */ splx(s); num_entries = ATE_NUM_ENTRIES(largest_working_size); @@ -423,16 +359,7 @@ /* Flush the write buffer associated with this * PCI device which might be using dma map RAM. */ - if ( is_pic(bridge) ) { - bridge->b_wr_req_buf[slot].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge)) ) { - BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg)); - } - else - bridge->b_wr_req_buf[slot].reg; - } + bridge->b_wr_req_buf[slot].reg; } } } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Tue Dec 3 10:07:27 2002 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -28,19 +28,16 @@ #include #include #include -#include #include #include -extern pcibr_info_t pcibr_info_get(devfs_handle_t); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); -uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); -void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); -void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); -static void swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); +uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); +uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); +void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); -#ifdef LITTLE_ENDIAN /* * on sn-ia we need to twiddle the the addresses going out * the pci bus because we use the unswizzled synergy space @@ -51,18 +48,13 @@ #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)]) #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)]) -#define CBP(b,r) (((volatile uint8_t *) b)[(r)^3]) -#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)^1]) +#define CBP(b,r) (((volatile uint8_t *) b)[(r)]) +#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)]) #define CWP(b,r) (((volatile uint32_t *) b)[(r)/4]) #define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)]) #define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)]) #define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)]) -#else -#define CB(b,r) (((volatile uint8_t *) cfgbase)[(r)^3]) -#define CS(b,r) (((volatile uint16_t *) cfgbase)[((r)/2)^1]) -#define CW(b,r) (((volatile uint32_t *) cfgbase)[(r)/4]) -#endif /* * Return a config space address for given slot / func / offset. Note the @@ -84,8 +76,7 @@ /* * Type 0 config space */ - if (is_pic(bridge)) - slot++; + slot++; return &bridge->b_type0_cfg_dev[slot].f[func].l[offset]; } @@ -109,7 +100,7 @@ cfg_p cfg_base; cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); + return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); } /* @@ -122,7 +113,7 @@ cfg_p cfg_base; cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); - return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned))); + return (do_pcibr_config_get(cfg_base, offset, sizeof(unsigned))); } /* @@ -135,7 +126,7 @@ cfg_p cfg_base; cfg_base = pcibr_slot_config_addr(bridge, slot, 0); - do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); + do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); } /* @@ -148,13 +139,13 @@ cfg_p cfg_base; cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0); - do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val); + do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); } int pcibr_config_debug = 0; cfg_p -pcibr_config_addr(devfs_handle_t conn, +pcibr_config_addr(vertex_hdl_t conn, unsigned reg) { pcibr_info_t pcibr_info; @@ -183,19 +174,6 @@ pciio_func = PCI_TYPE1_FUNC(reg); ASSERT(pciio_bus != 0); -#if 0 - } else if (conn != pciio_info_hostdev_get(pciio_info)) { - /* - * Conn is on a subordinate bus, so get bus/slot/func directly from - * its pciio_info_t structure. - */ - pciio_bus = pciio_info->c_bus; - pciio_slot = pciio_info->c_slot; - pciio_func = pciio_info->c_func; - if (pciio_func == PCIIO_FUNC_NONE) { - pciio_func = 0; - } -#endif } else { /* * Conn is directly connected to the host bus. PCI bus number is @@ -224,44 +202,23 @@ return cfgbase; } -extern unsigned char Is_pic_on_this_nasid[]; uint64_t -pcibr_config_get(devfs_handle_t conn, +pcibr_config_get(vertex_hdl_t conn, unsigned reg, unsigned size) { - if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) - return do_pcibr_config_get(0, pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); - else - return do_pcibr_config_get(1, pcibr_config_addr(conn, reg), + return do_pcibr_config_get(pcibr_config_addr(conn, reg), PCI_TYPE1_REG(reg), size); } uint64_t -do_pcibr_config_get( - int pic, - cfg_p cfgbase, +do_pcibr_config_get(cfg_p cfgbase, unsigned reg, unsigned size) { unsigned value; - if ( pic ) { - value = CWP(cfgbase, reg); - } - else { - if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) { - /* - * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped! - * Do not swizzle address and byte swap the result. - */ - value = SCW(cfgbase, reg); - value = __swab32(value); - } else { - value = CW(cfgbase, reg); - } - } + value = CWP(cfgbase, reg); if (reg & 3) value >>= 8 * (reg & 3); if (size < 4) @@ -270,108 +227,43 @@ } void -pcibr_config_set(devfs_handle_t conn, +pcibr_config_set(vertex_hdl_t conn, unsigned reg, unsigned size, uint64_t value) { - if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] ) - do_pcibr_config_set(1, pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); - else - swap_do_pcibr_config_set(pcibr_config_addr(conn, reg), + do_pcibr_config_set(pcibr_config_addr(conn, reg), PCI_TYPE1_REG(reg), size, value); } void -do_pcibr_config_set(int pic, - cfg_p cfgbase, +do_pcibr_config_set(cfg_p cfgbase, unsigned reg, unsigned size, uint64_t value) { - if ( pic ) { - switch (size) { - case 1: + switch (size) { + case 1: + CBP(cfgbase, reg) = value; + break; + case 2: + if (reg & 1) { CBP(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CBP(cfgbase, reg + 1) = value >> 8; - } else - CSP(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CSP(cfgbase, (reg + 1)) = value >> 8; - } else { - CSP(cfgbase, reg) = value; - CBP(cfgbase, reg + 2) = value >> 16; - } - break; - case 4: - CWP(cfgbase, reg) = value; - break; - } - } - else { - switch (size) { - case 1: - CB(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CB(cfgbase, reg) = value; - CB(cfgbase, reg + 1) = value >> 8; - } else - CS(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CB(cfgbase, reg) = value; - CS(cfgbase, (reg + 1)) = value >> 8; - } else { - CS(cfgbase, reg) = value; - CB(cfgbase, reg + 2) = value >> 16; - } - break; - case 4: - CW(cfgbase, reg) = value; - break; - } - } -} - -void -swap_do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - - uint64_t temp_value = 0; - - switch (size) { - case 1: - SCB(cfgbase, reg) = value; - break; - case 2: - temp_value = __swab16(value); - if (reg & 1) { - SCB(cfgbase, reg) = temp_value; - SCB(cfgbase, reg + 1) = temp_value >> 8; - } else - SCS(cfgbase, reg) = temp_value; - break; - case 3: - BUG(); - break; - - case 4: - temp_value = __swab32(value); - SCW(cfgbase, reg) = temp_value; - break; - } + CBP(cfgbase, reg + 1) = value >> 8; + } else + CSP(cfgbase, reg) = value; + break; + case 3: + if (reg & 1) { + CBP(cfgbase, reg) = value; + CSP(cfgbase, (reg + 1)) = value >> 8; + } else { + CSP(cfgbase, reg) = value; + CBP(cfgbase, reg + 2) = value >> 16; + } + break; + case 4: + CWP(cfgbase, reg) = value; + break; + } } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Tue Feb 25 10:47:06 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Fri May 23 03:37:38 2003 @@ -4,13 +4,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include +#include #include +#include #include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +31,6 @@ #include #include #include -#include #include #include @@ -74,32 +77,6 @@ #define USS302_BRIDGE_TIMEOUT_HLD 4 #endif -int pcibr_devflag = D_MP; - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations pcibr_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: NULL, - open: NULL, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL -}; - /* kbrick widgetnum-to-bus layout */ int p_busnum[MAX_PORT_NUM] = { /* widget# */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ @@ -116,17 +93,16 @@ pcibr_list_p pcibr_list = 0; #endif -extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen); -extern int hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags); +extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, uint buflen); extern long atoi(register char *p); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl); -extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen); +extern cnodeid_t nodevertex_to_cnodeid(vertex_hdl_t vhdl); +extern char *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen); extern struct map *atemapalloc(uint64_t); extern void atefree(struct map *, size_t, uint64_t); extern void atemapfree(struct map *); -extern pciio_dmamap_t get_free_pciio_dmamap(devfs_handle_t); +extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); extern void free_pciio_dmamap(pcibr_dmamap_t); -extern void xwidget_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); +extern void xwidget_error_register(vertex_hdl_t, error_handler_f *, error_handler_arg_t); #define ATE_WRITE() ate_write(pcibr_soft, ate_ptr, ate_count, ate) #if PCIBR_FREEZE_TIME @@ -153,9 +129,9 @@ extern int do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t); extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); -extern int pcibr_wrb_flush(devfs_handle_t); -extern int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -extern void pcibr_rrb_flush(devfs_handle_t); +extern int pcibr_wrb_flush(vertex_hdl_t); +extern int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); +extern void pcibr_rrb_flush(vertex_hdl_t); static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t); void pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t); @@ -166,21 +142,15 @@ extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); -void pcibr_init(void); -int pcibr_attach(devfs_handle_t); -int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, +int pcibr_attach(vertex_hdl_t); +int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, int, pcibr_soft_t *); -int pcibr_detach(devfs_handle_t); -int pcibr_open(devfs_handle_t *, int, int, cred_t *); -int pcibr_close(devfs_handle_t, int, int, cred_t *); -int pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int pcibr_unmap(devfs_handle_t, vhandl_t *); -int pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); +int pcibr_detach(vertex_hdl_t); int pcibr_pcix_rbars_calc(pcibr_soft_t); extern int pcibr_init_ext_ate_ram(bridge_t *); extern int pcibr_ate_alloc(pcibr_soft_t, int); extern void pcibr_ate_free(pcibr_soft_t, int, int); -extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); +extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap, #if PCIBR_FREEZE_TIME @@ -197,45 +167,43 @@ unsigned *cmd_regs, unsigned s); -pcibr_info_t pcibr_info_get(devfs_handle_t); +pcibr_info_t pcibr_info_get(vertex_hdl_t); -static iopaddr_t pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); +static iopaddr_t pcibr_addr_pci_to_xio(vertex_hdl_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); -pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); void pcibr_piomap_free(pcibr_piomap_t); caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); +caddr_t pcibr_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +iopaddr_t pcibr_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t); +void pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); extern bridge_ate_t pcibr_flags_to_ate(unsigned); -pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void pcibr_dmamap_free(pcibr_dmamap_t); extern bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); static iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -alenlist_t pcibr_dmamap_list(pcibr_dmamap_t, alenlist_t, unsigned); void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t); -iopaddr_t pcibr_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pcibr_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t); +iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pcibr_dmalist_drain(devfs_handle_t, alenlist_t); +void pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); +void pcibr_dmalist_drain(vertex_hdl_t, alenlist_t); iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); extern unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); -extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +extern pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); extern void pcibr_intr_free(pcibr_intr_t); extern void pcibr_setpciint(xtalk_intr_t); extern int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); extern void pcibr_intr_disconnect(pcibr_intr_t); -extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +extern vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); extern void pcibr_intr_func(intr_arg_t); extern void print_bridge_errcmd(uint32_t, char *); @@ -253,51 +221,48 @@ extern int pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *); -void pcibr_provider_startup(devfs_handle_t); -void pcibr_provider_shutdown(devfs_handle_t); +void pcibr_provider_startup(vertex_hdl_t); +void pcibr_provider_shutdown(vertex_hdl_t); -int pcibr_reset(devfs_handle_t); -pciio_endian_t pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); +int pcibr_reset(vertex_hdl_t); +pciio_endian_t pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); int pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t); -pciio_priority_t pcibr_priority_set(devfs_handle_t, pciio_priority_t); -int pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t); +pciio_priority_t pcibr_priority_set(vertex_hdl_t, pciio_priority_t); +int pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t); -extern cfg_p pcibr_config_addr(devfs_handle_t, unsigned); -extern uint64_t pcibr_config_get(devfs_handle_t, unsigned, unsigned); -extern void pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t); - -extern pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -extern void pcibr_hints_fix_rrbs(devfs_handle_t); -extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -extern void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -extern void pcibr_hints_handsoff(devfs_handle_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); - -extern int pcibr_slot_reset(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_info_init(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_info_free(devfs_handle_t,pciio_slot_t); +extern cfg_p pcibr_config_addr(vertex_hdl_t, unsigned); +extern uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); +extern void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); + +extern pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); +extern void pcibr_hints_fix_rrbs(vertex_hdl_t); +extern void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +extern void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); +extern void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); +extern void pcibr_hints_handsoff(vertex_hdl_t); +extern void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); + +extern int pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t); extern int pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t, pcibr_slot_info_resp_t); extern void pcibr_slot_func_info_return(pcibr_info_h, int, pcibr_slot_func_info_resp_t); -extern int pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t); extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); -extern int pcibr_slot_device_init(devfs_handle_t, pciio_slot_t); -extern int pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t); -extern int pcibr_slot_call_device_attach(devfs_handle_t, +extern int pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t); +extern int pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t); +extern int pcibr_slot_call_device_attach(vertex_hdl_t, pciio_slot_t, int); -extern int pcibr_slot_call_device_detach(devfs_handle_t, +extern int pcibr_slot_call_device_detach(vertex_hdl_t, pciio_slot_t, int); -extern int pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, +extern int pcibr_slot_attach(vertex_hdl_t, pciio_slot_t, int, char *, int *); -extern int pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int, +extern int pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int, char *, int *); -extern int pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t); - -extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t); -extern int pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t); +extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t, pciio_slot_t); +extern int pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, pciio_slot_t); /* ===================================================================== * Device(x) register management @@ -623,172 +588,47 @@ */ -/* - * pcibr_init: called once during system startup or - * when a loadable driver is loaded. - * - * The driver_register function should normally - * be in _reg, not _init. But the pcibr driver is - * required by devinit before the _reg routines - * are called, so this is an exception. - */ -void -pcibr_init(void) +static int +pcibr_mmap(struct file * file, struct vm_area_struct * vma) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pcibr_init()\n")); + vertex_hdl_t pcibr_vhdl = file->f_dentry->d_fsdata; + pcibr_soft_t pcibr_soft; + bridge_t *bridge; + unsigned long phys_addr; + int error = 0; - xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM, - XBRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); - xwidget_driver_register(BRIDGE_WIDGET_PART_NUM, - BRIDGE_WIDGET_MFGR_NUM, - "pcibr_", - 0); + pcibr_soft = pcibr_soft_get(pcibr_vhdl); + bridge = pcibr_soft->bs_base; + phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED | VM_IO; + error = io_remap_page_range(vma, phys_addr, vma->vm_start, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + return(error); } /* - * open/close mmap/munmap interface would be used by processes - * that plan to map the PCI bridge, and muck around with the - * registers. This is dangerous to do, and will be allowed - * to a select brand of programs. Typically these are - * diagnostics programs, or some user level commands we may - * write to do some weird things. - * To start with expect them to have root priveleges. - * We will ask for more later. + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. */ -/* ARGSUSED */ -int -pcibr_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -pcibr_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - int error; - devfs_handle_t vhdl = dev_to_vhdl(dev); - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get(vhdl); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - ASSERT(pcibr_soft); - len = ctob(btoc(len)); /* Make len page aligned */ - error = v_mapphys(vt, (void *) ((__psunsigned_t) bridge + off), len); - - /* - * If the offset being mapped corresponds to the flash prom - * base, and if the mapping succeeds, and if the user - * has requested the protections to be WRITE, enable the - * flash prom to be written. - * - * XXX- deprecate this in favor of using the - * real flash driver ... - */ - if (IS_BRIDGE_SOFT(pcibr_soft) && !error && - ((off == BRIDGE_EXTERNAL_FLASH) || - (len > BRIDGE_EXTERNAL_FLASH))) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_wid_control)) |= __swab32(BRIDGE_CTRL_FLASH_WR_EN); - BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ - } else { - bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - } - splx(s); - } - return error; -} - -/*ARGSUSED */ -int -pcibr_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - devfs_handle_t pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t) dev); - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge = pcibr_soft->bs_base; - - hwgraph_vertex_unref(pcibr_vhdl); - - if ( IS_PIC_SOFT(pcibr_soft) ) { - /* - * If flashprom write was enabled, disable it, as - * this is the last unmap. - */ - if (IS_BRIDGE_SOFT(pcibr_soft) && - (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN)) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - if (BRIDGE_REG_GET32((&bridge->b_wid_control)) & BRIDGE_CTRL_FLASH_WR_EN) { - int s; +static int pcibr_mmap(struct file * file, struct vm_area_struct * vma); +struct file_operations pcibr_fops = { + .owner = THIS_MODULE, + .mmap = pcibr_mmap, +}; - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - BRIDGE_REG_SET32((&bridge->b_wid_control)) &= __swab32((unsigned int)~BRIDGE_CTRL_FLASH_WR_EN); - BRIDGE_REG_GET32((&bridge->b_wid_control)); /* inval addr bug war */ - splx(s); - } else { - if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) { - int s; - - /* - * ensure that we write and read without any interruption. - * The read following the write is required for the Bridge war - */ - s = splhi(); - bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN; - bridge->b_wid_control; /* inval addr bug war */ - splx(s); - } - } - } - } - return 0; -} /* This is special case code used by grio. There are plans to make * this a bit more general in the future, but till then this should * be sufficient. */ pciio_slot_t -pcibr_device_slot_get(devfs_handle_t dev_vhdl) +pcibr_device_slot_get(vertex_hdl_t dev_vhdl) { char devname[MAXDEVNAME]; - devfs_handle_t tdev; + vertex_hdl_t tdev; pciio_info_t pciio_info; pciio_slot_t slot = PCIIO_SLOT_NONE; @@ -812,20 +652,8 @@ return slot; } -/*ARGSUSED */ -int -pcibr_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - return 0; -} - pcibr_info_t -pcibr_info_get(devfs_handle_t vhdl) +pcibr_info_get(vertex_hdl_t vhdl) { return (pcibr_info_t) pciio_info_get(vhdl); } @@ -902,10 +730,10 @@ * This is usually used at the time of shutting down of the PCI card. */ int -pcibr_device_unregister(devfs_handle_t pconn_vhdl) +pcibr_device_unregister(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; bridge_t *bridge; @@ -982,12 +810,12 @@ * slot's device status to be set. */ void -pcibr_driver_reg_callback(devfs_handle_t pconn_vhdl, +pcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error) { pciio_info_t pciio_info; pcibr_info_t pcibr_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; @@ -1033,12 +861,12 @@ * slot's device status to be set. */ void -pcibr_driver_unreg_callback(devfs_handle_t pconn_vhdl, +pcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl, int key1, int key2, int error) { pciio_info_t pciio_info; pcibr_info_t pcibr_info; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pciio_slot_t slot; pcibr_soft_t pcibr_soft; @@ -1084,14 +912,14 @@ * depends on hwgraph separator == '/' */ int -pcibr_bus_cnvlink(devfs_handle_t f_c) +pcibr_bus_cnvlink(vertex_hdl_t f_c) { char dst[MAXDEVNAME]; char *dp = dst; char *cp, *xp; int widgetnum; char pcibus[8]; - devfs_handle_t nvtx, svtx; + vertex_hdl_t nvtx, svtx; int rv; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n")); @@ -1145,11 +973,11 @@ */ /*ARGSUSED */ int -pcibr_attach(devfs_handle_t xconn_vhdl) +pcibr_attach(vertex_hdl_t xconn_vhdl) { /* REFERENCED */ graph_error_t rc; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; bridge_t *bridge; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n")); @@ -1180,11 +1008,11 @@ /*ARGSUSED */ int -pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, - devfs_handle_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) +pcibr_attach2(vertex_hdl_t xconn_vhdl, bridge_t *bridge, + vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) { /* REFERENCED */ - devfs_handle_t ctlr_vhdl; + vertex_hdl_t ctlr_vhdl; bridgereg_t id; int rev; pcibr_soft_t pcibr_soft; @@ -1193,7 +1021,7 @@ xtalk_intr_t xtalk_intr; int slot; int ibit; - devfs_handle_t noslot_conn; + vertex_hdl_t noslot_conn; char devnm[MAXDEVNAME], *s; pcibr_hints_t pcibr_hints; uint64_t int_enable; @@ -1209,23 +1037,15 @@ nasid_t nasid; int iobrick_type_get_nasid(nasid_t nasid); int iobrick_module_get_nasid(nasid_t nasid); - extern unsigned char Is_pic_on_this_nasid[512]; - - - async_attach_t aa = NULL; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum)); - aa = async_attach_get_info(xconn_vhdl); - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &pcibr_fops, NULL); - + ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, + 0, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + (struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl); ASSERT(ctlr_vhdl != NULL); /* @@ -1261,13 +1081,7 @@ pcibr_soft->bs_min_slot = 0; /* lowest possible slot# */ pcibr_soft->bs_max_slot = 7; /* highest possible slot# */ pcibr_soft->bs_busnum = busnum; - if (is_xbridge(bridge)) { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_XBRIDGE; - } else if (is_pic(bridge)) { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; - } else { - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_BRIDGE; - } + pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; switch(pcibr_soft->bs_bridge_type) { case PCIBR_BRIDGETYPE_BRIDGE: pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES; @@ -1367,10 +1181,6 @@ nasid = NASID_GET(bridge); - /* set whether it is a PIC or not */ - Is_pic_on_this_nasid[nasid] = (IS_PIC_SOFT(pcibr_soft)) ? 1 : 0; - - if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0) printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl, (unsigned int)pcibr_soft->bs_bricktype); @@ -1380,11 +1190,27 @@ if (pcibr_soft->bs_bricktype > 0) { switch (pcibr_soft->bs_bricktype) { case MODULE_PXBRICK: + case MODULE_IXBRICK: pcibr_soft->bs_first_slot = 0; pcibr_soft->bs_last_slot = 1; pcibr_soft->bs_last_reset = 1; + + /* If Bus 1 has IO9 then there are 4 devices in that bus. Note + * we figure this out from klconfig since the kernel has yet to + * probe + */ + if (pcibr_widget_to_bus(pcibr_vhdl) == 1) { + lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); + + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + pcibr_soft->bs_last_slot = 3; + pcibr_soft->bs_last_reset = 3; + } + brd = KLCF_NEXT(brd); + } + } break; - case MODULE_PEBRICK: case MODULE_PBRICK: pcibr_soft->bs_first_slot = 1; pcibr_soft->bs_last_slot = 2; @@ -1527,7 +1353,7 @@ /* enable parity checking on PICs internal RAM */ pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; - /* PIC BRINGUP WAR (PV# 862253): don't enable write request + /* PIC BRINGUP WAR (PV# 862253): dont enable write request * parity checking. */ if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { @@ -1559,11 +1385,6 @@ int entry; cnodeid_t cnodeid; nasid_t nasid; -#ifdef PIC_LATER - char *node_val; - devfs_handle_t node_vhdl; - char vname[MAXDEVNAME]; -#endif /* Set the Bridge's 32-bit PCI to XTalk * Direct Map register to the most useful @@ -1582,30 +1403,6 @@ */ cnodeid = 0; /* default node id */ - /* - * Determine the base address node id to be used for all 32-bit - * Direct Mapping I/O. The default is node 0, but this can be changed - * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE - * attribute in the irix.sm config file. A device driver can obtain - * this node value via a call to pcibr_get_dmatrans_node(). - */ -#ifdef PIC_LATER -// This probably needs to be addressed - pfg - node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE); - if (node_val != NULL) { - node_vhdl = hwgraph_path_to_vertex(node_val); - if (node_vhdl != GRAPH_VERTEX_NONE) { - cnodeid = nodevertex_to_cnodeid(node_vhdl); - } - if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) { - cnodeid = 0; - vertex_to_name(pcibr_vhdl, vname, sizeof(vname)); - printk(KERN_WARNING "Invalid hwgraph node path specified:\n" - " DEVICE_ADMIN: %s %s=%s\n", - vname, ADMIN_LBL_DMATRANS_NODE, node_val); - } - } -#endif /* PIC_LATER */ nasid = COMPACT_TO_NASID_NODEID(cnodeid); paddr = NODE_OFFSET(nasid) + 0; @@ -1763,6 +1560,13 @@ */ xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); + { + int irq = ((hub_intr_t)xtalk_intr)->i_bit; + int cpu = ((hub_intr_t)xtalk_intr)->i_cpuid; + + intr_unreserve_level(cpu, irq); + ((hub_intr_t)xtalk_intr)->i_bit = SGI_PCIBR_ERROR; + } ASSERT(xtalk_intr != NULL); pcibr_soft->bsi_err_intr = xtalk_intr; @@ -1778,12 +1582,8 @@ xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler, (intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge); -#ifdef BUS_INT_WAR_NOT_YET - request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, - ((hub_intr_t)xtalk_intr)->i_bit), - (intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error", + request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler, SA_SHIRQ, "PCIBR error", (intr_arg_t) pcibr_soft); -#endif PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, "pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n", @@ -1801,18 +1601,16 @@ if (IS_PIC_SOFT(pcibr_soft)) { int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS; int_enable = (uint64_t)int_enable_64; +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff7ffffeff; +#endif } else { int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff); int_enable = ((uint64_t)int_enable_32 & 0xffffffff); - } -#ifdef BUS_INT_WAR_NOT_YET - { - extern void sn_add_polled_interrupt(int irq, int interval); - - sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid, - ((hub_intr_t)xtalk_intr)->i_bit), 20000); - } +#ifdef PFG_TEST + int_enable = (uint64_t)0x7ffffeff; #endif + } #if BRIDGE_ERROR_INTR_WAR @@ -1849,24 +1647,6 @@ } #endif -#ifdef BRIDGE_B_DATACORR_WAR - - /* WAR panic for Rev B silent data corruption. - * PIOERR turned off here because there is a problem - * with not re-arming it in pcibr_error_intr_handler. - * We don't get LLP error interrupts if we don't - * re-arm PIOERR interrupts! Just disable them here - */ - - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) { - int_enable |= BRIDGE_IMR_LLP_REC_CBERR; - int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "Turning on LLP_REC_CBERR for Rev B Bridge.\n")); - } -#endif - /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are * locked out to be freed up sooner (by timing out) so that the * read tnums are never completely used up. @@ -1918,16 +1698,12 @@ if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_B) pcibr_soft->bs_dma_flags |= PCIBR_NOPREFETCH; else if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_prefetch_enable_rev)) + (BRIDGE_WIDGET_PART_NUM << 4)) pcibr_soft->bs_dma_flags |= PCIIO_NOPREFETCH; - /* WRITE_GATHER: - * Disabled up to but not including the - * rev number in pcibr_wg_enable_rev. There - * is no "WAR range" as with prefetch. - */ + /* WRITE_GATHER: Disabled */ if (pcibr_soft->bs_rev_num < - (BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev)) + (BRIDGE_WIDGET_PART_NUM << 4)) pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER; /* PIC only supports 64-bit direct mapping in PCI-X mode. Since @@ -2064,7 +1840,23 @@ */ if (pcibr_soft->bs_bricktype > 0) { switch (pcibr_soft->bs_bricktype) { + case MODULE_PBRICK: + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); + break; + case MODULE_IBRICK: + /* port 0xe on the Ibrick only has slots 1 and 2 */ + if (pcibr_soft->bs_xid == 0xe) { + do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); + do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); + } + else { + /* allocate one RRB for the serial port */ + do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); + } + break; case MODULE_PXBRICK: + case MODULE_IXBRICK: /* * If the IO9 is in the PXBrick (bus1, slot1) allocate * RRBs to all the devices @@ -2080,23 +1872,6 @@ do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8); do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); } - - break; - case MODULE_PEBRICK: - case MODULE_PBRICK: - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - break; - case MODULE_IBRICK: - /* port 0xe on the Ibrick only has slots 1 and 2 */ - if (pcibr_soft->bs_xid == 0xe) { - do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8); - do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8); - } - else { - /* allocate one RRB for the serial port */ - do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1); - } break; } /* switch */ } @@ -2113,78 +1888,8 @@ /* Call the device attach */ (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); -#ifdef PIC_LATER -#if (defined(USS302_TIMEOUT_WAR)) - /* - * If this bridge holds a Lucent USS-302 or USS-312 pci/usb controller, - * increase the Bridge PCI retry backoff interval. This part seems - * to go away for long periods of time if a DAC appears on the bus during - * a read command that is being retried. - */ - -{ - ii_ixtt_u_t ixtt; - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - if (pcibr_soft->bs_slot[slot].bss_vendor_id == - LUCENT_USBHC_VENDOR_ID_NUM && - (pcibr_soft->bs_slot[slot].bss_device_id == - LUCENT_USBHC302_DEVICE_ID_NUM || - pcibr_soft->bs_slot[slot].bss_device_id == - LUCENT_USBHC312_DEVICE_ID_NUM)) { - printk(KERN_NOTICE - "pcibr_attach: %x Bus holds a usb part - setting" - "bridge PCI_RETRY_HLD to %d\n", - pcibr_vhdl, USS302_BRIDGE_TIMEOUT_HLD); - - bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_HLD_MASK; - bridge->b_bus_timeout |= - BRIDGE_BUS_PCI_RETRY_HLD(USS302_BRIDGE_TIMEOUT_HLD); - - /* - * Have to consider the read response timer in the hub II as well - */ - - hubii_ixtt_get(xconn_vhdl, &ixtt); - - /* - * bump rrsp_ps to allow at least 1ms for read - * responses from this widget - */ - - ixtt.ii_ixtt_fld_s.i_rrsp_ps = 20000; - hubii_ixtt_set(xconn_vhdl, &ixtt); - - /* - * print the current setting - */ - - hubii_ixtt_get(xconn_vhdl, &ixtt); - printk( "Setting hub ixtt.rrsp_ps field to 0x%x\n", - ixtt.ii_ixtt_fld_s.i_rrsp_ps); - - break; /* only need to do it once */ - } - } -} -#endif /* (defined(USS302_TIMEOUT_WAR)) */ -#else - FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n"); -#endif /* PIC_LATER */ - - if (aa) - async_attach_add_info(noslot_conn, aa); - pciio_device_attach(noslot_conn, (int)0); - /* - * Tear down pointer to async attach info -- async threads for - * bridge's descendants may be running but the bridge's work is done. - */ - if (aa) - async_attach_del_info(xconn_vhdl); - return 0; } @@ -2195,10 +1900,10 @@ */ int -pcibr_detach(devfs_handle_t xconn) +pcibr_detach(vertex_hdl_t xconn) { pciio_slot_t slot; - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; pcibr_soft_t pcibr_soft; bridge_t *bridge; unsigned s; @@ -2265,9 +1970,9 @@ } int -pcibr_asic_rev(devfs_handle_t pconn_vhdl) +pcibr_asic_rev(vertex_hdl_t pconn_vhdl) { - devfs_handle_t pcibr_vhdl; + vertex_hdl_t pcibr_vhdl; int tmp_vhdl; arbitrary_info_t ainfo; @@ -2294,7 +1999,7 @@ } int -pcibr_write_gather_flush(devfs_handle_t pconn_vhdl) +pcibr_write_gather_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); @@ -2309,7 +2014,7 @@ */ static iopaddr_t -pcibr_addr_pci_to_xio(devfs_handle_t pconn_vhdl, +pcibr_addr_pci_to_xio(vertex_hdl_t pconn_vhdl, pciio_slot_t slot, pciio_space_t space, iopaddr_t pci_addr, @@ -2323,6 +2028,8 @@ unsigned bar; /* which BASE reg on device is decoding */ iopaddr_t xio_addr = XIO_NOWHERE; + iopaddr_t base; /* base of devio(x) mapped area on PCI */ + iopaddr_t limit; /* base of devio(x) mapped area on PCI */ pciio_space_t wspace; /* which space device is decoding */ iopaddr_t wbase; /* base of device decode on PCI */ @@ -2533,8 +2240,6 @@ PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, "pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg, device_bits)); -#else - printk("pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg); #endif } pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; @@ -2620,18 +2325,46 @@ */ case PCIIO_SPACE_MEM: /* "mem space" */ case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM32_BASE + req_size - 1) <= - BRIDGE_PCI_MEM32_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM32_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM32_BASE; + limit = PICBRIDGE0_PCI_MEM32_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM32_BASE; + limit = PICBRIDGE1_PCI_MEM32_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM32_BASE; + limit = BRIDGE_PCI_MEM32_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if ((pci_addr + BRIDGE_PCI_MEM64_BASE + req_size - 1) <= - BRIDGE_PCI_MEM64_LIMIT) - xio_addr = pci_addr + BRIDGE_PCI_MEM64_BASE; + if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ + base = PICBRIDGE0_PCI_MEM64_BASE; + limit = PICBRIDGE0_PCI_MEM64_LIMIT; + } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ + base = PICBRIDGE1_PCI_MEM64_BASE; + limit = PICBRIDGE1_PCI_MEM64_LIMIT; + } else { /* Bridge/Xbridge */ + base = BRIDGE_PCI_MEM64_BASE; + limit = BRIDGE_PCI_MEM64_LIMIT; + } + + if ((pci_addr + base + req_size - 1) <= limit) + xio_addr = pci_addr + base; break; case PCIIO_SPACE_IO: /* "i/o space" */ + /* + * PIC bridges do not support big-window aliases into PCI I/O space + */ + if (IS_PIC_SOFT(pcibr_soft)) { + xio_addr = XIO_NOWHERE; + break; + } + /* Bridge Hardware Bug WAR #482741: * The 4G area that maps directly from * XIO space to PCI I/O space is busted @@ -2725,7 +2458,7 @@ /*ARGSUSED6 */ pcibr_piomap_t -pcibr_piomap_alloc(devfs_handle_t pconn_vhdl, +pcibr_piomap_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -2737,7 +2470,7 @@ pciio_info_t pciio_info = &pcibr_info->f_c; pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pcibr_piomap_t *mapptr; pcibr_piomap_t maplist; @@ -2867,7 +2600,7 @@ /*ARGSUSED */ caddr_t -pcibr_piotrans_addr(devfs_handle_t pconn_vhdl, +pcibr_piotrans_addr(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -2877,7 +2610,7 @@ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; iopaddr_t xio_addr; caddr_t addr; @@ -2908,7 +2641,7 @@ /*ARGSUSED */ iopaddr_t -pcibr_piospace_alloc(devfs_handle_t pconn_vhdl, +pcibr_piospace_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_space_t space, size_t req_size, @@ -3010,7 +2743,7 @@ /*ARGSUSED */ void -pcibr_piospace_free(devfs_handle_t pconn_vhdl, +pcibr_piospace_free(vertex_hdl_t pconn_vhdl, pciio_space_t space, iopaddr_t pciaddr, size_t req_size) @@ -3161,14 +2894,14 @@ /*ARGSUSED */ pcibr_dmamap_t -pcibr_dmamap_alloc(devfs_handle_t pconn_vhdl, +pcibr_dmamap_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, size_t req_size_max, unsigned flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pciio_slot_t slot; xwidgetnum_t xio_port; @@ -3454,6 +3187,29 @@ iopaddr_t pci_addr; pciio_slot_t slot; + if (IS_PIC_BUSNUM_SOFT(soft, 0)) { + if ((xio_addr >= PICBRIDGE0_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE0_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE0_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE0_PCI_MEM64_BASE; + return pci_addr; + } + } else if (IS_PIC_BUSNUM_SOFT(soft, 1)) { + if ((xio_addr >= PICBRIDGE1_PCI_MEM32_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM32_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM32_BASE; + return pci_addr; + } + if ((xio_addr >= PICBRIDGE1_PCI_MEM64_BASE) && + (xio_lim <= PICBRIDGE1_PCI_MEM64_LIMIT)) { + pci_addr = xio_addr - PICBRIDGE1_PCI_MEM64_BASE; + return pci_addr; + } + } else { if ((xio_addr >= BRIDGE_PCI_MEM32_BASE) && (xio_lim <= BRIDGE_PCI_MEM32_LIMIT)) { pci_addr = xio_addr - BRIDGE_PCI_MEM32_BASE; @@ -3464,6 +3220,7 @@ pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE; return pci_addr; } + } for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot) if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) && (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) { @@ -3644,243 +3401,6 @@ } /*ARGSUSED */ -alenlist_t -pcibr_dmamap_list(pcibr_dmamap_t pcibr_dmamap, - alenlist_t palenlist, - unsigned flags) -{ - pcibr_soft_t pcibr_soft; - bridge_t *bridge=NULL; - - unsigned al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - int inplace = flags & PCIIO_INPLACE; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist; - size_t length; - iopaddr_t offset; - unsigned direct64; - int ate_index = 0; - int ate_count = 0; - int ate_total = 0; - bridge_ate_p ate_ptr = (bridge_ate_p)0; - bridge_ate_t ate_proto = (bridge_ate_t)0; - bridge_ate_t ate_prev; - bridge_ate_t ate; - alenaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - alenaddr_t new_addr; - unsigned cmd_regs[8]; - unsigned s = 0; - -#if PCIBR_FREEZE_TIME - unsigned freeze_time; -#endif - int ate_freeze_done = 0; /* To pair ATE_THAW - * with an ATE_FREEZE - */ - - pcibr_soft = pcibr_dmamap->bd_soft; - - xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: xtalk_dmamap_list() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_create() failed, " - "pcibr_dmamap=0x%lx\n", (unsigned long)pcibr_dmamap)); - goto fail; - } - } - - direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64; - if (!direct64) { - bridge = pcibr_soft->bs_base; - ate_ptr = pcibr_dmamap->bd_ate_ptr; - ate_index = pcibr_dmamap->bd_ate_index; - ate_proto = pcibr_dmamap->bd_ate_proto; - ATE_FREEZE(); - ate_freeze_done = 1; /* Remember that we need to do an ATE_THAW */ - } - pci_addr = pcibr_dmamap->bd_pci_addr; - - ate_prev = 0; /* matches no valid ATEs */ - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &length, al_flags)) { - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - if (xio_port == pcibr_soft->bs_xid) { - new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length); - if (new_addr == PCI_NOWHERE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: pcibr_addr_xio_to_pci failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - } else if (direct64) { - new_addr = pci_addr | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - new_addr &= ~PCI64_ATTR_PREF; - - } else { - /* calculate the ate value for - * the first address. If it - * matches the previous - * ATE written (ie. we had - * multiple blocks in the - * same IOPG), then back up - * and reuse that ATE. - * - * We are NOT going to - * aggressively try to - * reuse any other ATEs. - */ - offset = IOPGOFF(xio_addr); - ate = ate_proto - | (xio_port << ATE_TIDSHIFT) - | (xio_addr - offset); - if (ate == ate_prev) { - PCIBR_DEBUG((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: ATE share\n")); - ate_ptr--; - ate_index--; - pci_addr -= IOPGSIZE; - } - new_addr = pci_addr + offset; - - /* Fill in the hardware ATEs - * that contain this block. - */ - ate_count = IOPG(offset + length - 1) + 1; - ate_total += ate_count; - - /* Ensure that this map contains enough ATE's */ - if (ate_total > pcibr_dmamap->bd_ate_count) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list :\n" - "\twanted xio_addr [0x%x..0x%x]\n" - "\tate_total 0x%x bd_ate_count 0x%x\n" - "\tATE's required > number allocated\n", - xio_addr, xio_addr + length - 1, - ate_total, pcibr_dmamap->bd_ate_count)); - goto fail; - } - - ATE_WRITE(); - - ate_index += ate_count; - ate_ptr += ate_count; - - ate_count <<= IOPFNSHIFT; - ate += ate_count; - pci_addr += ate_count; - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &new_addr, &length, al_flags)) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_replace() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - - goto fail; - } - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - new_addr, length, al_flags)) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: alenlist_append() failed, " - "pcibr_dmamap=0x%x\n", pcibr_dmamap)); - goto fail; - } - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - - /* In case an ATE_FREEZE was done do the ATE_THAW to unroll all the - * changes that ATE_FREEZE has done to implement the external SSRAM - * bug workaround. - */ - if (ate_freeze_done) { - ATE_THAW(); - if ( IS_PIC_SOFT(pcibr_soft) ) { - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); - } else { - bridge->b_wid_tflush; - } - } - } - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_list: pcibr_dmamap=0x%x, pciio_alenlist=0x%x\n", - pcibr_dmamap, pciio_alenlist)); - - return pciio_alenlist; - - fail: - /* There are various points of failure after doing an ATE_FREEZE - * We need to do an ATE_THAW. Otherwise the ATEs are locked forever. - * The decision to do an ATE_THAW needs to be based on whether a - * an ATE_FREEZE was done before. - */ - if (ate_freeze_done) { - ATE_THAW(); - if ( IS_PIC_SOFT(pcibr_soft) ) { - bridge->b_wid_tflush; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_GET32((&bridge->b_wid_tflush)); - } else { - bridge->b_wid_tflush; - } - } - } - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - -/*ARGSUSED */ void pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) { @@ -3917,7 +3437,7 @@ /*ARGSUSED */ cnodeid_t -pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl) +pcibr_get_dmatrans_node(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -3928,7 +3448,7 @@ /*ARGSUSED */ iopaddr_t -pcibr_dmatrans_addr(devfs_handle_t pconn_vhdl, +pcibr_dmatrans_addr(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, paddr_t paddr, size_t req_size, @@ -3936,7 +3456,7 @@ { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; @@ -4149,213 +3669,6 @@ return 0; } -/*ARGSUSED */ -alenlist_t -pcibr_dmatrans_list(devfs_handle_t pconn_vhdl, - device_desc_t dev_desc, - alenlist_t palenlist, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - xwidgetnum_t xio_port; - - alenlist_t pciio_alenlist = 0; - alenlist_t xtalk_alenlist = 0; - - int inplace; - unsigned direct64; - unsigned al_flags; - - iopaddr_t xio_base; - alenaddr_t xio_addr; - size_t xio_size; - - size_t map_size; - iopaddr_t pci_base; - alenaddr_t pci_addr; - - unsigned relbits = 0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - inplace = flags & PCIIO_INPLACE; - direct64 = flags & PCIIO_DMA_A64; - al_flags = (flags & PCIIO_NOSLEEP) ? AL_NOSLEEP : 0; - - if (direct64) { - map_size = 1ull << 48; - xio_base = 0; - pci_base = slotp->bss_d64_base; - if ((pci_base != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) { - /* DMA configuration conflict */ - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: DMA configuration conflict " - "for direct64, flags=0x%x\n", flags)); - goto fail; - } else { - relbits = BRIDGE_DEV_D64_BITS; - pci_base = - pcibr_flags_to_d64(flags, pcibr_soft); - } - } else { - xio_base = pcibr_soft->bs_dir_xbase; - map_size = 1ull << 31; - pci_base = slotp->bss_d32_base; - if ((pci_base != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - /* reuse previous base info */ - } else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) { - /* DMA configuration conflict */ - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: DMA configuration conflict " - "for direct32, flags=0x%x\n", flags)); - goto fail; - } else { - relbits = BRIDGE_DEV_D32_BITS; - pci_base = PCI32_DIRECT_BASE; - } - } - - xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist, - flags & DMAMAP_FLAGS); - if (!xtalk_alenlist) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xtalk_dmatrans_list failed " - "xtalk_alenlist=0x%x\n", xtalk_alenlist)); - goto fail; - } - - alenlist_cursor_init(xtalk_alenlist, 0, NULL); - - if (inplace) { - pciio_alenlist = xtalk_alenlist; - } else { - pciio_alenlist = alenlist_create(al_flags); - if (!pciio_alenlist) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_create failed with " - " 0x%x\n", pciio_alenlist)); - goto fail; - } - } - - while (ALENLIST_SUCCESS == - alenlist_get(xtalk_alenlist, NULL, 0, - &xio_addr, &xio_size, al_flags)) { - - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xio_addr == XIO_NOWHERE\n")); - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size); - if (pci_addr == (alenaddr_t)NULL) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: pcibr_addr_xio_to_pci failed " - "xio_addr=0x%x, xio_size=0x%x\n", xio_addr, xio_size)); - goto fail; - } - } else if (direct64) { - ASSERT(xio_port != 0); - pci_addr = pci_base | xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - } else { - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = xio_size + offset; - - if ((xio_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: xio_size > map_size fail\n" - "xio_addr=0x%x, xio_size=0x%x. map_size=0x%x, " - "xio_port=0x%x, endoff=0x%x\n", - xio_addr, xio_size, map_size, xio_port, endoff)); - goto fail; - } - - pci_addr = pci_base + (xio_addr - xio_base); - } - - /* write the PCI DMA address - * out to the scatter-gather list. - */ - if (inplace) { - if (ALENLIST_SUCCESS != - alenlist_replace(pciio_alenlist, NULL, - &pci_addr, &xio_size, al_flags)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_replace failed\n")); - goto fail; - } - } else { - if (ALENLIST_SUCCESS != - alenlist_append(pciio_alenlist, - pci_addr, xio_size, al_flags)) { - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: alenlist_append failed\n")); - goto fail; - } - } - } - - if (relbits) { - if (direct64) { - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_base; - } else { - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_base; - } - } - if (!inplace) - alenlist_done(xtalk_alenlist); - - /* Reset the internal cursor of the alenlist to be returned back - * to the caller. - */ - alenlist_cursor_init(pciio_alenlist, 0, NULL); - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_list: pciio_alenlist=0x%x\n", - pciio_alenlist)); - - return pciio_alenlist; - - fail: - if (relbits) - pcibr_release_device(pcibr_soft, pciio_slot, relbits); - if (pciio_alenlist && !inplace) - alenlist_destroy(pciio_alenlist); - return 0; -} - void pcibr_dmamap_drain(pcibr_dmamap_t map) { @@ -4363,24 +3676,24 @@ } void -pcibr_dmaaddr_drain(devfs_handle_t pconn_vhdl, +pcibr_dmaaddr_drain(vertex_hdl_t pconn_vhdl, paddr_t paddr, size_t bytes) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); } void -pcibr_dmalist_drain(devfs_handle_t pconn_vhdl, +pcibr_dmalist_drain(vertex_hdl_t pconn_vhdl, alenlist_t list) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; xtalk_dmalist_drain(xconn_vhdl, list); } @@ -4402,18 +3715,18 @@ */ /*ARGSUSED */ void -pcibr_provider_startup(devfs_handle_t pcibr) +pcibr_provider_startup(vertex_hdl_t pcibr) { } /*ARGSUSED */ void -pcibr_provider_shutdown(devfs_handle_t pcibr) +pcibr_provider_shutdown(vertex_hdl_t pcibr) { } int -pcibr_reset(devfs_handle_t conn) +pcibr_reset(vertex_hdl_t conn) { #ifdef PIC_LATER pciio_info_t pciio_info = pciio_info_get(conn); @@ -4484,7 +3797,7 @@ } pciio_endian_t -pcibr_endian_set(devfs_handle_t pconn_vhdl, +pcibr_endian_set(vertex_hdl_t pconn_vhdl, pciio_endian_t device_end, pciio_endian_t desired_end) { @@ -4629,7 +3942,7 @@ } pciio_priority_t -pcibr_priority_set(devfs_handle_t pconn_vhdl, +pcibr_priority_set(vertex_hdl_t pconn_vhdl, pciio_priority_t device_prio) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -4653,7 +3966,7 @@ * Returns 0 on failure, 1 on success */ int -pcibr_device_flags_set(devfs_handle_t pconn_vhdl, +pcibr_device_flags_set(vertex_hdl_t pconn_vhdl, pcibr_device_flags_t flags) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -4792,10 +4105,8 @@ (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, (pciio_dmamap_free_f *) pcibr_dmamap_free, (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, (pciio_dmamap_done_f *) pcibr_dmamap_done, (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, (pciio_dmamap_drain_f *) pcibr_dmamap_drain, (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, (pciio_dmalist_drain_f *) pcibr_dmalist_drain, @@ -4814,23 +4125,16 @@ (pciio_priority_set_f *) pcibr_priority_set, (pciio_config_get_f *) pcibr_config_get, (pciio_config_set_f *) pcibr_config_set, -#ifdef PIC_LATER - (pciio_error_devenable_f *) pcibr_error_devenable, - (pciio_error_extract_f *) pcibr_error_extract, - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, -#else (pciio_error_devenable_f *) 0, (pciio_error_extract_f *) 0, (pciio_driver_reg_callback_f *) 0, (pciio_driver_unreg_callback_f *) 0, -#endif /* PIC_LATER */ (pciio_device_unregister_f *) pcibr_device_unregister, (pciio_dma_enabled_f *) pcibr_dma_enabled, }; int -pcibr_dma_enabled(devfs_handle_t pconn_vhdl) +pcibr_dma_enabled(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); @@ -4857,7 +4161,7 @@ * parameter 'format' is sent to the console. */ void -pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...) +pcibr_debug(uint32_t type, vertex_hdl_t vhdl, char *format, ...) { char hwpath[MAXDEVNAME] = "\0"; char copy_of_hwpath[MAXDEVNAME]; @@ -4865,7 +4169,6 @@ short widget = -1; short slot = -1; va_list ap; - char *strtok_r(char *string, const char *sepset, char **lasts); if (pcibr_debug_mask & type) { if (vhdl) { @@ -4873,13 +4176,12 @@ char *cp; if (strcmp(module, pcibr_debug_module)) { - /* strtok_r() wipes out string, use a copy */ + /* use a copy */ (void)strcpy(copy_of_hwpath, hwpath); cp = strstr(copy_of_hwpath, "/module/"); if (cp) { - char *last = NULL; cp += strlen("/module"); - module = strtok_r(cp, "/", &last); + module = strsep(&cp, "/"); } } if (pcibr_debug_widget != -1) { @@ -4917,4 +4219,27 @@ va_end(ap); } } +} + +int +isIO9(nasid_t nasid) { + lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); + + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + return 1; + } + brd = KLCF_NEXT(brd); + } + /* if it's dual ported, check the peer also */ + nasid = NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer; + if (nasid < 0) return 0; + brd = (lboard_t *)KL_CONFIG_INFO(nasid); + while (brd) { + if (brd->brd_flags & LOCAL_MASTER_IO6) { + return 1; + } + brd = KLCF_NEXT(brd); + } + return 0; } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Mon Feb 24 10:14:08 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,26 +27,11 @@ #include #include #include -#include #include #include -#ifdef __ia64 -#define rmallocmap atemapalloc -#define rmfreemap atemapfree -#define rmfree atefree -#define rmalloc atealloc -#endif - extern int hubii_check_widget_disabled(nasid_t, int); -#ifdef BRIDGE_B_DATACORR_WAR -extern int ql_bridge_rev_b_war(devfs_handle_t); -extern int bridge_rev_b_data_check_disable; -char *rev_b_datacorr_warning = -"***************************** WARNING! ******************************\n"; -char *rev_b_datacorr_mesg = -"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n"; -#endif + /* ===================================================================== * ERROR HANDLING @@ -76,13 +61,9 @@ BRIDGE_ISR_PCIBUS_PIOERR; #endif -#if defined (PCIBR_LLP_CONTROL_WAR) -int pcibr_llp_control_war_cnt; -#endif /* PCIBR_LLP_CONTROL_WAR */ +int pcibr_llp_control_war_cnt; /* PCIBR_LLP_CONTROL_WAR */ -/* FIXME: can these arrays be local ? */ - -struct reg_values xio_cmd_pactyp[] = +static struct reg_values xio_cmd_pactyp[] = { {0x0, "RdReq"}, {0x1, "RdResp"}, @@ -103,7 +84,7 @@ {0} }; -struct reg_desc xio_cmd_bits[] = +static struct reg_desc xio_cmd_bits[] = { {WIDGET_DIDN, -28, "DIDN", "%x"}, {WIDGET_SIDN, -24, "SIDN", "%x"}, @@ -120,58 +101,7 @@ #define F(s,n) { 1l<<(s),-(s), n } -struct reg_desc bridge_int_status_desc[] = -{ - F(45, "PCI_X_SPLIT_MES_PE"),/* PIC ONLY */ - F(44, "PCI_X_SPLIT_EMES"), /* PIC ONLY */ - F(43, "PCI_X_SPLIT_TO"), /* PIC ONLY */ - F(42, "PCI_X_UNEX_COMP"), /* PIC ONLY */ - F(41, "INT_RAM_PERR"), /* PIC ONLY */ - F(40, "PCI_X_ARB_ERR"), /* PIC ONLY */ - F(39, "PCI_X_REQ_TOUT"), /* PIC ONLY */ - F(38, "PCI_X_TABORT"), /* PIC ONLY */ - F(37, "PCI_X_PERR"), /* PIC ONLY */ - F(36, "PCI_X_SERR"), /* PIC ONLY */ - F(35, "PCI_X_MRETRY"), /* PIC ONLY */ - F(34, "PCI_X_MTOUT"), /* PIC ONLY */ - F(33, "PCI_X_DA_PARITY"), /* PIC ONLY */ - F(32, "PCI_X_AD_PARITY"), /* PIC ONLY */ - F(31, "MULTI_ERR"), /* BRIDGE ONLY */ - F(30, "PMU_ESIZE_EFAULT"), - F(29, "UNEXPECTED_RESP"), - F(28, "BAD_XRESP_PACKET"), - F(27, "BAD_XREQ_PACKET"), - F(26, "RESP_XTALK_ERROR"), - F(25, "REQ_XTALK_ERROR"), - F(24, "INVALID_ADDRESS"), - F(23, "UNSUPPORTED_XOP"), - F(22, "XREQ_FIFO_OFLOW"), - F(21, "LLP_REC_SNERROR"), - F(20, "LLP_REC_CBERROR"), - F(19, "LLP_RCTY"), - F(18, "LLP_TX_RETRY"), - F(17, "LLP_TCTY"), - F(16, "SSRAM_PERR"), /* BRIDGE ONLY */ - F(15, "PCI_ABORT"), - F(14, "PCI_PARITY"), - F(13, "PCI_SERR"), - F(12, "PCI_PERR"), - F(11, "PCI_MASTER_TOUT"), - F(10, "PCI_RETRY_CNT"), - F(9, "XREAD_REQ_TOUT"), - F(8, "GIO_BENABLE_ERR"), /* BRIDGE ONLY */ - F(7, "INT7"), - F(6, "INT6"), - F(5, "INT5"), - F(4, "INT4"), - F(3, "INT3"), - F(2, "INT2"), - F(1, "INT1"), - F(0, "INT0"), - {0} -}; - -struct reg_values space_v[] = +static struct reg_values space_v[] = { {PCIIO_SPACE_NONE, "none"}, {PCIIO_SPACE_ROM, "ROM"}, @@ -189,13 +119,13 @@ {PCIIO_SPACE_BAD, "BAD"}, {0} }; -struct reg_desc space_desc[] = +static struct reg_desc space_desc[] = { {0xFF, 0, "space", 0, space_v}, {0} }; #define device_desc device_bits -struct reg_desc device_bits[] = +static struct reg_desc device_bits[] = { {BRIDGE_DEV_ERR_LOCK_EN, 0, "ERR_LOCK_EN"}, {BRIDGE_DEV_PAGE_CHK_DIS, 0, "PAGE_CHK_DIS"}, @@ -218,14 +148,14 @@ {0} }; -void +static void print_bridge_errcmd(uint32_t cmdword, char *errtype) { printk("\t Bridge %s Error Command Word Register ", errtype); print_register(cmdword, xio_cmd_bits); } -char *pcibr_isr_errs[] = +static char *pcibr_isr_errs[] = { "", "", "", "", "", "", "", "", "08: GIO non-contiguous byte enable in crosstalk packet", /* BRIDGE ONLY */ @@ -279,7 +209,7 @@ /* * display memory directory state */ -void +static void pcibr_show_dir_state(paddr_t paddr, char *prefix) { #ifdef LATER @@ -428,7 +358,6 @@ break; case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ -/* case BRIDGE_ISR_PMU_ESIZE_FAULT: bit30 PMU_ESIZE_FAULT */ if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) reg_desc = "Map Fault Address"; else @@ -592,31 +521,9 @@ printk( "\t%s\n", pcibr_isr_errs[i]); } } - -#if BRIDGE_ERROR_INTR_WAR - if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) { /* known bridge bug */ - /* - * Should never receive interrupts for these reasons on Rev 1 bridge - * as they are not enabled. Assert for it. - */ - ASSERT((int_status & (BRIDGE_IMR_PCI_MST_TIMEOUT | - BRIDGE_ISR_RESP_XTLK_ERR | - BRIDGE_ISR_LLP_TX_RETRY)) == 0); - } - if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) { /* known bridge bug */ - /* - * This interrupt is turned off at init time. So, should never - * see this interrupt. - */ - ASSERT((int_status & BRIDGE_ISR_BAD_XRESP_PKT) == 0); - } -#endif } -#define PCIBR_ERRINTR_GROUP(error) \ - (( error & (BRIDGE_IRR_PCI_GRP|BRIDGE_IRR_GIO_GRP) - -uint32_t +static uint32_t pcibr_errintr_group(uint32_t error) { uint32_t group = BRIDGE_IRR_MULTI_CLR; @@ -741,15 +648,7 @@ picreg_t int_status_64; int number_bits; int i; - - /* REFERENCED */ uint64_t disable_errintr_mask = 0; -#ifdef EHE_ENABLE - int rv; - int error_code = IOECODE_DMA | IOECODE_READ; - ioerror_mode_t mode = MODE_DEVERROR; - ioerror_t ioe; -#endif /* EHE_ENABLE */ nasid_t nasid; @@ -806,10 +705,6 @@ pcibr_soft->bs_errinfo.bserr_toutcnt++; /* Let's go recursive */ return(pcibr_error_intr_handler(irq, arg, ep)); -#ifdef LATER - timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT); -#endif - return; } /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a @@ -847,24 +742,6 @@ pcibr_pioerr_check(pcibr_soft); } -#ifdef BRIDGE_B_DATACORR_WAR - if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) && - (err_status & BRIDGE_IMR_LLP_REC_CBERR)) { - if (bridge_rev_b_data_check_disable) - printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning, - pcibr_soft->bs_name, rev_b_datacorr_mesg, - rev_b_datacorr_warning); - else { - ql_bridge_rev_b_war(pcibr_soft->bs_vhdl); - PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning, - pcibr_soft->bs_name, rev_b_datacorr_mesg, - rev_b_datacorr_warning); - } - - err_status &= ~BRIDGE_IMR_LLP_REC_CBERR; - } -#endif /* BRIDGE_B_DATACORR_WAR */ - if (err_status) { struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat; @@ -1024,9 +901,8 @@ (0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) { err_status &= ~BRIDGE_ISR_INVLD_ADDR; } -#if defined (PCIBR_LLP_CONTROL_WAR) /* - * The bridge bug, where the llp_config or control registers + * The bridge bug (PCIBR_LLP_CONTROL_WAR), where the llp_config or control registers * need to be read back after being written, affects an MP * system since there could be small windows between writing * the register and reading it back on one cpu while another @@ -1039,40 +915,9 @@ if ((err_status & BRIDGE_ISR_INVLD_ADDR) && ((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower)) == (BRIDGE_INT_RST_STAT & 0xff0))) { -#if 0 - if (kdebug) - printk(KERN_NOTICE "%s bridge: ignoring llp/control address interrupt", - pcibr_soft->bs_name); -#endif pcibr_llp_control_war_cnt++; err_status &= ~BRIDGE_ISR_INVLD_ADDR; } -#endif /* PCIBR_LLP_CONTROL_WAR */ - -#ifdef EHE_ENABLE - /* Check if this is the RESP_XTALK_ERROR interrupt. - * This can happen due to a failed DMA READ operation. - */ - if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) { - /* Phase 1 : Look at the error state in the bridge and further - * down in the device layers. - */ - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP); - IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid); - (void)pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - /* Phase 2 : Perform the action agreed upon in phase 1. - */ - (void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION); - rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - error_code, - mode, - &ioe); - } - if (rv != IOERROR_HANDLED) { -#endif /* EHE_ENABLE */ bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; @@ -1089,25 +934,16 @@ */ if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) && (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { - printk("BRIDGE ERR_STATUS 0x%x\n", err_status); + printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); pcibr_error_dump(pcibr_soft); -#ifdef LATER - machine_error_dump(""); -#endif PRINT_PANIC("PCI Bridge Error interrupt killed the system"); } if (err_status & BRIDGE_ISR_ERROR_FATAL) { -#ifdef LATER - machine_error_dump(""); -#endif PRINT_PANIC("PCI Bridge Error interrupt killed the system"); /*NOTREACHED */ } -#ifdef EHE_ENABLE - } -#endif /* * We can't return without re-enabling the interrupt, since @@ -1137,136 +973,6 @@ pcibr_soft->bs_errinfo.bserr_intstat = 0; } -/* - * pcibr_addr_toslot - * Given the 'pciaddr' find out which slot this address is - * allocated to, and return the slot number. - * While we have the info handy, construct the - * function number, space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - */ -int -pcibr_addr_toslot(pcibr_soft_t pcibr_soft, - iopaddr_t pciaddr, - pciio_space_t *spacep, - iopaddr_t *offsetp, - pciio_function_t *funcp) -{ - int s, f = 0, w; - iopaddr_t base; - size_t size; - pciio_piospace_t piosp; - - /* - * Check if the address is in config space - */ - - if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { - - if (pciaddr >= BRIDGE_CONFIG1_BASE) - pciaddr -= BRIDGE_CONFIG1_BASE; - else - pciaddr -= BRIDGE_CONFIG_BASE; - - s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; - pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; - - if (funcp) { - f = pciaddr / 0x100; - pciaddr %= 0x100; - } - if (spacep) - *spacep = PCIIO_SPACE_CFG; - if (offsetp) - *offsetp = pciaddr; - if (funcp) - *funcp = f; - - return s; - } - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - for (w = 0; w < 6; w++) { - if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) { - continue; - } - base = pcibr_info->f_window[w].w_base; - size = pcibr_info->f_window[w].w_size; - - if ((pciaddr >= base) && (pciaddr < (base + size))) { - if (spacep) - *spacep = PCIIO_SPACE_WIN(w); - if (offsetp) - *offsetp = pciaddr - base; - if (funcp) - *funcp = f; - return s; - } /* endif match */ - } /* next window */ - } /* next func */ - } /* next slot */ - - /* - * Check if the address was allocated as part of the - * pcibr_piospace_alloc calls. - */ - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - piosp = pcibr_info->f_piospace; - while (piosp) { - if ((piosp->start <= pciaddr) && - ((piosp->count + piosp->start) > pciaddr)) { - if (spacep) - *spacep = piosp->space; - if (offsetp) - *offsetp = pciaddr - piosp->start; - return s; - } /* endif match */ - piosp = piosp->next; - } /* next piosp */ - } /* next func */ - } /* next slot */ - - /* - * Some other random address on the PCI bus ... - * we have no way of knowing whether this was - * a MEM or I/O access; so, for now, we just - * assume that the low 1G is MEM, the next - * 3G is I/O, and anything above the 4G limit - * is obviously MEM. - */ - - if (spacep) - *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : - (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : - PCIIO_SPACE_MEM); - if (offsetp) - *offsetp = pciaddr; - - return PCIIO_SLOT_NONE; - -} - void pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) { @@ -1286,59 +992,6 @@ (void) bridge->b_wid_tflush; /* flushbus */ } -/* - * pcibr_error_extract - * Given the 'pcibr vertex handle' find out which slot - * the bridge status error address (from pcibr_soft info - * hanging off the vertex) - * allocated to, and return the slot number. - * While we have the info handy, construct the - * space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - * - * XXX- this interface has no way to return the function - * number on a multifunction card, even though that data - * is available. - */ - -pciio_slot_t -pcibr_error_extract(devfs_handle_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *offsetp) -{ - pcibr_soft_t pcibr_soft = 0; - iopaddr_t bserr_addr; - bridge_t *bridge; - pciio_slot_t slot = PCIIO_SLOT_NONE; - arbitrary_info_t rev; - - /* Do a sanity check as to whether we really got a - * bridge vertex handle. - */ - if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != - GRAPH_SUCCESS) - return(slot); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) { - bridge = pcibr_soft->bs_base; - bserr_addr = - bridge->b_pci_err_lower | - ((uint64_t) (bridge->b_pci_err_upper & - BRIDGE_ERRUPPR_ADDRMASK) << 32); - - slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, - spacep, offsetp, NULL); - } - return slot; -} - /*ARGSUSED */ void pcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum) @@ -1426,7 +1079,7 @@ { int retval = IOERROR_HANDLED; - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; bridge_t *bridge = pcibr_soft->bs_base; iopaddr_t bad_xaddr; @@ -1837,7 +1490,7 @@ ioerror_mode_t mode, ioerror_t *ioe) { - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t bus_lowaddr, bus_uppraddr; int retval = 0; @@ -1946,7 +1599,7 @@ ioerror_mode_t mode, ioerror_t *ioe) { - devfs_handle_t pcibr_vhdl = pcibr_soft->bs_vhdl; + vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; int retval; retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); @@ -1982,34 +1635,12 @@ pcibr_soft_t pcibr_soft; int retval = IOERROR_BADERRORCODE; -#ifdef EHE_ENABLE - devfs_handle_t xconn_vhdl,pcibr_vhdl; - error_state_t e_state; -#endif /* EHE_ENABLE */ - pcibr_soft = (pcibr_soft_t) einfo; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, "pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n", pcibr_soft, error_code)); -#ifdef EHE_ENABLE - xconn_vhdl = pcibr_soft->bs_conn; - pcibr_vhdl = pcibr_soft->bs_vhdl; - - e_state = error_state_get(xconn_vhdl); - - if (error_state_set(pcibr_vhdl, e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); - - /* If we are in the action handling phase clean out the error state - * on the xswitch. - */ - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(xconn_vhdl, ERROR_STATE_NONE); -#endif /* EHE_ENABLE */ - #if DEBUG && ERROR_DEBUG printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name); #endif @@ -2086,11 +1717,6 @@ * the error from the PIO address. */ -#if 0 - if (mode == MODE_DEVPROBE) - pio_retval = IOERROR_HANDLED; - else { -#endif if (error_code & IOECODE_PIO) { iopaddr_t bad_xaddr; /* @@ -2123,9 +1749,6 @@ pio_retval = IOERROR_UNHANDLED; } } -#if 0 - } /* MODE_DEVPROBE */ -#endif /* * If the error was a result of a DMA Write, we tell what bus on the PIC @@ -2200,38 +1823,4 @@ } else { return IOERROR_HANDLED; } -} - - -/* - * Reenable a device after handling the error. - * This is called by the lower layers when they wish to be reenabled - * after an error. - * Note that each layer would be calling the previous layer to reenable - * first, before going ahead with their own re-enabling. - */ - -int -pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - ASSERT(error_code & IOECODE_PIO); - - /* If the error is not known to be a write, - * we have to call devenable. - * write errors are isolated to the bridge. - */ - if (!(error_code & IOECODE_WRITE)) { - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; - int rc; - - rc = xtalk_error_devenable(xconn_vhdl, pciio_slot, error_code); - if (rc != IOERROR_HANDLED) - return rc; - } - pcibr_error_cleanup(pcibr_soft, error_code); - return IOERROR_HANDLED; } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Tue Dec 3 10:07:27 2002 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,20 +27,19 @@ #include #include #include -#include #include #include -pcibr_hints_t pcibr_hints_get(devfs_handle_t, int); -void pcibr_hints_fix_rrbs(devfs_handle_t); -void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(devfs_handle_t); -void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t); +pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); +void pcibr_hints_fix_rrbs(vertex_hdl_t); +void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); +void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); +void pcibr_hints_handsoff(vertex_hdl_t); +void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); pcibr_hints_t -pcibr_hints_get(devfs_handle_t xconn_vhdl, int alloc) +pcibr_hints_get(vertex_hdl_t xconn_vhdl, int alloc) { arbitrary_info_t ainfo = 0; graph_error_t rv; @@ -79,7 +78,7 @@ } void -pcibr_hints_fix_some_rrbs(devfs_handle_t xconn_vhdl, unsigned mask) +pcibr_hints_fix_some_rrbs(vertex_hdl_t xconn_vhdl, unsigned mask) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -91,13 +90,13 @@ } void -pcibr_hints_fix_rrbs(devfs_handle_t xconn_vhdl) +pcibr_hints_fix_rrbs(vertex_hdl_t xconn_vhdl) { pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); } void -pcibr_hints_dualslot(devfs_handle_t xconn_vhdl, +pcibr_hints_dualslot(vertex_hdl_t xconn_vhdl, pciio_slot_t host, pciio_slot_t guest) { @@ -111,7 +110,7 @@ } void -pcibr_hints_intr_bits(devfs_handle_t xconn_vhdl, +pcibr_hints_intr_bits(vertex_hdl_t xconn_vhdl, pcibr_intr_bits_f *xxx_intr_bits) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -124,7 +123,7 @@ } void -pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) +pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -133,7 +132,7 @@ } void -pcibr_hints_handsoff(devfs_handle_t xconn_vhdl) +pcibr_hints_handsoff(vertex_hdl_t xconn_vhdl) { pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); @@ -145,13 +144,13 @@ } void -pcibr_hints_subdevs(devfs_handle_t xconn_vhdl, +pcibr_hints_subdevs(vertex_hdl_t xconn_vhdl, pciio_slot_t slot, uint64_t subdevs) { arbitrary_info_t ainfo = 0; char sdname[16]; - devfs_handle_t pconn_vhdl = GRAPH_VERTEX_NONE; + vertex_hdl_t pconn_vhdl = GRAPH_VERTEX_NONE; sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot); (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_idbg.c Sat Mar 9 02:24:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,147 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef LATER - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -void -idbg_pss_func(pcibr_info_h pcibr_infoh, int func) -{ - pcibr_info_t pcibr_info = pcibr_infoh[func]; - char name[MAXDEVNAME]; - int win; - - if (!pcibr_info) - return; - qprintf("Per-slot Function Info\n"); - sprintf(name, "%v", pcibr_info->f_vertex); - qprintf("\tSlot Name : %s\n",name); - qprintf("\tPCI Bus : %d ",pcibr_info->f_bus); - qprintf("Slot : %d ", pcibr_info->f_slot); - qprintf("Function : %d ", pcibr_info->f_func); - qprintf("VendorId : 0x%x " , pcibr_info->f_vendor); - qprintf("DeviceId : 0x%x\n", pcibr_info->f_device); - sprintf(name, "%v", pcibr_info->f_master); - qprintf("\tBus provider : %s\n",name); - qprintf("\tProvider Fns : 0x%x ", pcibr_info->f_pops); - qprintf("Error Handler : 0x%x Arg 0x%x\n", - pcibr_info->f_efunc,pcibr_info->f_einfo); - for(win = 0 ; win < 6 ; win++) - qprintf("\tBase Reg #%d space %s base 0x%x size 0x%x\n", - win,pci_space[pcibr_info->f_window[win].w_space], - pcibr_info->f_window[win].w_base, - pcibr_info->f_window[win].w_size); - - qprintf("\tRom base 0x%x size 0x%x\n", - pcibr_info->f_rbase,pcibr_info->f_rsize); - - qprintf("\tInterrupt Bit Map\n"); - qprintf("\t\tPCI Int#\tBridge Pin#\n"); - for (win = 0 ; win < 4; win++) - qprintf("\t\tINT%c\t\t%d\n",win+'A',pcibr_info->f_ibit[win]); - qprintf("\n"); -} - - -void -idbg_pss_info(pcibr_soft_t pcibr_soft, pciio_slot_t slot) -{ - pcibr_soft_slot_t pss; - char slot_conn_name[MAXDEVNAME]; - int func; - - pss = &pcibr_soft->bs_slot[slot]; - qprintf("PCI INFRASTRUCTURAL INFO FOR SLOT %d\n", slot); - qprintf("\tHost Present ? %s ", pss->has_host ? "yes" : "no"); - qprintf("\tHost Slot : %d\n",pss->host_slot); - sprintf(slot_conn_name, "%v", pss->slot_conn); - qprintf("\tSlot Conn : %s\n",slot_conn_name); - qprintf("\t#Functions : %d\n",pss->bss_ninfo); - for (func = 0; func < pss->bss_ninfo; func++) - idbg_pss_func(pss->bss_infos,func); - qprintf("\tSpace : %s ",pci_space[pss->bss_devio.bssd_space]); - qprintf("\tBase : 0x%x ", pss->bss_devio.bssd_base); - qprintf("\tShadow Devreg : 0x%x\n", pss->bss_device); - qprintf("\tUsage counts : pmu %d d32 %d d64 %d\n", - pss->bss_pmu_uctr,pss->bss_d32_uctr,pss->bss_d64_uctr); - - qprintf("\tDirect Trans Info : d64_base 0x%x d64_flags 0x%x" - "d32_base 0x%x d32_flags 0x%x\n", - pss->bss_d64_base, pss->bss_d64_flags, - pss->bss_d32_base, pss->bss_d32_flags); - - qprintf("\tExt ATEs active ? %s", - pss->bss_ext_ates_active ? "yes" : "no"); - qprintf(" Command register : 0x%x ", pss->bss_cmd_pointer); - qprintf(" Shadow command val : 0x%x\n", pss->bss_cmd_shadow); - - qprintf("\tRRB Info : Valid %d+%d Reserved %d\n", - pcibr_soft->bs_rrb_valid[slot], - pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], - pcibr_soft->bs_rrb_res[slot]); - -} - -int ips = 0; - -void -idbg_pss(pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - - if (ips >= 0 && ips < 8) - idbg_pss_info(pcibr_soft,ips); - else if (ips < 0) - for (slot = 0; slot < 8; slot++) - idbg_pss_info(pcibr_soft,slot); - else - qprintf("Invalid ips %d\n",ips); -} -#endif /* LATER */ diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Mon Feb 24 10:09:35 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -36,20 +35,32 @@ #define rmfreemap atemapfree #define rmfree atefree #define rmalloc atealloc + +inline int +compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) +{ + FIXME("compare_and_swap_ptr : NOT ATOMIC"); + if (*location == old_ptr) { + *location = new_ptr; + return(1); + } + else + return(0); +} #endif unsigned pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); -pcibr_intr_t pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); void pcibr_intr_free(pcibr_intr_t); void pcibr_setpciint(xtalk_intr_t); int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); void pcibr_intr_disconnect(pcibr_intr_t); -devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t); +vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); void pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); void pcibr_intr_func(intr_arg_t); -extern pcibr_info_t pcibr_info_get(devfs_handle_t); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); /* ===================================================================== * INTERRUPT MANAGEMENT @@ -132,6 +143,102 @@ } /* + * On SN systems there is a race condition between a PIO read response + * and DMA's. In rare cases, the read response may beat the DMA, causing + * the driver to think that data in memory is complete and meaningful. + * This code eliminates that race. + * This routine is called by the PIO read routines after doing the read. + * This routine then forces a fake interrupt on another line, which + * is logically associated with the slot that the PIO is addressed to. + * (see sn_dma_flush_init() ) + * It then spins while watching the memory location that the interrupt + * is targetted to. When the interrupt response arrives, we are sure + * that the DMA has landed in memory and it is safe for the driver + * to proceed. + */ + +extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; + +void +sn_dma_flush(unsigned long addr) { + nasid_t nasid; + int wid_num; + volatile struct sn_flush_device_list *p; + int i,j; + int bwin; + unsigned long flags; + + nasid = NASID_GET(addr); + wid_num = SWIN_WIDGETNUM(addr); + bwin = BWIN_WINDOWNUM(addr); + + if (flush_nasid_list[nasid].widget_p == NULL) return; + if (bwin > 0) { + bwin--; + switch (bwin) { + case 0: + wid_num = ((flush_nasid_list[nasid].iio_itte1) >> 8) & 0xf; + break; + case 1: + wid_num = ((flush_nasid_list[nasid].iio_itte2) >> 8) & 0xf; + break; + case 2: + wid_num = ((flush_nasid_list[nasid].iio_itte3) >> 8) & 0xf; + break; + case 3: + wid_num = ((flush_nasid_list[nasid].iio_itte4) >> 8) & 0xf; + break; + case 4: + wid_num = ((flush_nasid_list[nasid].iio_itte5) >> 8) & 0xf; + break; + case 5: + wid_num = ((flush_nasid_list[nasid].iio_itte6) >> 8) & 0xf; + break; + case 6: + wid_num = ((flush_nasid_list[nasid].iio_itte7) >> 8) & 0xf; + break; + } + } + if (flush_nasid_list[nasid].widget_p == NULL) return; + if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) return; + p = &flush_nasid_list[nasid].widget_p[wid_num][0]; + + // find a matching BAR + + for (i=0; ibar_list[j].start == 0) break; + if (addr >= p->bar_list[j].start && addr <= p->bar_list[j].end) break; + } + if (j < PCI_ROM_RESOURCE && p->bar_list[j].start != 0) break; + p++; + } + + // if no matching BAR, return without doing anything. + + if (i == DEV_PER_WIDGET) return; + + spin_lock_irqsave(&p->flush_lock, flags); + + p->flush_addr = 0; + + // force an interrupt. + + *(bridgereg_t *)(p->force_int_addr) = 1; + + // wait for the interrupt to come back. + + while (p->flush_addr != 0x10f); + + // okay, everything is synched up. + spin_unlock_irqrestore(&p->flush_lock, flags); + + return; +} + +EXPORT_SYMBOL(sn_dma_flush); + +/* * There are end cases where a deadlock can occur if interrupt * processing completes and the Bridge b_int_status bit is still set. * @@ -164,51 +271,42 @@ * to check if a specific Bridge b_int_status bit is set, and if so, * cause the setting of the corresponding interrupt bit. * - * On a XBridge (SN1), we do this by writing the appropriate Bridge Force - * Interrupt register. On SN0, or SN1 with an older Bridge, the Bridge - * Force Interrupt register does not exist, so we write the Hub - * INT_PEND_MOD register directly. Likewise for Octane, where we write the - * Heart Set Interrupt Status register directly. + * On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force + * Interrupt register. */ void -pcibr_force_interrupt(pcibr_intr_wrap_t wrap) +pcibr_force_interrupt(pcibr_intr_t intr) { -#ifdef PIC_LATER unsigned bit; - pcibr_soft_t pcibr_soft = wrap->iw_soft; + unsigned bits; + pcibr_soft_t pcibr_soft = intr->bi_soft; bridge_t *bridge = pcibr_soft->bs_base; - bit = wrap->iw_ibit; + bits = intr->bi_ibits; + for (bit = 0; bit < 8; bit++) { + if (bits & (1 << bit)) { - PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, - "pcibr_force_interrupt: bit=0x%x\n", bit)); + PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, + "pcibr_force_interrupt: bit=0x%x\n", bit)); - if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { - bridge->b_force_pin[bit].intr = 1; - } else if ((1 << bit) & *wrap->iw_stat) { - cpuid_t cpu; - unsigned intr_bit; - xtalk_intr_t xtalk_intr = - pcibr_soft->bs_intr[bit].bsi_xtalk_intr; - - intr_bit = (short) xtalk_intr_vector_get(xtalk_intr); - cpu = xtalk_intr_cpuid_get(xtalk_intr); - REMOTE_CPU_SEND_INTR(cpu, intr_bit); + if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) { + bridge->b_force_pin[bit].intr = 1; + } + } } -#endif /* PIC_LATER */ } /*ARGSUSED */ pcibr_intr_t -pcibr_intr_alloc(devfs_handle_t pconn_vhdl, +pcibr_intr_alloc(vertex_hdl_t pconn_vhdl, device_desc_t dev_desc, pciio_intr_line_t lines, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - devfs_handle_t xconn_vhdl = pcibr_soft->bs_conn; + vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; bridge_t *bridge = pcibr_soft->bs_base; int is_threaded = 0; @@ -498,25 +596,18 @@ { iopaddr_t addr; xtalk_intr_vector_t vect; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; bridge_t *bridge; + picreg_t *int_addr; addr = xtalk_intr_addr_get(xtalk_intr); vect = xtalk_intr_vector_get(xtalk_intr); vhdl = xtalk_intr_dev_get(xtalk_intr); bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0); - if (is_pic(bridge)) { - picreg_t *int_addr; - int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); - *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | + int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr); + *int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) | (PIC_INT_ADDR_HOST & addr)); - } else { - bridgereg_t *int_addr; - int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr); - *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) | - (BRIDGE_INT_ADDR_FLD & vect)); - } } /*ARGSUSED */ @@ -582,8 +673,7 @@ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, " "pcibr_int_bit=0x%x\n", int_addr, - (is_pic(bridge) ? - *(picreg_t *)int_addr : *(bridgereg_t *)int_addr), + *(picreg_t *)int_addr, pcibr_int_bit)); } @@ -699,7 +789,7 @@ xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap, (xtalk_intr_setfunc_t)pcibr_setpciint, - (void *)pcibr_int_bit); + (void *)(long)pcibr_int_bit); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", pcibr_int_bit)); @@ -707,7 +797,7 @@ } /*ARGSUSED */ -devfs_handle_t +vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) { pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; @@ -780,9 +870,6 @@ bridge->b_wid_int_lower = NEW_b_wid_int_lower; bridge->b_int_host_err = vect; -printk("pcibr_setwidint: b_wid_int_upper 0x%x b_wid_int_lower 0x%x b_int_host_err 0x%x\n", - NEW_b_wid_int_upper, NEW_b_wid_int_lower, vect); - } /* @@ -957,7 +1044,7 @@ * interrupt to avoid a potential deadlock situation. */ if (wrap->iw_hdlrcnt == 0) { - pcibr_force_interrupt(wrap); + pcibr_force_interrupt((pcibr_intr_t) wrap); } } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Tue Feb 18 10:25:13 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -41,11 +40,11 @@ void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); -int pcibr_wrb_flush(devfs_handle_t); -int pcibr_rrb_alloc(devfs_handle_t, int *, int *); -int pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *); -void pcibr_rrb_flush(devfs_handle_t); -int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +int pcibr_wrb_flush(vertex_hdl_t); +int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); +int pcibr_rrb_check(vertex_hdl_t, int *, int *, int *, int *); +void pcibr_rrb_flush(vertex_hdl_t); +int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); void pcibr_rrb_debug(char *, pcibr_soft_t); @@ -70,17 +69,15 @@ #define RRB_SIZE (4) /* sizeof rrb within reg (bits) */ #define RRB_ENABLE_BIT(bridge) (0x8) /* [BRIDGE | PIC]_RRB_EN */ -#define NUM_PDEV_BITS(bridge) (is_pic((bridge)) ? 1 : 2) -#define NUM_VDEV_BITS(bridge) (is_pic((bridge)) ? 2 : 1) -#define NUMBER_VCHANNELS(bridge) (is_pic((bridge)) ? 4 : 2) +#define NUM_PDEV_BITS(bridge) (1) +#define NUM_VDEV_BITS(bridge) (2) +#define NUMBER_VCHANNELS(bridge) (4) #define SLOT_2_PDEV(bridge, slot) ((slot) >> 1) #define SLOT_2_RRB_REG(bridge, slot) ((slot) & 0x1) /* validate that the slot and virtual channel are valid for a given bridge */ #define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \ - (is_pic((bridge)) ? \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0)) + (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) /* * Count how many RRBs are marked valid for the specified PCI slot @@ -105,16 +102,7 @@ pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) @@ -144,16 +132,7 @@ enable_bit = RRB_ENABLE_BIT(bridge); - if ( is_pic(bridge) ) { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } + tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; for (rrb_index = 0; rrb_index < 8; rrb_index++) { if ((tmp & enable_bit) != enable_bit) @@ -192,17 +171,8 @@ pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } - + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) { if ((tmp & enable_bit) != enable_bit) { /* clear the rrb and OR in the new rrb into 'reg' */ @@ -213,16 +183,7 @@ tmp = (tmp >> RRB_SIZE); } - if ( is_pic(bridge) ) { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; - } else { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - } + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; return (more ? -1 : 0); } @@ -255,17 +216,8 @@ pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | vchan_bits | pdev_bits; - if ( is_pic(bridge) ) { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)); - } else { - reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; - } - } - + reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; + for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) { if ((tmp & RRB_MASK) == rrb_bits) { /* @@ -281,16 +233,7 @@ tmp = (tmp >> RRB_SIZE); } - if ( is_pic(bridge) ) { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg; - } else { - bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; - } - } + bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg; /* call do_pcibr_rrb_clear() for all the rrbs we've freed */ for (rrb_index = 0; rrb_index < 8; rrb_index++) { @@ -337,50 +280,18 @@ * this RRB must be disabled. */ - if ( is_pic(bridge) ) { - /* wait until RRB has no outstanduing XIO packets. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } + /* wait until RRB has no outstanduing XIO packets. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb)); - - /* wait until RRB is no longer valid. */ - while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } - } else { /* io_get_sh_swapper(NASID_GET(bridge)) */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - - /* if the RRB has data, drain it. */ - if (status & BRIDGE_RRB_VALID(rrb)) { - bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); - /* wait until RRB is no longer valid. */ - while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { - ; /* XXX- beats on bridge. bad idea? */ - } - } + + /* if the RRB has data, drain it. */ + if (status & BRIDGE_RRB_VALID(rrb)) { + bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); + + /* wait until RRB is no longer valid. */ + while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { + ; /* XXX- beats on bridge. bad idea? */ } } } @@ -399,43 +310,16 @@ int shft = (RRB_SIZE * (rrbn >> 1)); unsigned long ebit = RRB_ENABLE_BIT(bridge) << shft; - if ( is_pic(bridge) ) { - rrbv = *rrbp; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - rrbv = BRIDGE_REG_GET32((&rrbp)); - } else { - rrbv = *rrbp; - } - } + rrbv = *rrbp; if (rrbv & ebit) { - if ( is_pic(bridge) ) { - *rrbp = rrbv & ~ebit; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit)); - } else { - *rrbp = rrbv & ~ebit; - } - } + *rrbp = rrbv & ~ebit; } do_pcibr_rrb_clear(bridge, rrbn); if (rrbv & ebit) { - if ( is_pic(bridge) ) { - *rrbp = rrbv; - } - else { - if (io_get_sh_swapper(NASID_GET(bridge))) { - BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv); - } else { - *rrbp = rrbv; - } - } + *rrbp = rrbv; } } @@ -475,7 +359,7 @@ * Flush all the rrb's assigned to the specified connection point. */ void -pcibr_rrb_flush(devfs_handle_t pconn_vhdl) +pcibr_rrb_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); @@ -510,7 +394,7 @@ * device hanging off the bridge. */ int -pcibr_wrb_flush(devfs_handle_t pconn_vhdl) +pcibr_wrb_flush(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); @@ -546,7 +430,7 @@ * as best we can and return 0. */ int -pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, +pcibr_rrb_alloc(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1) { @@ -753,7 +637,7 @@ */ int -pcibr_rrb_check(devfs_handle_t pconn_vhdl, +pcibr_rrb_check(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1, int *count_reserved, @@ -802,7 +686,7 @@ */ int -pcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, +pcibr_slot_initial_rrb_alloc(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -889,7 +773,7 @@ */ int -pcibr_initial_rrb(devfs_handle_t pcibr_vhdl, +pcibr_initial_rrb(vertex_hdl_t pcibr_vhdl, pciio_slot_t first, pciio_slot_t last) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Sun May 25 17:00:00 2003 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c Mon Jun 16 17:03:25 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -41,42 +40,41 @@ #endif -extern pcibr_info_t pcibr_info_get(devfs_handle_t); -extern int pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl); +extern pcibr_info_t pcibr_info_get(vertex_hdl_t); +extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -extern int pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t); +extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); extern int pcibr_pcix_rbars_calc(pcibr_soft_t); -int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, pciio_slot_t slot); -int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, +int pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); +int pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); -int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, +int pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags); -int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, +int pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); -int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot); static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *); -void pcibr_device_info_free(devfs_handle_t, pciio_slot_t); +void pcibr_device_info_free(vertex_hdl_t, pciio_slot_t); iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, pciio_space_t, int, int, int); void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t); cfg_p pcibr_find_capability(cfg_p, unsigned); -extern uint64_t do_pcibr_config_get(int, cfg_p, unsigned, unsigned); -void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); +extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); +void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); -int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, +int pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, int *sub_errorp); int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot, pcibr_slot_info_resp_t respp); -extern devfs_handle_t baseio_pci_vhdl; -int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t); +extern vertex_hdl_t baseio_pci_vhdl; +int scsi_ctlr_nums_add(vertex_hdl_t, vertex_hdl_t); /* For now .... */ @@ -111,7 +109,7 @@ #ifdef PIC_LATER int -pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_startup(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pciio_slot_t slot; @@ -127,11 +125,6 @@ /* req_slot is the 'external' slot number, convert for internal use */ slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot); - /* Do not allow start-up of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - /* Check for the valid slot */ if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); @@ -170,7 +163,7 @@ * Software shut-down the PCI slot */ int -pcibr_slot_shutdown(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_shutdown(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge; @@ -194,11 +187,6 @@ if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) return(PCI_NOT_A_SLOT); - /* Do not allow shut-down of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - #ifdef PIC_LATER /* Acquire update access to the bus */ mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO); @@ -284,7 +272,6 @@ { pcibr_info_t pcibr_info = pcibr_infoh[func]; int win; - boolean_t is_sys_critical_vertex(devfs_handle_t); funcp->resp_f_status = 0; @@ -296,9 +283,6 @@ #if defined(SUPPORT_PRINTING_V_FORMAT) sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex); #endif - if(is_sys_critical_vertex(pcibr_info->f_vertex)) { - funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL; - } funcp->resp_f_bus = pcibr_info->f_bus; funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info); @@ -345,7 +329,6 @@ reg_p b_respp; pcibr_slot_info_resp_t slotp; pcibr_slot_func_info_resp_t funcp; - boolean_t is_sys_critical_vertex(devfs_handle_t); extern void snia_kmem_free(void *, int); slotp = snia_kmem_zalloc(sizeof(*slotp), 0); @@ -368,11 +351,6 @@ slotp->resp_slot_status = pss->slot_status; slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); - - if (is_sys_critical_vertex(pss->slot_conn)) { - slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL; - } - slotp->resp_bss_ninfo = pss->bss_ninfo; for (func = 0; func < pss->bss_ninfo; func++) { @@ -455,7 +433,7 @@ * External SSRAM workaround info */ int -pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp) +pcibr_slot_query(vertex_hdl_t pcibr_vhdl, pcibr_slot_req_t reqp) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pciio_slot_t slot; @@ -481,11 +459,6 @@ return(PCI_NOT_A_SLOT); } - /* Do not allow a query of a slot in a shoehorn */ - if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) { - return(PCI_SLOT_IN_SHOEHORN); - } - /* Return information for the requested PCI slot */ if (slot != PCIIO_SLOT_NONE) { if (size < sizeof(*respp)) { @@ -534,88 +507,6 @@ return(error); } -#if 0 -/* - * pcibr_slot_reset - * Reset the PCI device in the particular slot. - * - * The Xbridge does not comply with the PCI Specification - * when resetting an indiviaudl slot. An individual slot is - * is reset by toggling the slot's bit in the Xbridge Control - * Register. The Xbridge will assert the target slot's - * (non-bussed) RST signal, but does not assert the (bussed) - * REQ64 signal as required by the specification. As - * designed, the Xbridge cannot assert the REQ64 signal - * becuase it may interfere with a bus transaction in progress. - * The practical effects of this Xbridge implementation is - * device dependent; it probably will not adversely effect - * 32-bit cards, but may disable 64-bit data transfers by those - * cards that normally support 64-bit data transfers. - * - * The Xbridge will assert REQ64 when all four slots are reset - * by simultaneously toggling all four slot reset bits in the - * Xbridge Control Register. This is basically a PCI bus reset - * and asserting the (bussed) REQ64 signal will not interfere - * with any bus transactions in progress. - * - * The Xbridge (and the SN0 Bridge) support resetting only - * four PCI bus slots via the (X)bridge Control Register. - * - * To reset an individual slot for the PCI Hot-Plug feature - * use the L1 console commands to power-down and then - * power-up the slot, or use the kernel infrastructure - * functions to power-down/up the slot when they are - * implemented for SN1. - */ -int -pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge_t *bridge; - bridgereg_t ctrlreg,tmp; - volatile bridgereg_t *wrb_flush; - - if (!pcibr_soft) - return(EINVAL); - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - /* Enable the DMA operations from this device of the xtalk widget - * (PCI host bridge in this case). - */ - xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot); - - /* Set the reset slot bit in the bridge's wid control register - * to reset the PCI slot - */ - bridge = pcibr_soft->bs_base; - - /* Read the bridge widget control and clear out the reset pin - * bit for the corresponding slot. - */ - tmp = ctrlreg = bridge->b_wid_control; - - tmp &= ~BRIDGE_CTRL_RST_PIN(slot); - - bridge->b_wid_control = tmp; - tmp = bridge->b_wid_control; - - /* Restore the old control register back. - * NOTE : PCI card gets reset when the reset pin bit - * changes from 0 (set above) to 1 (going to be set now). - */ - - bridge->b_wid_control = ctrlreg; - - /* Flush the write buffers if any !! */ - wrb_flush = &(bridge->b_wr_req_buf[slot].reg); - while (*wrb_flush); - - return(0); -} -#endif - #define PROBE_LOCK 0 /* FIXME: we're attempting to lock around accesses * to b_int_enable. This hangs pcibr_probe_slot() */ @@ -627,7 +518,7 @@ * information associated with this particular PCI device. */ int -pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -650,7 +541,7 @@ int nfunc; pciio_function_t rfunc; int func; - devfs_handle_t conn_vhdl; + vertex_hdl_t conn_vhdl; pcibr_soft_slot_t slotp; /* Get the basic software information required to proceed */ @@ -669,10 +560,6 @@ return(0); } - /* Check for a slot with any system critical functions */ - if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(EPERM); - /* Try to read the device-id/vendor-id from the config space */ cfgw = pcibr_slot_config_addr(bridge, slot, 0); @@ -701,7 +588,7 @@ if (vendor == 0xFFFF) return(ENODEV); - htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); nfunc = 1; rfunc = PCIIO_FUNC_NONE; pfail = 0; @@ -750,7 +637,7 @@ cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1); + htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); rfunc = func; } htype &= 0x7f; @@ -810,16 +697,10 @@ * Timer for these devices */ - lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1); + lt_time = do_pcibr_config_get(cfgw, PCI_CFG_LATENCY_TIMER, 1); if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) && - !((vendor == IOC3_VENDOR_ID_NUM) && - ( -#ifdef PIC_LATER - (device == IOC3_DEVICE_ID_NUM) || - (device == LINC_DEVICE_ID_NUM) || -#endif - (device == 0x5 /* RAD_DEV */)))) { + (device == 0x5 /* RAD_DEV */)) { unsigned min_gnt; unsigned min_gnt_mult; @@ -827,7 +708,7 @@ * needs in increments of 250ns. But latency timer is in * PCI clock cycles, so a conversion is needed. */ - min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1); + min_gnt = do_pcibr_config_get(cfgw, PCI_MIN_GNT, 1); if (IS_133MHZ(pcibr_soft)) min_gnt_mult = 32; /* 250ns @ 133MHz in clocks */ @@ -843,7 +724,7 @@ else lt_time = 4 * min_gnt_mult; /* 1 micro second */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); + do_pcibr_config_set(cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, "pcibr_slot_info_init: set Latency Timer for slot=%d, " @@ -851,12 +732,27 @@ PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time)); } - /* Get the PCI-X capability if running in PCI-X mode. If the func - * doesn't have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE - * pcibr_info struct so the device driver for that function is not - * called. + + /* In our architecture the setting of the cacheline size isn't + * beneficial for cards in PCI mode, but in PCI-X mode devices + * can optionally use the cacheline size value for internal + * device optimizations (See 7.1.5 of the PCI-X v1.0 spec). + * NOTE: cachline size is in doubleword increments */ if (IS_PCIX(pcibr_soft)) { + if (!do_pcibr_config_get(cfgw, PCI_CFG_CACHE_LINE, 1)) { + do_pcibr_config_set(cfgw, PCI_CFG_CACHE_LINE, 1, 0x20); + PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, + "pcibr_slot_info_init: set CacheLine for slot=%d, " + "func=%d, to 0x20\n", + PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); + } + + /* Get the PCI-X capability if running in PCI-X mode. If the func + * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE + * pcibr_info struct so the device driver for that function is not + * called. + */ if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) { printk(KERN_WARNING #if defined(SUPPORT_PRINTING_V_FORMAT) @@ -898,7 +794,7 @@ if (func == 0) slotp->slot_conn = conn_vhdl; - cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; @@ -949,7 +845,7 @@ * this could be pushed up into pciio, when we * start supporting more PCI providers. */ - base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); + base = do_pcibr_config_get(wptr, (win * 4), 4); if (base & PCI_BA_IO_SPACE) { /* BASE is in I/O space. */ @@ -975,7 +871,7 @@ } else if (base & 0xC0000000) { base = 0; /* outside permissable range */ } else if ((code == PCI_BA_MEM_64BIT) && - (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) { + (do_pcibr_config_get(wptr, ((win + 1)*4), 4) != 0)) { base = 0; /* outside permissable range */ } } @@ -983,8 +879,8 @@ if (base != 0) { /* estimate size */ size = base & -base; } else { /* calculate size */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0); /* write 1's */ - size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */ + do_pcibr_config_set(wptr, (win * 4), 4, ~0); /* write 1's */ + size = do_pcibr_config_get(wptr, (win * 4), 4); /* read back */ size &= mask; /* keep addr */ size &= -size; /* keep lsbit */ if (size == 0) @@ -995,45 +891,9 @@ pcibr_info->f_window[win].w_base = base; pcibr_info->f_window[win].w_size = size; -#if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM) - /* - * IOC3 BASE_ADDR* BUG WORKAROUND - * - - * If we write to BASE1 on the IOC3, the - * data in BASE0 is replaced. The - * original workaround was to remember - * the value of BASE0 and restore it - * when we ran off the end of the BASE - * registers; however, a later - * workaround was added (I think it was - * rev 1.44) to avoid setting up - * anything but BASE0, with the comment - * that writing all ones to BASE1 set - * the enable-parity-error test feature - * in IOC3's SCR bit 14. - * - * So, unless we defer doing any PCI - * space allocation until drivers - * attach, and set up a way for drivers - * (the IOC3 in paricular) to tell us - * generically to keep our hands off - * BASE registers, we gotta "know" about - * the IOC3 here. - * - * Too bad the PCI folks didn't reserve the - * all-zero value for 'no BASE here' (it is a - * valid code for an uninitialized BASE in - * 32-bit PCI memory space). - */ - - if ((vendor == IOC3_VENDOR_ID_NUM) && - (device == IOC3_DEVICE_ID_NUM)) - break; -#endif if (code == PCI_BA_MEM_64BIT) { win++; /* skip upper half */ - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0); /* must be zero */ + do_pcibr_config_set(wptr, (win * 4), 4, 0); /* must be zero */ } } /* next win */ } /* next func */ @@ -1056,7 +916,7 @@ int defend_against_circular_linkedlist = 0; /* Check to see if there is a capabilities pointer in the cfg header */ - if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { + if (!(do_pcibr_config_get(cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { return (NULL); } @@ -1067,14 +927,14 @@ * significant bits of the next pointer must be ignored, so we mask * with 0xfc). */ - cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); + cap_nxt = (do_pcibr_config_get(cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); while (cap_nxt && (defend_against_circular_linkedlist <= 48)) { - cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1); + cap_id = do_pcibr_config_get(cfgw, cap_nxt, 1); if (cap_id == capability) { return ((cfg_p)((char *)cfgw + cap_nxt)); } - cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc); + cap_nxt = (do_pcibr_config_get(cfgw, cap_nxt+1, 1) & 0xfc); defend_against_circular_linkedlist++; } @@ -1087,7 +947,7 @@ * with a particular PCI device. */ int -pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, +pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1223,20 +1083,21 @@ * the base registers in the card. */ int -pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; bridge_t *bridge; - size_t align_slot; iopaddr_t mask; int nbars; int nfunc; int func; int win; int rc = 0; + int align; + int align_slot; pcibr_soft = pcibr_soft_get(pcibr_vhdl); @@ -1275,7 +1136,8 @@ * the entire "lo" area is only a * megabyte, total ... */ - align_slot = (slot < 2) ? 0x200000 : 0x100000; + align_slot = 0x100000; + align = align_slot; for (func = 0; func < nfunc; ++func) { cfg_p cfgw; @@ -1300,7 +1162,7 @@ cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) + if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) nbars = 2; else nbars = PCI_CFG_BASE_ADDRS; @@ -1333,23 +1195,24 @@ continue; /* already allocated */ } + align = (win) ? size : align_slot; + + if (align < _PAGESZ) + align = _PAGESZ; /* ie. 0x00004000 */ + switch (space) { case PCIIO_SPACE_IO: base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_IO, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; break; case PCIIO_SPACE_MEM: - if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) & + if ((do_pcibr_config_get(wptr, (win * 4), 4) & PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) { - int align = size; /* ie. 0x00001000 */ - - if (align < _PAGESZ) - align = _PAGESZ; /* ie. 0x00004000 */ /* allocate from 20-bit PCI space */ base = pcibr_bus_addr_alloc(pcibr_soft, @@ -1363,7 +1226,7 @@ base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_window[win], PCIIO_SPACE_MEM32, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; } @@ -1377,7 +1240,7 @@ PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space)); } pcibr_info->f_window[win].w_base = base; - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base); + do_pcibr_config_set(wptr, (win * 4), 4, base); #if defined(SUPPORT_PRINTING_R_FORMAT) if (pcibr_debug_mask & PCIBR_DEBUG_BAR) { @@ -1405,26 +1268,22 @@ /* * Allocate space for the EXPANSION ROM - * NOTE: DO NOT DO THIS ON AN IOC3, - * as it blows the system away. */ base = size = 0; - if ((pcibr_soft->bs_slot[slot].bss_vendor_id != IOC3_VENDOR_ID_NUM) || - (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) { - + { wptr = cfgw + PCI_EXPANSION_ROM / 4; - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000); - mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4); + do_pcibr_config_set(wptr, 0, 4, 0xFFFFF000); + mask = do_pcibr_config_get(wptr, 0, 4); if (mask & 0xFFFFF000) { size = mask & -mask; base = pcibr_bus_addr_alloc(pcibr_soft, &pcibr_info->f_rwindow, PCIIO_SPACE_MEM32, - 0, size, align_slot); + 0, size, align); if (!base) rc = ENOSPC; else { - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base); + do_pcibr_config_set(wptr, 0, 4, base); PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, "pcibr_slot_addr_space_init: slot=%d, func=%d, " "ROM in [0x%X..0x%X], allocated by pcibr\n", @@ -1435,7 +1294,7 @@ } pcibr_info->f_rbase = base; pcibr_info->f_rsize = size; - + /* * if necessary, update the board's * command register to enable decoding @@ -1463,7 +1322,7 @@ pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + pci_cfg_cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); #if PCI_FBBE /* XXX- check here to see if dev can do fast-back-to-back */ if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP)) @@ -1471,7 +1330,7 @@ #endif pci_cfg_cmd_reg &= 0xFFFF; if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, + do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); } /* next func */ return(rc); @@ -1483,7 +1342,7 @@ */ int -pcibr_slot_device_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1525,8 +1384,6 @@ PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, "pcibr_slot_device_init: Device(%d): %R\n", slot, devreg, device_bits)); -#else - printk("pcibr_slot_device_init: Device(%d) 0x%x\n", slot, devreg); #endif return(0); } @@ -1536,7 +1393,7 @@ * Setup the host/guest relations for a PCI slot. */ int -pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl, +pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft; @@ -1605,18 +1462,17 @@ * card in this slot. */ int -pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl, +pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags) { pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; - async_attach_t aa = NULL; int func; - devfs_handle_t xconn_vhdl, conn_vhdl; + vertex_hdl_t xconn_vhdl, conn_vhdl; #ifdef PIC_LATER - devfs_handle_t scsi_vhdl; + vertex_hdl_t scsi_vhdl; #endif int nfunc; int error_func; @@ -1639,7 +1495,6 @@ } xconn_vhdl = pcibr_soft->bs_conn; - aa = async_attach_get_info(xconn_vhdl); nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; @@ -1656,13 +1511,6 @@ conn_vhdl = pcibr_info->f_vertex; -#ifdef LATER - /* - * Activate if and when we support cdl. - */ - if (aa) - async_attach_add_info(conn_vhdl, aa); -#endif /* LATER */ error_func = pciio_device_attach(conn_vhdl, drv_flags); @@ -1728,7 +1576,7 @@ * card in this slot. */ int -pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl, +pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags) { @@ -1736,7 +1584,7 @@ pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; int func; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; + vertex_hdl_t conn_vhdl = GRAPH_VERTEX_NONE; int nfunc; int error_func; int error_slot = 0; @@ -1811,7 +1659,7 @@ * PCI card on the bus. */ int -pcibr_slot_attach(devfs_handle_t pcibr_vhdl, +pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, @@ -1850,7 +1698,7 @@ * slot-specific freeing that needs to be done. */ int -pcibr_slot_detach(devfs_handle_t pcibr_vhdl, +pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int drv_flags, char *l1_msg, @@ -1859,10 +1707,6 @@ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); int error; - /* Make sure that we do not detach a system critical function vertex */ - if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot)) - return(PCI_IS_SYS_CRITICAL); - /* Call the device detach function */ error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); if (error) { @@ -1892,61 +1736,6 @@ } /* - * pcibr_is_slot_sys_critical - * Check slot for any functions that are system critical. - * Return 1 if any are system critical or 0 otherwise. - * - * This function will always return 0 when called by - * pcibr_attach() because the system critical vertices - * have not yet been set in the hwgraph. - */ -int -pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - devfs_handle_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int func; - boolean_t is_sys_critical_vertex(devfs_handle_t); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return(EINVAL); - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(EINVAL); - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - if (is_sys_critical_vertex(conn_vhdl)) { -#if defined(SUPPORT_PRINTING_V_FORMAT) - printk(KERN_WARNING "%v is a system critical device vertex\n", conn_vhdl); -#else - printk(KERN_WARNING "%p is a system critical device vertex\n", (void *)conn_vhdl); -#endif - return(1); - } - - } - - return(0); -} - -/* * pcibr_probe_slot_pic: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. @@ -1984,57 +1773,6 @@ } /* - * pcibr_probe_slot_non_pic: read a config space word - * while trapping any errors; return zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -static int -pcibr_probe_slot_non_pic(bridge_t *bridge, - cfg_p cfg, - unsigned *valp) -{ - int rv; - bridgereg_t b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0; - extern int badaddr_val(volatile void *, int, volatile void *); - - b_old_enable = bridge->b_int_enable; - b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT; - bridge->b_int_enable = b_new_enable; - - /* - * The xbridge doesn't clear b_err_int_view unless - * multi-err is cleared... - */ - if (is_xbridge(bridge)) { - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - } - - if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) { - bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR; - (void) bridge->b_wid_tflush; /* flushbus */ - } - rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp); - /* - * The xbridge doesn't set master timeout in b_int_status - * here. Fortunately it's in error_interrupt_view. - */ - if (is_xbridge(bridge)) { - if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) { - bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR; - rv = 1; /* unoccupied slot */ - } - } - bridge->b_int_enable = b_old_enable; - bridge->b_wid_tflush; /* wait until Bridge PIO complete */ - - return(rv); -} - - -/* * pcibr_probe_slot: read a config space word * while trapping any errors; return zero if * all went OK, or nonzero if there was an error. @@ -2046,15 +1784,12 @@ cfg_p cfg, unsigned *valp) { - if ( is_pic(bridge) ) - return(pcibr_probe_slot_pic(bridge, cfg, valp)); - else - return(pcibr_probe_slot_non_pic(bridge, cfg, valp)); + return(pcibr_probe_slot_pic(bridge, cfg, valp)); } void -pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot) +pcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); pcibr_info_t pcibr_info; @@ -2079,9 +1814,9 @@ /* Disable memory and I/O BARs */ cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0); - cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4); + cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); - do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg); + do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg); for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) @@ -2181,7 +1916,7 @@ * io_brick_tab[] array defined in ml/SN/iograph.c */ int -pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) +pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl) { pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); xwidgetnum_t widget = pcibr_soft->bs_xid; diff -Nru a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c --- a/arch/ia64/sn/io/sn2/pciio.c Mon Feb 24 05:30:35 2003 +++ b/arch/ia64/sn/io/sn2/pciio.c Fri May 16 04:18:19 2003 @@ -7,8 +7,6 @@ * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ -#define USRPCI 0 - #include #include #include @@ -44,13 +42,8 @@ #undef DEBUG_PCIIO /* turn this on for yet more console output */ -#define GET_NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DO_DEL(ptr) (kfree(ptr)) - char pciio_info_fingerprint[] = "pciio_info"; -cdl_p pciio_registry = NULL; - int badaddr_val(volatile void *addr, int len, volatile void *ptr) { @@ -97,8 +90,6 @@ extern char master_baseio_wid; if (master_baseio_nasid < 0) { - nasid_t tmp; - master_baseio_nasid = ia64_sn_get_master_baseio_nasid(); if ( master_baseio_nasid >= 0 ) { @@ -109,13 +100,13 @@ } int -hub_dma_enabled(devfs_handle_t xconn_vhdl) +hub_dma_enabled(vertex_hdl_t xconn_vhdl) { return(0); } int -hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +hub_error_devenable(vertex_hdl_t xconn_vhdl, int devnum, int error_code) { return(0); } @@ -153,66 +144,64 @@ */ #if !defined(DEV_FUNC) -static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev); +static pciio_provider_t *pciio_to_provider_fns(vertex_hdl_t dev); #endif -pciio_piomap_t pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); +pciio_piomap_t pciio_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); void pciio_piomap_free(pciio_piomap_t); caddr_t pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t); void pciio_piomap_done(pciio_piomap_t); -caddr_t pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -caddr_t pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); +caddr_t pciio_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); +caddr_t pciio_pio_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned); -iopaddr_t pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t); -void pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t); +iopaddr_t pciio_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t); +void pciio_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); -pciio_dmamap_t pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +pciio_dmamap_t pciio_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void pciio_dmamap_free(pciio_dmamap_t); iopaddr_t pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t); -alenlist_t pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned); void pciio_dmamap_done(pciio_dmamap_t); -iopaddr_t pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +iopaddr_t pciio_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); void pciio_dmamap_drain(pciio_dmamap_t); -void pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t); -void pciio_dmalist_drain(devfs_handle_t, alenlist_t); -iopaddr_t pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); +void pciio_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); +void pciio_dmalist_drain(vertex_hdl_t, alenlist_t); +iopaddr_t pciio_dma_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned); -pciio_intr_t pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t); +pciio_intr_t pciio_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); void pciio_intr_free(pciio_intr_t); int pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t); void pciio_intr_disconnect(pciio_intr_t); -devfs_handle_t pciio_intr_cpu_get(pciio_intr_t); +vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t); void pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t); -void pciio_provider_startup(devfs_handle_t); -void pciio_provider_shutdown(devfs_handle_t); +void pciio_provider_startup(vertex_hdl_t); +void pciio_provider_shutdown(vertex_hdl_t); -pciio_endian_t pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t); -pciio_priority_t pciio_priority_set(devfs_handle_t, pciio_priority_t); -devfs_handle_t pciio_intr_dev_get(pciio_intr_t); +pciio_endian_t pciio_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); +pciio_priority_t pciio_priority_set(vertex_hdl_t, pciio_priority_t); +vertex_hdl_t pciio_intr_dev_get(pciio_intr_t); -devfs_handle_t pciio_pio_dev_get(pciio_piomap_t); +vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t); pciio_slot_t pciio_pio_slot_get(pciio_piomap_t); pciio_space_t pciio_pio_space_get(pciio_piomap_t); iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t); ulong pciio_pio_mapsz_get(pciio_piomap_t); caddr_t pciio_pio_kvaddr_get(pciio_piomap_t); -devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t); +vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t); pciio_slot_t pciio_dma_slot_get(pciio_dmamap_t); -pciio_info_t pciio_info_chk(devfs_handle_t); -pciio_info_t pciio_info_get(devfs_handle_t); -void pciio_info_set(devfs_handle_t, pciio_info_t); -devfs_handle_t pciio_info_dev_get(pciio_info_t); +pciio_info_t pciio_info_chk(vertex_hdl_t); +pciio_info_t pciio_info_get(vertex_hdl_t); +void pciio_info_set(vertex_hdl_t, pciio_info_t); +vertex_hdl_t pciio_info_dev_get(pciio_info_t); pciio_slot_t pciio_info_slot_get(pciio_info_t); pciio_function_t pciio_info_function_get(pciio_info_t); pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t); pciio_device_id_t pciio_info_device_id_get(pciio_info_t); -devfs_handle_t pciio_info_master_get(pciio_info_t); +vertex_hdl_t pciio_info_master_get(pciio_info_t); arbitrary_info_t pciio_info_mfast_get(pciio_info_t); pciio_provider_t *pciio_info_pops_get(pciio_info_t); error_handler_f *pciio_info_efunc_get(pciio_info_t); @@ -223,30 +212,28 @@ iopaddr_t pciio_info_rom_base_get(pciio_info_t); size_t pciio_info_rom_size_get(pciio_info_t); -void pciio_init(void); -int pciio_attach(devfs_handle_t); +int pciio_attach(vertex_hdl_t); -void pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns); -void pciio_provider_unregister(devfs_handle_t); -pciio_provider_t *pciio_provider_fns_get(devfs_handle_t); +void pciio_provider_register(vertex_hdl_t, pciio_provider_t *pciio_fns); +void pciio_provider_unregister(vertex_hdl_t); +pciio_provider_t *pciio_provider_fns_get(vertex_hdl_t); int pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned); -void pciio_driver_unregister(char *driver_prefix); -devfs_handle_t pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +vertex_hdl_t pciio_device_register(vertex_hdl_t, vertex_hdl_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -void pciio_device_unregister(devfs_handle_t); -pciio_info_t pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); +void pciio_device_unregister(vertex_hdl_t); +pciio_info_t pciio_device_info_new(pciio_info_t, vertex_hdl_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); void pciio_device_info_free(pciio_info_t); -devfs_handle_t pciio_device_info_register(devfs_handle_t, pciio_info_t); -void pciio_device_info_unregister(devfs_handle_t, pciio_info_t); -int pciio_device_attach(devfs_handle_t, int); -int pciio_device_detach(devfs_handle_t, int); -void pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t); - -int pciio_reset(devfs_handle_t); -int pciio_write_gather_flush(devfs_handle_t); -int pciio_slot_inuse(devfs_handle_t); +vertex_hdl_t pciio_device_info_register(vertex_hdl_t, pciio_info_t); +void pciio_device_info_unregister(vertex_hdl_t, pciio_info_t); +int pciio_device_attach(vertex_hdl_t, int); +int pciio_device_detach(vertex_hdl_t, int); +void pciio_error_register(vertex_hdl_t, error_handler_f *, error_handler_arg_t); + +int pciio_reset(vertex_hdl_t); +int pciio_write_gather_flush(vertex_hdl_t); +int pciio_slot_inuse(vertex_hdl_t); /* ===================================================================== * Provider Function Location @@ -261,7 +248,7 @@ #if !defined(DEV_FUNC) static pciio_provider_t * -pciio_to_provider_fns(devfs_handle_t dev) +pciio_to_provider_fns(vertex_hdl_t dev) { pciio_info_t card_info; pciio_provider_t *provider_fns; @@ -316,7 +303,7 @@ */ pciio_piomap_t -pciio_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +pciio_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* lowest address (or offset in window) */ @@ -354,7 +341,7 @@ } caddr_t -pciio_piotrans_addr(devfs_handle_t dev, /* translate for this device */ +pciio_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* starting address (or offset in window) */ @@ -366,7 +353,7 @@ } caddr_t -pciio_pio_addr(devfs_handle_t dev, /* translate for this device */ +pciio_pio_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ iopaddr_t addr, /* starting address (or offset in window) */ @@ -410,7 +397,7 @@ } iopaddr_t -pciio_piospace_alloc(devfs_handle_t dev, /* Device requiring space */ +pciio_piospace_alloc(vertex_hdl_t dev, /* Device requiring space */ device_desc_t dev_desc, /* Device descriptor */ pciio_space_t space, /* MEM32/MEM64/IO */ size_t byte_count, /* Size of mapping */ @@ -423,7 +410,7 @@ } void -pciio_piospace_free(devfs_handle_t dev, /* Device freeing space */ +pciio_piospace_free(vertex_hdl_t dev, /* Device freeing space */ pciio_space_t space, /* Type of space */ iopaddr_t pciaddr, /* starting address */ size_t byte_count) @@ -440,7 +427,7 @@ */ pciio_dmamap_t -pciio_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ +pciio_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) @@ -465,15 +452,6 @@ (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); } -alenlist_t -pciio_dmamap_list(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(pciio_dmamap, dmamap_list) - (CAST_DMAMAP(pciio_dmamap), alenlist, flags); -} - void pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) { @@ -482,7 +460,7 @@ } iopaddr_t -pciio_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ +pciio_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -492,18 +470,8 @@ (dev, dev_desc, paddr, byte_count, flags); } -alenlist_t -pciio_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - iopaddr_t -pciio_dma_addr(devfs_handle_t dev, /* translate for this device */ +pciio_dma_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -553,14 +521,14 @@ } void -pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +pciio_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) { DEV_FUNC(dev, dmaaddr_drain) (dev, addr, size); } void -pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list) +pciio_dmalist_drain(vertex_hdl_t dev, alenlist_t list) { DEV_FUNC(dev, dmalist_drain) (dev, list); @@ -577,10 +545,10 @@ * Return resource handle in intr_hdl. */ pciio_intr_t -pciio_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ +pciio_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ pciio_intr_line_t lines, /* INTR line(s) to attach */ - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { /* owner of this interrupt */ return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) (dev, dev_desc, lines, owner_dev); @@ -624,7 +592,7 @@ * Return a hwgraph vertex that represents the CPU currently * targeted by an interrupt. */ -devfs_handle_t +vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t intr_hdl) { return INTR_FUNC(intr_hdl, intr_cpu_get) @@ -663,12 +631,12 @@ */ static pciio_info_t pciio_cardinfo_get( - devfs_handle_t pciio_vhdl, + vertex_hdl_t pciio_vhdl, pciio_slot_t pci_slot) { char namebuf[16]; pciio_info_t info = 0; - devfs_handle_t conn; + vertex_hdl_t conn; pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE); if (GRAPH_SUCCESS == @@ -699,22 +667,16 @@ /*ARGSUSED */ int pciio_error_handler( - devfs_handle_t pciio_vhdl, + vertex_hdl_t pciio_vhdl, int error_code, ioerror_mode_t mode, ioerror_t *ioerror) { pciio_info_t pciio_info; - devfs_handle_t pconn_vhdl; -#if USRPCI - devfs_handle_t usrpci_v; -#endif + vertex_hdl_t pconn_vhdl; pciio_slot_t slot; int retval; -#ifdef EHE_ENABLE - error_state_t e_state; -#endif /* EHE_ENABLE */ #if DEBUG && ERROR_DEBUG printk("%v: pciio_error_handler\n", pciio_vhdl); @@ -733,16 +695,6 @@ if (pciio_info && pciio_info->c_efunc) { pconn_vhdl = pciio_info_dev_get(pciio_info); -#ifdef EHE_ENABLE - e_state = error_state_get(pciio_vhdl); - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif - retval = pciio_info->c_efunc (pciio_info->c_einfo, error_code, mode, ioerror); if (retval != IOERROR_UNHANDLED) @@ -770,49 +722,11 @@ pconn_vhdl = pciio_info_dev_get(pciio_info); -#ifdef EHE_ENABLE - e_state = error_state_get(pciio_vhdl); - - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE); - - if (error_state_set(pconn_vhdl,e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); -#endif /* EHE_ENABLE */ - retval = pciio_info->c_efunc (pciio_info->c_einfo, error_code, mode, ioerror); if (retval != IOERROR_UNHANDLED) return retval; } - -#if USRPCI - /* If the USRPCI driver is available and - * knows about this connection point, - * deliver the error to it. - * - * OK to use pconn_vhdl here, even though we - * have already UNREF'd it, since we know that - * it is not going away. - */ - pconn_vhdl = pciio_info_dev_get(pciio_info); - if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) { - iopaddr_t busaddr; - IOERROR_GETVALUE(busaddr, ioerror, busaddr); - retval = usrpci_error_handler (usrpci_v, error_code, busaddr); - hwgraph_vertex_unref(usrpci_v); - if (retval != IOERROR_UNHANDLED) { - /* - * This unref is not needed. If this code is called often enough, - * the system will crash, due to vertex reference count reaching 0, - * causing vertex to be unallocated. -jeremy - * hwgraph_vertex_unref(pconn_vhdl); - */ - return retval; - } - } -#endif } } @@ -829,7 +743,7 @@ * Startup a crosstalk provider */ void -pciio_provider_startup(devfs_handle_t pciio_provider) +pciio_provider_startup(vertex_hdl_t pciio_provider) { DEV_FUNC(pciio_provider, provider_startup) (pciio_provider); @@ -839,7 +753,7 @@ * Shutdown a crosstalk provider */ void -pciio_provider_shutdown(devfs_handle_t pciio_provider) +pciio_provider_shutdown(vertex_hdl_t pciio_provider) { DEV_FUNC(pciio_provider, provider_shutdown) (pciio_provider); @@ -851,7 +765,7 @@ * how things will actually appear in memory. */ pciio_endian_t -pciio_endian_set(devfs_handle_t dev, +pciio_endian_set(vertex_hdl_t dev, pciio_endian_t device_end, pciio_endian_t desired_end) { @@ -880,7 +794,7 @@ * Specify PCI arbitration priority. */ pciio_priority_t -pciio_priority_set(devfs_handle_t dev, +pciio_priority_set(vertex_hdl_t dev, pciio_priority_t device_prio) { ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW)); @@ -893,7 +807,7 @@ * Read value of configuration register */ uint64_t -pciio_config_get(devfs_handle_t dev, +pciio_config_get(vertex_hdl_t dev, unsigned reg, unsigned size) { @@ -923,7 +837,7 @@ * Change value of configuration register */ void -pciio_config_set(devfs_handle_t dev, +pciio_config_set(vertex_hdl_t dev, unsigned reg, unsigned size, uint64_t value) @@ -953,7 +867,7 @@ * Issue a hardware reset to a card. */ int -pciio_reset(devfs_handle_t dev) +pciio_reset(vertex_hdl_t dev) { return DEV_FUNC(dev, reset) (dev); } @@ -962,19 +876,19 @@ * flush write gather buffers */ int -pciio_write_gather_flush(devfs_handle_t dev) +pciio_write_gather_flush(vertex_hdl_t dev) { return DEV_FUNC(dev, write_gather_flush) (dev); } -devfs_handle_t +vertex_hdl_t pciio_intr_dev_get(pciio_intr_t pciio_intr) { return (pciio_intr->pi_dev); } /****** Generic crosstalk pio interfaces ******/ -devfs_handle_t +vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap) { return (pciio_piomap->pp_dev); @@ -1011,7 +925,7 @@ } /****** Generic crosstalk dma interfaces ******/ -devfs_handle_t +vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap) { return (pciio_dmamap->pd_dev); @@ -1026,7 +940,7 @@ /****** Generic pci slot information interfaces ******/ pciio_info_t -pciio_info_chk(devfs_handle_t pciio) +pciio_info_chk(vertex_hdl_t pciio) { arbitrary_info_t ainfo = 0; @@ -1035,7 +949,7 @@ } pciio_info_t -pciio_info_get(devfs_handle_t pciio) +pciio_info_get(vertex_hdl_t pciio) { pciio_info_t pciio_info; @@ -1051,18 +965,17 @@ #endif /* DEBUG_PCIIO */ if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { + (pciio_info->c_fingerprint != pciio_info_fingerprint) + && (pciio_info->c_fingerprint != NULL)) { - return((pciio_info_t)-1); /* Should panic .. */ + return((pciio_info_t)-1); /* Should panic .. */ } - return pciio_info; } void -pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info) +pciio_info_set(vertex_hdl_t pciio, pciio_info_t pciio_info) { if (pciio_info != NULL) pciio_info->c_fingerprint = pciio_info_fingerprint; @@ -1076,7 +989,7 @@ (arbitrary_info_t) pciio_info); } -devfs_handle_t +vertex_hdl_t pciio_info_dev_get(pciio_info_t pciio_info) { return (pciio_info->c_vertex); @@ -1106,7 +1019,7 @@ return (pciio_info->c_device); } -devfs_handle_t +vertex_hdl_t pciio_info_master_get(pciio_info_t pciio_info) { return (pciio_info->c_master); @@ -1172,47 +1085,12 @@ */ /* - * pciioinit: called once during device driver - * initializtion if this driver is configured into - * the system. - */ -void -pciio_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("pciio_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (pciio_registry == NULL) { - cp = cdl_new(EDGE_LBL_PCI, "vendor", "device"); - if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(pciio_registry != NULL); -} - -/* * pciioattach: called for each vertex in the graph * that is a PCI provider. */ /*ARGSUSED */ int -pciio_attach(devfs_handle_t pciio) +pciio_attach(vertex_hdl_t pciio) { #if DEBUG && ATTACH_DEBUG #if defined(SUPPORT_PRINTING_V_FORMAT) @@ -1228,7 +1106,7 @@ * Associate a set of pciio_provider functions with a vertex. */ void -pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns) +pciio_provider_register(vertex_hdl_t provider, pciio_provider_t *pciio_fns) { hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); } @@ -1237,7 +1115,7 @@ * Disassociate a set of pciio_provider functions with a vertex. */ void -pciio_provider_unregister(devfs_handle_t provider) +pciio_provider_unregister(vertex_hdl_t provider) { arbitrary_info_t ainfo; @@ -1249,7 +1127,7 @@ * provider. */ pciio_provider_t * -pciio_provider_fns_get(devfs_handle_t provider) +pciio_provider_fns_get(vertex_hdl_t provider) { arbitrary_info_t ainfo = 0; @@ -1265,86 +1143,13 @@ char *driver_prefix, unsigned flags) { - /* a driver's init routine might call - * pciio_driver_register before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - return cdl_add_driver(pciio_registry, - vendor_id, device_id, - driver_prefix, flags, NULL); -} - -/* - * Remove an initialization function. - */ -void -pciio_driver_unregister( - char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called register; so - * we can assume we have a registry here. - */ - ASSERT(pciio_registry != NULL); - - cdl_del_driver(pciio_registry, driver_prefix, NULL); -} - -/* - * Set the slot status for a device supported by the - * driver being registered. - */ -void -pciio_driver_reg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Set the slot status for a device supported by the - * driver being unregistered. - */ -void -pciio_driver_unreg_callback( - devfs_handle_t pconn_vhdl, - int key1, - int key2, - int error) -{ -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -pciio_iterate(char *driver_prefix, - pciio_iter_f * func) -{ - /* a driver's init routine might call - * pciio_iterate before the - * system calls pciio_init; so we - * make the init call ourselves here. - */ - if (pciio_registry == NULL) - pciio_init(); - - ASSERT(pciio_registry != NULL); - - cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func); + return(0); } -devfs_handle_t +vertex_hdl_t pciio_device_register( - devfs_handle_t connectpt, /* vertex for /hw/.../pciio/%d */ - devfs_handle_t master, /* card's master ASIC (PCI provider) */ + vertex_hdl_t connectpt, /* vertex for /hw/.../pciio/%d */ + vertex_hdl_t master, /* card's master ASIC (PCI provider) */ pciio_slot_t slot, /* card's slot */ pciio_function_t func, /* card's func */ pciio_vendor_id_t vendor_id, @@ -1356,7 +1161,7 @@ } void -pciio_device_unregister(devfs_handle_t pconn) +pciio_device_unregister(vertex_hdl_t pconn) { DEV_FUNC(pconn,device_unregister)(pconn); } @@ -1364,14 +1169,14 @@ pciio_info_t pciio_device_info_new( pciio_info_t pciio_info, - devfs_handle_t master, + vertex_hdl_t master, pciio_slot_t slot, pciio_function_t func, pciio_vendor_id_t vendor_id, pciio_device_id_t device_id) { if (!pciio_info) - GET_NEW(pciio_info); + NEW(pciio_info); ASSERT(pciio_info != NULL); pciio_info->c_slot = slot; @@ -1396,14 +1201,14 @@ BZERO((char *)pciio_info,sizeof(pciio_info)); } -devfs_handle_t +vertex_hdl_t pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info) /* details about the connectpt */ { char name[32]; - devfs_handle_t pconn; - int device_master_set(devfs_handle_t, devfs_handle_t); + vertex_hdl_t pconn; + int device_master_set(vertex_hdl_t, vertex_hdl_t); pciio_slot_func_to_name(name, pciio_info->c_slot, @@ -1429,25 +1234,15 @@ */ device_master_set(pconn, pciio_info->c_master); - -#if USRPCI - /* - * Call into usrpci provider to let it initialize for - * the given slot. - */ - if (pciio_info->c_slot != PCIIO_SLOT_NONE) - usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot); -#endif - return pconn; } void -pciio_device_info_unregister(devfs_handle_t connectpt, +pciio_device_info_unregister(vertex_hdl_t connectpt, pciio_info_t pciio_info) { char name[32]; - devfs_handle_t pconn; + vertex_hdl_t pconn; if (!pciio_info) return; @@ -1470,7 +1265,7 @@ /* Add the pci card inventory information to the hwgraph */ static void -pciio_device_inventory_add(devfs_handle_t pconn_vhdl) +pciio_device_inventory_add(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -1488,7 +1283,7 @@ /*ARGSUSED */ int -pciio_device_attach(devfs_handle_t pconn, +pciio_device_attach(vertex_hdl_t pconn, int drv_flags) { pciio_info_t pciio_info; @@ -1507,34 +1302,15 @@ * pciio_init) have been called; so we * can assume here that we have a registry. */ - ASSERT(pciio_registry != NULL); - return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags)); + return(cdl_add_connpt(vendor_id, device_id, pconn, drv_flags)); } int -pciio_device_detach(devfs_handle_t pconn, +pciio_device_detach(vertex_hdl_t pconn, int drv_flags) { - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - ASSERT(pciio_registry != NULL); - - return(cdl_del_connpt(pciio_registry, vendor_id, device_id, - pconn, drv_flags)); - + return(0); } /* SN2 */ @@ -1728,7 +1504,7 @@ * cooperating drivers, well, cooperate ... */ void -pciio_error_register(devfs_handle_t pconn, +pciio_error_register(vertex_hdl_t pconn, error_handler_f *efunc, error_handler_arg_t einfo) { @@ -1746,7 +1522,7 @@ * vhdl is the vertex for the slot */ int -pciio_slot_inuse(devfs_handle_t pconn_vhdl) +pciio_slot_inuse(vertex_hdl_t pconn_vhdl) { pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); @@ -1763,7 +1539,7 @@ } int -pciio_dma_enabled(devfs_handle_t pconn_vhdl) +pciio_dma_enabled(vertex_hdl_t pconn_vhdl) { return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl); } @@ -1777,7 +1553,7 @@ /* * These are complementary Linux interfaces that takes in a pci_dev * as the - * first arguement instead of devfs_handle_t. + * first arguement instead of vertex_hdl_t. */ iopaddr_t snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned); pciio_dmamap_t snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned); @@ -1800,7 +1576,7 @@ int *count_vchan0, int *count_vchan1) { - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1); } @@ -1811,7 +1587,7 @@ pciio_endian_t device_end, pciio_endian_t desired_end) { - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); return DEV_FUNC(dev, endian_set) (dev, device_end, desired_end); @@ -1825,7 +1601,7 @@ unsigned flags) { /* defined in dma.h */ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be @@ -1842,7 +1618,7 @@ unsigned flags) { /* defined in dma.h */ - devfs_handle_t dev = PCIDEV_VERTEX(pci_dev); + vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); /* * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be diff -Nru a/arch/ia64/sn/io/sn2/pic.c b/arch/ia64/sn/io/sn2/pic.c --- a/arch/ia64/sn/io/sn2/pic.c Mon Feb 24 05:30:53 2003 +++ b/arch/ia64/sn/io/sn2/pic.c Fri May 23 03:37:38 2003 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -36,29 +35,16 @@ #define PCI_BUS_NO_1 1 -int pic_devflag = D_MP; +extern int pcibr_attach2(vertex_hdl_t, bridge_t *, vertex_hdl_t, int, pcibr_soft_t *); +extern void pcibr_driver_reg_callback(vertex_hdl_t, int, int, int); +extern void pcibr_driver_unreg_callback(vertex_hdl_t, int, int, int); -extern int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, int, pcibr_soft_t *); -extern void pcibr_driver_reg_callback(devfs_handle_t, int, int, int); -extern void pcibr_driver_unreg_callback(devfs_handle_t, int, int, int); - - -void -pic_init(void) -{ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pic_init()\n")); - - xwidget_driver_register(PIC_WIDGET_PART_NUM_BUS0, - PIC_WIDGET_MFGR_NUM, - "pic_", - 0); -} /* * copy inventory_t from conn_v to peer_conn_v */ int -pic_bus1_inventory_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v) +pic_bus1_inventory_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v) { inventory_t *pinv, *peer_pinv; @@ -66,7 +52,7 @@ (arbitrary_info_t *)&pinv) == GRAPH_SUCCESS) { NEW(peer_pinv); - bcopy(pinv, peer_pinv, sizeof(inventory_t)); + bcopy((const char *)pinv, (char *)peer_pinv, sizeof(inventory_t)); if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_INVENT, (arbitrary_info_t)peer_pinv) != GRAPH_SUCCESS) { DEL(peer_pinv); @@ -75,8 +61,7 @@ return 1; } - printk("pic_bus1_inventory_dup: cannot get INFO_LBL_INVENT from 0x%lx\n ", - conn_v); + printk("pic_bus1_inventory_dup: cannot get INFO_LBL_INVENT from 0x%lx\n ", (uint64_t)conn_v); return 0; } @@ -84,13 +69,12 @@ * copy xwidget_info_t from conn_v to peer_conn_v */ int -pic_bus1_widget_info_dup(devfs_handle_t conn_v, devfs_handle_t peer_conn_v, +pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, cnodeid_t xbow_peer) { xwidget_info_t widget_info, peer_widget_info; char peer_path[256]; - char *p; - devfs_handle_t peer_hubv; + vertex_hdl_t peer_hubv; hubinfo_t peer_hub_info; /* get the peer hub's widgetid */ @@ -126,7 +110,7 @@ } printk("pic_bus1_widget_info_dup: " - "cannot get INFO_LBL_XWIDGET from 0x%lx\n", conn_v); + "cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v); return 0; } @@ -138,15 +122,15 @@ * If not successful, return zero and both buses will attach to the * vertex passed into pic_attach(). */ -devfs_handle_t -pic_bus1_redist(nasid_t nasid, devfs_handle_t conn_v) +vertex_hdl_t +pic_bus1_redist(nasid_t nasid, vertex_hdl_t conn_v) { cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); cnodeid_t xbow_peer = -1; char pathname[256], peer_path[256], tmpbuf[256]; char *p; int rc; - devfs_handle_t peer_conn_v; + vertex_hdl_t peer_conn_v; int pos; slabid_t slab; @@ -155,7 +139,7 @@ /* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */ /* sprintf(pathname, "%v", conn_v); */ xbow_peer = NASID_TO_COMPACT_NODEID(NODEPDA(cnode)->xbow_peer); - pos = devfs_generate_path(conn_v, tmpbuf, 256); + pos = hwgfs_generate_path(conn_v, tmpbuf, 256); strcpy(pathname, &tmpbuf[pos]); p = pathname + strlen("hw/module/001c01/slab/0/"); @@ -170,7 +154,7 @@ rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v); if (GRAPH_SUCCESS == rc) printk("pic_attach: found unexpected vertex: 0x%lx\n", - peer_conn_v); + (uint64_t)peer_conn_v); else if (GRAPH_NOT_FOUND != rc) { printk("pic_attach: hwgraph_traverse unexpectedly" " returned 0x%x\n", rc); @@ -208,13 +192,13 @@ int -pic_attach(devfs_handle_t conn_v) +pic_attach(vertex_hdl_t conn_v) { int rc; bridge_t *bridge0, *bridge1 = (bridge_t *)0; - devfs_handle_t pcibr_vhdl0, pcibr_vhdl1 = (devfs_handle_t)0; + vertex_hdl_t pcibr_vhdl0, pcibr_vhdl1 = (vertex_hdl_t)0; pcibr_soft_t bus0_soft, bus1_soft = (pcibr_soft_t)0; - devfs_handle_t conn_v0, conn_v1, peer_conn_v; + vertex_hdl_t conn_v0, conn_v1, peer_conn_v; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n")); @@ -229,11 +213,11 @@ conn_v0 = conn_v1 = conn_v; /* If dual-ported then split the two PIC buses across both Cbricks */ - if (peer_conn_v = pic_bus1_redist(NASID_GET(bridge0), conn_v)) + if ((peer_conn_v = (pic_bus1_redist(NASID_GET(bridge0), conn_v)))) conn_v1 = peer_conn_v; /* - * Create the vertex for the PCI buses, which week + * Create the vertex for the PCI buses, which we * will also use to hold the pcibr_soft and * which will be the "master" vertex for all the * pciio connection points we will hang off it. @@ -266,7 +250,6 @@ /* save a pointer to the PIC's other bus's soft struct */ bus0_soft->bs_peers_soft = bus1_soft; bus1_soft->bs_peers_soft = bus0_soft; - bus0_soft->bs_peers_soft = (pcibr_soft_t)0; PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach: bus0_soft=0x%x, bus1_soft=0x%x\n", @@ -294,10 +277,8 @@ (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, (pciio_dmamap_free_f *) pcibr_dmamap_free, (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_list_f *) pcibr_dmamap_list, (pciio_dmamap_done_f *) pcibr_dmamap_done, (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmatrans_list_f *) pcibr_dmatrans_list, (pciio_dmamap_drain_f *) pcibr_dmamap_drain, (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, (pciio_dmalist_drain_f *) pcibr_dmalist_drain, diff -Nru a/arch/ia64/sn/io/sn2/sgi_io_init.c b/arch/ia64/sn/io/sn2/sgi_io_init.c --- a/arch/ia64/sn/io/sn2/sgi_io_init.c Mon Feb 24 05:34:00 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,226 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void mlreset(void); -extern int init_hcl(void); -extern void klgraph_hack_init(void); -extern void hubspc_init(void); -extern void pciio_init(void); -extern void pcibr_init(void); -extern void xtalk_init(void); -extern void xbow_init(void); -extern void xbmon_init(void); -extern void pciiox_init(void); -extern void pic_init(void); -extern void usrpci_init(void); -extern void ioc3_init(void); -extern void initialize_io(void); -extern void klhwg_add_all_modules(devfs_handle_t); -extern void klhwg_add_all_nodes(devfs_handle_t); - -void sn_mp_setup(void); -extern devfs_handle_t hwgraph_root; -extern void io_module_init(void); -extern void pci_bus_cvlink_init(void); -extern void temp_hack(void); - -extern int pci_bus_to_hcl_cvlink(void); - -/* #define DEBUG_IO_INIT 1 */ -#ifdef DEBUG_IO_INIT -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_IO_INIT */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - - nasid = COMPACT_TO_NASID_NODEID(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode); - - npdap = NODEPDA(cnode); - - REMOTE_HUB_S(nasid, IIO_IWEIM, 0x8000); - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval= 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval= 0x0; - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ -#ifdef BRINGUP2 - REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff ); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - //REMOTE_HUB_S(nasid, IIO_IWI, 0x00FF00FF00FFFFFF); -#endif - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void -sgi_master_io_infr_init(void) -{ - int cnode; - extern void kdba_io_init(); - - /* - * Do any early init stuff .. einit_tbl[] etc. - */ - init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */ - - /* - * initialize the Linux PCI to xwidget vertexes .. - */ - pci_bus_cvlink_init(); - - kdba_io_init(); - -#ifdef BRINGUP - /* - * Hack to provide statically initialzed klgraph entries. - */ - DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n"); - klgraph_hack_init(); -#endif /* BRINGUP */ - - /* - * This is the Master CPU. Emulate mlsetup and main.c in Irix. - */ - mlreset(); - - /* - * allowboot() is called by kern/os/main.c in main() - * Emulate allowboot() ... - * per_cpu_init() - only need per_hub_init() - * cpu_io_setup() - Nothing to do. - * - */ - sn_mp_setup(); - - for (cnode = 0; cnode < numnodes; cnode++) { - per_hub_init(cnode); - } - - /* We can do headless hub cnodes here .. */ - - /* - * io_init[] stuff. - * - * Get SGI IO Infrastructure drivers to init and register with - * each other etc. - */ - - hubspc_init(); - pciio_init(); - pcibr_init(); - pic_init(); - xtalk_init(); - xbow_init(); - xbmon_init(); - pciiox_init(); - usrpci_init(); - ioc3_init(); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - initialize_io(); - pci_bus_to_hcl_cvlink(); - -#ifdef CONFIG_PCIBA - DBG("--> sgi_master_io_infr_init: calling pciba_init()\n"); -#ifndef BRINGUP2 - pciba_init(); -#endif -#endif -} - -/* - * One-time setup for MP SN. - * Allocate per-node data, slurp prom klconfig information and - * convert it to hwgraph information. - */ -void -sn_mp_setup(void) -{ - cpuid_t cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) { - /* Skip holes in CPU space */ - if (cpu_enabled(cpu)) { - init_platform_pda(cpu); - } - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - io_module_init(); /* Use to be called module_init() .. */ - klhwg_add_all_modules(hwgraph_root); - klhwg_add_all_nodes(hwgraph_root); -} diff -Nru a/arch/ia64/sn/io/sn2/shub.c b/arch/ia64/sn/io/sn2/shub.c --- a/arch/ia64/sn/io/sn2/shub.c Mon Feb 24 05:34:25 2003 +++ b/arch/ia64/sn/io/sn2/shub.c Fri May 16 04:18:18 2003 @@ -97,6 +97,14 @@ } static inline void +shub_mmr_write_iospace(cnodeid_t cnode, shubreg_t reg, uint64_t val) +{ + int nasid = cnodeid_to_nasid(cnode); + + REMOTE_HUB_S(nasid, reg, val); +} + +static inline void shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val) { int nasid = cnodeid_to_nasid(cnode); @@ -118,6 +126,14 @@ return val; } +static inline uint64_t +shub_mmr_read_iospace(cnodeid_t cnode, shubreg_t reg) +{ + int nasid = cnodeid_to_nasid(cnode); + + return REMOTE_HUB_L(nasid, reg); +} + static inline uint32_t shub_mmr_read32(cnodeid_t cnode, shubreg_t reg) { @@ -182,11 +198,9 @@ { cnodeid_t cnode; uint64_t longarg; - devfs_handle_t d; + vertex_hdl_t d; int nasid; - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; cnode = (cnodeid_t)hwgraph_fastinfo_get(d); switch (cmd) { @@ -231,3 +245,252 @@ struct file_operations shub_mon_fops = { ioctl: shubstats_ioctl, }; + +/* + * "linkstatd" kernel thread to export SGI Numalink + * stats via /proc/sgi_sn/linkstats + */ +static struct s_linkstats { + uint64_t hs_ni_sn_errors[2]; + uint64_t hs_ni_cb_errors[2]; + uint64_t hs_ni_retry_errors[2]; + int hs_ii_up; + uint64_t hs_ii_sn_errors; + uint64_t hs_ii_cb_errors; + uint64_t hs_ii_retry_errors; +} *sn_linkstats; + +static spinlock_t sn_linkstats_lock; +static unsigned long sn_linkstats_starttime; +static unsigned long sn_linkstats_samples; +static unsigned long sn_linkstats_overflows; +static unsigned long sn_linkstats_update_msecs; + +void +sn_linkstats_reset(unsigned long msecs) +{ + int cnode; + uint64_t iio_wstat; + uint64_t llp_csr_reg; + + spin_lock(&sn_linkstats_lock); + memset(sn_linkstats, 0, numnodes * sizeof(struct s_linkstats)); + for (cnode=0; cnode < numnodes; cnode++) { + shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L); + shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L); + shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L); + + /* zero the II retry counter */ + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */ + shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat); + + /* Check if the II xtalk link is working */ + llp_csr_reg = shub_mmr_read_iospace(cnode, IIO_LLP_CSR); + if (llp_csr_reg & IIO_LLP_CSR_IS_UP) + sn_linkstats[cnode].hs_ii_up = 1; + } + + sn_linkstats_update_msecs = msecs; + sn_linkstats_samples = 0; + sn_linkstats_overflows = 0; + sn_linkstats_starttime = jiffies; + spin_unlock(&sn_linkstats_lock); +} + +int +linkstatd_thread(void *unused) +{ + int cnode; + int overflows; + uint64_t reg[2]; + uint64_t iio_wstat = 0L; + ii_illr_u_t illr; + struct s_linkstats *lsp; + struct task_struct *tsk = current; + + daemonize("linkstatd"); + set_user_nice(tsk, 19); + sigfillset(&tsk->blocked); + strcpy(tsk->comm, "linkstatd"); + + while(1) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(sn_linkstats_update_msecs * HZ / 1000); + + spin_lock(&sn_linkstats_lock); + + overflows = 0; + for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) { + reg[0] = shub_mmr_read(cnode, SH_NI0_LLP_ERR); + reg[1] = shub_mmr_read(cnode, SH_NI1_LLP_ERR); + if (lsp->hs_ii_up) { + illr = (ii_illr_u_t)shub_mmr_read_iospace(cnode, IIO_LLP_LOG); + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + } + + if (!overflows && ( + (reg[0] & SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK) == + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK || + (reg[0] & SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK) == + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK || + (reg[1] & SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK) == + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK || + (reg[1] & SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK) == + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK || + (lsp->hs_ii_up && illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) || + (lsp->hs_ii_up && illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX))) { + overflows = 1; + } + +#define LINKSTAT_UPDATE(reg, cnt, mask, shift) cnt += (reg & mask) >> shift + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_sn_errors[0], + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK, + SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_sn_errors[1], + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK, + SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_cb_errors[0], + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK, + SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_cb_errors[1], + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK, + SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[0], lsp->hs_ni_retry_errors[0], + SH_NI0_LLP_ERR_RETRY_COUNT_MASK, + SH_NI0_LLP_ERR_RETRY_COUNT_SHFT); + + LINKSTAT_UPDATE(reg[1], lsp->hs_ni_retry_errors[1], + SH_NI1_LLP_ERR_RETRY_COUNT_MASK, + SH_NI1_LLP_ERR_RETRY_COUNT_SHFT); + + if (lsp->hs_ii_up) { + /* II sn and cb errors */ + lsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt; + lsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt; + lsp->hs_ii_retry_errors += (iio_wstat & 0x0000000000ff0000) >> 16; + + shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L); + shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L); + shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L); + + /* zero the II retry counter */ + iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT); + iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */ + shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat); + } + } + + sn_linkstats_samples++; + if (overflows) + sn_linkstats_overflows++; + + spin_unlock(&sn_linkstats_lock); + } +} + +static char * +rate_per_minute(uint64_t val, uint64_t secs) +{ + static char buf[16]; + uint64_t a=0, b=0, c=0, d=0; + + if (secs) { + a = 60 * val / secs; + b = 60 * 10 * val / secs - (10 * a); + c = 60 * 100 * val / secs - (100 * a) - (10 * b); + d = 60 * 1000 * val / secs - (1000 * a) - (100 * b) - (10 * c); + } + sprintf(buf, "%4lu.%lu%lu%lu", a, b, c, d); + + return buf; +} + +int +sn_linkstats_get(char *page) +{ + int n = 0; + int cnode; + int nlport; + struct s_linkstats *lsp; + nodepda_t *npda; + uint64_t snsum = 0; + uint64_t cbsum = 0; + uint64_t retrysum = 0; + uint64_t snsum_ii = 0; + uint64_t cbsum_ii = 0; + uint64_t retrysum_ii = 0; + uint64_t secs; + + spin_lock(&sn_linkstats_lock); + secs = (jiffies - sn_linkstats_starttime) / HZ; + + n += sprintf(page, "# SGI Numalink stats v1 : %lu samples, %lu o/flows, update %lu msecs\n", + sn_linkstats_samples, sn_linkstats_overflows, sn_linkstats_update_msecs); + + n += sprintf(page+n, "%-37s %8s %8s %8s %8s\n", + "# Numalink", "sn errs", "cb errs", "cb/min", "retries"); + + for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) { + npda = NODEPDA(cnode); + + /* two NL links on each SHub */ + for (nlport=0; nlport < 2; nlport++) { + cbsum += lsp->hs_ni_cb_errors[nlport]; + snsum += lsp->hs_ni_sn_errors[nlport]; + retrysum += lsp->hs_ni_retry_errors[nlport]; + + /* avoid buffer overrun (should be using seq_read API) */ + if (numnodes > 64) + continue; + + n += sprintf(page + n, "/%s/link/%d %8lu %8lu %8s %8lu\n", + npda->hwg_node_name, nlport+1, lsp->hs_ni_sn_errors[nlport], + lsp->hs_ni_cb_errors[nlport], + rate_per_minute(lsp->hs_ni_cb_errors[nlport], secs), + lsp->hs_ni_retry_errors[nlport]); + } + + /* one II port on each SHub (may not be connected) */ + if (lsp->hs_ii_up) { + n += sprintf(page + n, "/%s/xtalk %8lu %8lu %8s %8lu\n", + npda->hwg_node_name, lsp->hs_ii_sn_errors, + lsp->hs_ii_cb_errors, rate_per_minute(lsp->hs_ii_cb_errors, secs), + lsp->hs_ii_retry_errors); + + snsum_ii += lsp->hs_ii_sn_errors; + cbsum_ii += lsp->hs_ii_cb_errors; + retrysum_ii += lsp->hs_ii_retry_errors; + } + } + + n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n", + "System wide NL totals", snsum, cbsum, + rate_per_minute(cbsum, secs), retrysum); + + n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n", + "System wide II totals", snsum_ii, cbsum_ii, + rate_per_minute(cbsum_ii, secs), retrysum_ii); + + spin_unlock(&sn_linkstats_lock); + + return n; +} + +static int __init +linkstatd_init(void) +{ + spin_lock_init(&sn_linkstats_lock); + sn_linkstats = kmalloc(numnodes * sizeof(struct s_linkstats), GFP_KERNEL); + sn_linkstats_reset(60000UL); /* default 60 second update interval */ + kernel_thread(linkstatd_thread, NULL, CLONE_FS | CLONE_FILES); + + return 0; +} + +__initcall(linkstatd_init); diff -Nru a/arch/ia64/sn/io/sn2/shub_intr.c b/arch/ia64/sn/io/sn2/shub_intr.c --- a/arch/ia64/sn/io/sn2/shub_intr.c Tue Dec 3 10:07:28 2002 +++ b/arch/ia64/sn/io/sn2/shub_intr.c Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #include @@ -30,7 +30,7 @@ /* ARGSUSED */ void -hub_intr_init(devfs_handle_t hubv) +hub_intr_init(vertex_hdl_t hubv) { } @@ -45,9 +45,9 @@ } static hub_intr_t -do_hub_intr_alloc(devfs_handle_t dev, +do_hub_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev, + vertex_hdl_t owner_dev, int uncond_nothread) { cpuid_t cpu = 0; @@ -71,7 +71,7 @@ cpuphys = cpu_physical_id(cpu); slice = cpu_physical_id_to_slice(cpuphys); nasid = cpu_physical_id_to_nasid(cpuphys); - cnode = cpu_to_node_map[cpu]; + cnode = cpuid_to_cnodeid(cpu); if (slice) { xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47); @@ -101,17 +101,17 @@ } hub_intr_t -hub_intr_alloc(devfs_handle_t dev, +hub_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); } hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, +hub_intr_alloc_nothd(vertex_hdl_t dev, device_desc_t dev_desc, - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); } @@ -187,19 +187,4 @@ rv = intr_disconnect_level(cpu, bit); ASSERT(rv == 0); intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl) -{ - cpuid_t cpuid = intr_hdl->i_cpuid; - - ASSERT(cpuid != CPU_NONE); - - return(cpuid_to_vertex(cpuid)); } diff -Nru a/arch/ia64/sn/io/sn2/shuberror.c b/arch/ia64/sn/io/sn2/shuberror.c --- a/arch/ia64/sn/io/sn2/shuberror.c Tue Dec 3 10:07:28 2002 +++ b/arch/ia64/sn/io/sn2/shuberror.c Mon May 19 05:42:56 2003 @@ -4,13 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include +#include #include #include #include @@ -27,28 +28,26 @@ #include #include #include +#include #include #include #include extern void hubni_eint_init(cnodeid_t cnode); extern void hubii_eint_init(cnodeid_t cnode); -extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); -int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo); -extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); +extern irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); +int hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); +int hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); +extern void bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); +void print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe); extern int maxcpus; +extern error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); #define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ -#ifdef BUS_INT_WAR -void sn_add_polled_interrupt(int irq, int interval); -void sn_delete_polled_interrupt(int irq); -extern int bus_int_war_ide_irq; -#endif - - void hub_error_clear(nasid_t nasid) { @@ -74,9 +73,7 @@ REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); } - REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, -1); - idsr = REMOTE_HUB_L(nasid, IIO_IIDSR); - REMOTE_HUB_S(nasid, IIO_IIDSR, (idsr & ~(IIO_IIDSR_SENT_MASK))); + REMOTE_HUB_S(nasid, IIO_IECLR, -1); } @@ -117,7 +114,6 @@ * Returns : None. */ - void hubii_eint_init(cnodeid_t cnode) { @@ -125,33 +121,41 @@ ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; - devfs_handle_t hub_v; + vertex_hdl_t hub_v; int bit_pos_to_irq(int bit); + ii_ilcsr_u_t ilcsr; - hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); + hub_v = (vertex_hdl_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { + /* + * HUB II link is not up. Disable LLP. Clear old errors. + * Enable interrupts to handle BTE errors. + */ + ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; + REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); + } + /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ - intr_cpu = intr_heuristic(hub_v,0,-1,0,hub_v, + intr_cpu = intr_heuristic(hub_v,0,SGI_II_ERROR,0,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } - rv = intr_connect_level(intr_cpu, bit, 0, NULL); - request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN_hub_error", (void *)hub_v); - irq_desc(bit + (intr_cpu << 8))->status |= SN2_IRQ_PER_HUB; -#ifdef BUS_INT_WAR - sn_add_polled_interrupt(bit + (intr_cpu << 8), (0.01 * HZ)); -#endif + rv = intr_connect_level(intr_cpu, SGI_II_ERROR, 0, NULL); + request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); + irq_desc(bit)->status |= SN2_IRQ_PER_HUB; ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; @@ -164,21 +168,32 @@ /*ARGSUSED*/ -void +irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { - devfs_handle_t hub_v; + vertex_hdl_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; + ii_ilcsr_u_t ilcsr; /* two levels of casting avoids compiler warning.!! */ - hub_v = (devfs_handle_t)(long)(arg); + hub_v = (vertex_hdl_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); +#if 0 + if (idsr & 0x1) { + /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ + printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); + printk("***** Please file PV with the above messages *****\n"); + /* panic("We have to panic to prevent further unknown states ..\n"); */ + } +#endif + /* * Identify the reason for error. */ @@ -218,10 +233,26 @@ * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ - printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", - hinfo->h_cnodeid, reason); + ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); + if (ilcsr.ii_ilcsr_fld_s.i_llp_en == 1) { /* Link is enabled */ + printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", + hinfo->h_nasid, hinfo->h_cnodeid, reason); + } } + + /* + * Before processing any interrupt related information, clear all + * error indication and reenable interrupts. This will prevent + * lost interrupts due to the interrupt handler scanning past a PRB/CRB + * which has not errorred yet and then the PRB/CRB goes into error. + * Note, PRB errors are cleared individually. + */ + REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xff0000); + idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; + REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); + + /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. @@ -232,14 +263,8 @@ */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); - /* - * If we reach here, it indicates crb/prb handlers successfully - * handled the error. So, re-enable II to send more interrupt - * and return. - */ - REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); - idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); + + return IRQ_HANDLED; } /* @@ -295,6 +320,105 @@ "Xtalk Error Packet" }; +void +print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, + ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, + ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe) +{ + printk("CRB %d regA\n\t" + "a_iow 0x%x\n\t" + "valid0x%x\n\t" + "Address0x%lx\n\t" + "a_tnum 0x%x\n\t" + "a_sidn 0x%x\n", + crb_num, + icrba.a_iow, + icrba.a_valid, + icrba.a_addr, + icrba.a_tnum, + icrba.a_sidn); + printk("CRB %d regB\n\t" + "b_imsgtype 0x%x\n\t" + "b_imsg 0x%x\n" + "\tb_use_old 0x%x\n\t" + "b_initiator 0x%x\n\t" + "b_exc 0x%x\n" + "\tb_ackcnt 0x%x\n\t" + "b_resp 0x%x\n\t" + "b_ack 0x%x\n" + "\tb_hold 0x%x\n\t" + "b_wb 0x%x\n\t" + "b_intvn 0x%x\n" + "\tb_stall_ib 0x%x\n\t" + "b_stall_int 0x%x\n" + "\tb_stall_bte_0 0x%x\n\t" + "b_stall_bte_1 0x%x\n" + "\tb_error 0x%x\n\t" + "b_lnetuce 0x%x\n\t" + "b_mark 0x%x\n\t" + "b_xerr 0x%x\n", + crb_num, + icrbb.b_imsgtype, + icrbb.b_imsg, + icrbb.b_use_old, + icrbb.b_initiator, + icrbb.b_exc, + icrbb.b_ackcnt, + icrbb.b_resp, + icrbb.b_ack, + icrbb.b_hold, + icrbb.b_wb, + icrbb.b_intvn, + icrbb.b_stall_ib, + icrbb.b_stall_int, + icrbb.b_stall_bte_0, + icrbb.b_stall_bte_1, + icrbb.b_error, + icrbb.b_lnetuce, + icrbb.b_mark, + icrbb.b_xerr); + printk("CRB %d regC\n\t" + "c_source 0x%x\n\t" + "c_xtsize 0x%x\n\t" + "c_cohtrans 0x%x\n\t" + "c_btenum 0x%x\n\t" + "c_gbr 0x%x\n\t" + "c_doresp 0x%x\n\t" + "c_barrop 0x%x\n\t" + "c_suppl 0x%x\n", + crb_num, + icrbc.c_source, + icrbc.c_xtsize, + icrbc.c_cohtrans, + icrbc.c_btenum, + icrbc.c_gbr, + icrbc.c_doresp, + icrbc.c_barrop, + icrbc.c_suppl); + printk("CRB %d regD\n\t" + "d_bteaddr 0x%lx\n\t" + "d_bteop 0x%x\n\t" + "d_pripsc 0x%x\n\t" + "d_pricnt 0x%x\n\t" + "d_sleep 0x%x\n\t", + crb_num, + icrbd.d_bteaddr, + icrbd.d_bteop, + icrbd.d_pripsc, + icrbd.d_pricnt, + icrbd.d_sleep); + printk("CRB %d regE\n\t" + "icrbe_timeout 0x%x\n\t" + "icrbe_context 0x%x\n\t" + "icrbe_toutvld 0x%x\n\t" + "icrbe_ctxtvld 0x%x\n\t", + crb_num, + icrbe.icrbe_timeout, + icrbe.icrbe_context, + icrbe.icrbe_toutvld, + icrbe.icrbe_ctxtvld); +} + /* * hubiio_crb_error_handler * @@ -317,7 +441,7 @@ */ int -hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { cnodeid_t cnode; nasid_t nasid; @@ -335,6 +459,9 @@ cnode = NASID_TO_COMPACT_NODEID(nasid); /* + * XXX - Add locking for any recovery actions + */ + /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ @@ -373,16 +500,11 @@ else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; - /* >>> bte_crb_error_handler needs to be - * broken into two parts. The first should - * cleanup the CRB. The second should wait - * until all bte related CRB's are complete - * and then do the error reset. - */ + hubiio_crb_free(hinfo, i); + bte_crb_error_handler(hub_v, bte_num, i, &ioerror, icrbd.d_bteop); - hubiio_crb_free(hinfo, i); num_errors++; continue; } @@ -430,6 +552,86 @@ IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); } + if (icrbb.b_error) { + /* + * CRB 'i' has some error. Identify the type of error, + * and try to handle it. + * + */ + switch(icrbb.b_ecode) { + case IIO_ICRB_ECODE_PERR: + case IIO_ICRB_ECODE_WERR: + case IIO_ICRB_ECODE_AERR: + case IIO_ICRB_ECODE_PWERR: + case IIO_ICRB_ECODE_TOUT: + case IIO_ICRB_ECODE_XTERR: + printk("Shub II CRB %d: error %s on hub cnodeid: %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* + * Any sort of write error is mostly due + * bad programming (Note it's not a timeout.) + * So, invoke hub_iio_error_handler with + * appropriate information. + */ + IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); + + /* Go through the error bit lookup phase */ + if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == + ERROR_RETURN_CODE_CANNOT_SET_STATE) + return(IOERROR_UNHANDLED); + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVERROR, + &ioerror); + if (rc == IOERROR_HANDLED) { + rc = hub_ioerror_handler( + hub_v, + DMA_WRITE_ERROR, + MODE_DEVREENABLE, + &ioerror); + }else { + printk("Unable to handle %s on hub %d", + hubiio_crb_errors[icrbb.b_ecode], + cnode); + /* panic; */ + } + /* Go to Next error */ + print_crb_fields(i, icrba, icrbb, icrbc, + icrbd, icrbe); + hubiio_crb_free(hinfo, i); + continue; + case IIO_ICRB_ECODE_PRERR: + case IIO_ICRB_ECODE_DERR: + printk("Shub II CRB %d: error %s on hub : %d", + i, hubiio_crb_errors[icrbb.b_ecode], cnode); + /* panic */ + default: + printk("Shub II CRB error (code : %d) on hub : %d", + icrbb.b_ecode, cnode); + /* panic */ + } + } + /* + * Error is not indicated via the errcode field + * Check other error indications in this register. + */ + if (icrbb.b_xerr) { + printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", + i, cnode); + /* panic */ + } + if (icrbb.b_lnetuce) { + printk("Shub II CRB %d: Uncorrectable data error detected on data " + " from NUMAlink to node %d", + i, cnode); + /* panic */ + } + print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); + + + + if (icrbb.b_error) { /* @@ -488,7 +690,7 @@ default: panic("Fatal error (code : %d) on hub : %d", - cnode); + icrbb.b_ecode, cnode); /*NOTREACHED*/ } @@ -568,7 +770,7 @@ * Cleanup involes freeing the PRB register */ static void -hubii_prb_handler(devfs_handle_t hub_v, hubinfo_t hinfo, int wnum) +hubii_prb_handler(vertex_hdl_t hub_v, hubinfo_t hinfo, int wnum) { nasid_t nasid; @@ -576,13 +778,13 @@ /* * Clear error bit by writing to IECLR register. */ - REMOTE_HUB_S(nasid, IIO_IO_ERR_CLR, (1 << wnum)); + REMOTE_HUB_S(nasid, IIO_IECLR, (1 << wnum)); /* * PIO Write to Widget 'i' got into an error. * Invoke hubiio_error_handler with this information. */ - printk( "Hub nasid %d got a PIO Write error from widget %d, cleaning up and continuing", - nasid, wnum); + printk( "Hub nasid %d got a PIO Write error from widget %d, " + "cleaning up and continuing", nasid, wnum); /* * XXX * It may be necessary to adjust IO PRB counter @@ -591,7 +793,7 @@ } int -hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo) +hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { int wnum; nasid_t nasid; diff -Nru a/arch/ia64/sn/io/sn2/shubio.c b/arch/ia64/sn/io/sn2/shubio.c --- a/arch/ia64/sn/io/sn2/shubio.c Mon Feb 24 05:34:49 2003 +++ b/arch/ia64/sn/io/sn2/shubio.c Fri May 16 04:18:18 2003 @@ -30,8 +30,8 @@ #include -error_state_t error_state_get(devfs_handle_t v); -error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state); +error_state_t error_state_get(vertex_hdl_t v); +error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); /* @@ -42,7 +42,7 @@ /*ARGSUSED*/ int hub_xp_error_handler( - devfs_handle_t hub_v, + vertex_hdl_t hub_v, nasid_t nasid, int error_code, ioerror_mode_t mode, @@ -50,7 +50,7 @@ { /*REFERENCED*/ hubreg_t iio_imem; - devfs_handle_t xswitch; + vertex_hdl_t xswitch; error_state_t e_state; cnodeid_t cnode; @@ -148,7 +148,7 @@ */ int hub_ioerror_handler( - devfs_handle_t hub_v, + vertex_hdl_t hub_v, int error_code, int mode, struct io_error_s *ioerror) @@ -158,6 +158,7 @@ int retval = 0; /*REFERENCED*/ iopaddr_t p; + caddr_t cp; IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror); @@ -193,14 +194,14 @@ * This is typically true for user mode bus errors while * accessing I/O space. */ - IOERROR_GETVALUE(p,ioerror,vaddr); - if (p){ + IOERROR_GETVALUE(cp,ioerror,vaddr); + if (cp){ /* * If neither in small window nor in large window range, * outright reject it. */ - IOERROR_GETVALUE(p,ioerror,vaddr); - if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){ + IOERROR_GETVALUE(cp,ioerror,vaddr); + if (NODE_SWIN_ADDR(nasid, (paddr_t)cp)){ iopaddr_t hubaddr; xwidgetnum_t widgetnum; iopaddr_t xtalkaddr; @@ -216,7 +217,7 @@ IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); - } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){ + } else if (NODE_BWIN_ADDR(nasid, (paddr_t)cp)){ /* * Address corresponds to large window space. * Convert it to xtalk address. @@ -428,11 +429,6 @@ return retval; } -#define L_BITSMINOR 18 -#define L_MAXMAJ 0x1ff -#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ) -#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0) - #define INFO_LBL_ERROR_STATE "error_state" #define v_error_state_get(v,s) \ @@ -454,12 +450,12 @@ * current state otherwise */ error_state_t -error_state_get(devfs_handle_t v) +error_state_get(vertex_hdl_t v) { error_state_t s; /* Check if we have a valid hwgraph vertex */ - if (!dev_is_vertex(v)) + if ( v == (vertex_hdl_t)0 ) return(ERROR_STATE_NONE); /* Get the labelled info hanging off the vertex which corresponds @@ -479,13 +475,13 @@ * ERROR_RETURN_CODE_SUCCESS otherwise */ error_return_code_t -error_state_set(devfs_handle_t v,error_state_t new_state) +error_state_set(vertex_hdl_t v,error_state_t new_state) { error_state_t old_state; boolean_t replace = B_TRUE; /* Check if we have a valid hwgraph vertex */ - if (!dev_is_vertex(v)) + if ( v == (vertex_hdl_t)0 ) return(ERROR_RETURN_CODE_GENERAL_FAILURE); diff -Nru a/arch/ia64/sn/io/sn2/xbow.c b/arch/ia64/sn/io/sn2/xbow.c --- a/arch/ia64/sn/io/sn2/xbow.c Mon Feb 24 05:39:15 2003 +++ b/arch/ia64/sn/io/sn2/xbow.c Fri May 23 03:37:38 2003 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -45,8 +45,6 @@ #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) #define DEL(ptr) (kfree(ptr)) -int xbow_devflag = D_MP; - /* * This file supports the Xbow chip. Main functions: initializtion, * error handling, and GBR. @@ -60,9 +58,9 @@ typedef struct xbow_soft_s *xbow_soft_t; struct xbow_soft_s { - devfs_handle_t conn; /* our connection point */ - devfs_handle_t vhdl; /* xbow's private vertex */ - devfs_handle_t busv; /* the xswitch vertex */ + vertex_hdl_t conn; /* our connection point */ + vertex_hdl_t vhdl; /* xbow's private vertex */ + vertex_hdl_t busv; /* the xswitch vertex */ xbow_t *base; /* PIO pointer to crossbow chip */ char *name; /* hwgraph name */ @@ -90,36 +88,27 @@ */ void xbow_mlreset(xbow_t *); -void xbow_init(void); -int xbow_attach(devfs_handle_t); - -int xbow_open(devfs_handle_t *, int, int, cred_t *); -int xbow_close(devfs_handle_t, int, int, cred_t *); - -int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int xbow_unmap(devfs_handle_t, vhandl_t *); -int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); +int xbow_attach(vertex_hdl_t); int xbow_widget_present(xbow_t *, int); static int xbow_link_alive(xbow_t *, int); -devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); +vertex_hdl_t xbow_widget_lookup(vertex_hdl_t, int); void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -void xbow_update_perf_counters(devfs_handle_t); -xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -int xbow_enable_perf_counter(devfs_handle_t, int, int, int); -xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); -void xbow_update_llp_status(devfs_handle_t); - -int xbow_disable_llp_monitor(devfs_handle_t); -int xbow_enable_llp_monitor(devfs_handle_t); -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, +void xbow_update_perf_counters(vertex_hdl_t); +xbow_perf_link_t *xbow_get_perf_counters(vertex_hdl_t); +int xbow_enable_perf_counter(vertex_hdl_t, int, int, int); +xbow_link_status_t *xbow_get_llp_status(vertex_hdl_t); +void xbow_update_llp_status(vertex_hdl_t); + +int xbow_disable_llp_monitor(vertex_hdl_t); +int xbow_enable_llp_monitor(vertex_hdl_t); +int xbow_prio_bw_alloc(vertex_hdl_t, xwidgetnum_t, xwidgetnum_t, unsigned long long, unsigned long long); static void xbow_setwidint(xtalk_intr_t); -void idbg_xbowregs(int64_t); xswitch_reset_link_f xbow_reset_link; @@ -128,32 +117,6 @@ xbow_reset_link, }; -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -static int xbow_mmap(struct file * file, struct vm_area_struct * vma); -struct file_operations xbow_fops = { - owner: THIS_MODULE, - llseek: NULL, - read: NULL, - write: NULL, - readdir: NULL, - poll: NULL, - ioctl: NULL, - mmap: xbow_mmap, - open: xbow_open, - flush: NULL, - release: NULL, - fsync: NULL, - fasync: NULL, - lock: NULL, - readv: NULL, - writev: NULL, - sendpage: NULL, - get_unmapped_area: NULL -}; static int xbow_mmap(struct file * file, struct vm_area_struct * vma) @@ -164,12 +127,21 @@ phys_addr = (unsigned long)file->private_data & ~0xc000000000000000; /* Mask out the Uncache bits */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED | VM_IO; - error = io_remap_page_range(vma, vma->vm_start, phys_addr, - vma->vm_end - vma->vm_start, + error = io_remap_page_range(vma, phys_addr, vma->vm_start, + vma->vm_end-vma->vm_start, vma->vm_page_prot); return(error); } +/* + * This is the file operation table for the pcibr driver. + * As each of the functions are implemented, put the + * appropriate function name below. + */ +struct file_operations xbow_fops = { + .owner = THIS_MODULE, + .mmap = xbow_mmap, +}; /* * xbow_mlreset: called at mlreset time if the @@ -188,39 +160,6 @@ { } -/* - * xbow_init: called with the rest of the device - * driver XXX_init routines. This platform *might* - * have a Crossbow chip, or even several, but it - * might have none. Register with the crosstalk - * generic provider so when we encounter the chip - * the right magic happens. - */ -void -xbow_init(void) -{ - -#if DEBUG && ATTACH_DEBUG - printk("xbow_init\n"); -#endif - - xwidget_driver_register(PXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - - xwidget_driver_register(XXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - xwidget_driver_register(XBOW_WIDGET_PART_NUM, - XBOW_WIDGET_MFGR_NUM, - "xbow_", - CDL_PRI_HI); /* attach before friends */ -} - #ifdef XBRIDGE_REGS_SIM /* xbow_set_simulated_regs: sets xbow regs as needed * for powering through the boot @@ -257,11 +196,11 @@ /*ARGSUSED */ int -xbow_attach(devfs_handle_t conn) +xbow_attach(vertex_hdl_t conn) { /*REFERENCED */ - devfs_handle_t vhdl; - devfs_handle_t busv; + vertex_hdl_t vhdl; + vertex_hdl_t busv; xbow_t *xbow; xbow_soft_t soft; int port; @@ -322,10 +261,10 @@ * file ops. */ vhdl = NULL; - vhdl = devfs_register(conn, EDGE_LBL_XBOW, - DEVFS_FL_AUTO_DEVNUM, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &xbow_fops, (void *)xbow); + vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, 0, + 0, 0, 0, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, + (struct file_operations *)&xbow_fops, (void *)xbow); if (!vhdl) { printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", (void *)conn); @@ -393,6 +332,14 @@ */ intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl); ASSERT(intr_hdl != NULL); + + { + int irq = ((hub_intr_t)intr_hdl)->i_bit; + int cpu = ((hub_intr_t)intr_hdl)->i_cpuid; + + intr_unreserve_level(cpu, irq); + ((hub_intr_t)intr_hdl)->i_bit = SGI_XBOW_ERROR; + } xtalk_intr_connect(intr_hdl, (intr_func_t) xbow_errintr_handler, @@ -400,19 +347,9 @@ (xtalk_intr_setfunc_t) xbow_setwidint, (void *) xbow); - request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, - ((hub_intr_t)intr_hdl)->i_bit), - (intr_func_t)xbow_errintr_handler, 0, "XBOW error", + request_irq(SGI_XBOW_ERROR, (void *)xbow_errintr_handler, SA_SHIRQ, "XBOW error", (intr_arg_t) soft); -#ifdef BUS_INT_WAR_NOT_YET - { - void sn_add_polled_interrupt(int, int); - sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid, - ((hub_intr_t)intr_hdl)->i_bit), 5000); - } -#endif - /* * Enable xbow error interrupts @@ -482,50 +419,14 @@ return 0; /* attach successful */ } -/*ARGSUSED */ -int -xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - xbow_soft_t soft = xbow_soft_get(vhdl); - int error; - - ASSERT(soft); - len = ctob(btoc(len)); - /* XXX- this ignores the offset!!! */ - error = v_mapphys(vt, (void *) soft->base, len); - return error; -} - -/*ARGSUSED */ -int -xbow_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - /* This contains special-case code for grio. There are plans to make * this general sometime in the future, but till then this should * be good enough. */ xwidgetnum_t -xbow_widget_num_get(devfs_handle_t dev) +xbow_widget_num_get(vertex_hdl_t dev) { - devfs_handle_t tdev; + vertex_hdl_t tdev; char devname[MAXDEVNAME]; xwidget_info_t xwidget_info; int i; @@ -555,58 +456,6 @@ return XWIDGET_NONE; } -int -xbow_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t vhdl; - int error = 0; - -#if defined (DEBUG) - int rc; - devfs_handle_t conn; - struct xwidget_info_s *xwidget_info; - xbow_soft_t xbow_soft; -#endif - *rvalp = 0; - - vhdl = dev_to_vhdl(dev); -#if defined (DEBUG) - xbow_soft = xbow_soft_get(vhdl); - conn = xbow_soft->conn; - - xwidget_info = xwidget_info_get(conn); - ASSERT_ALWAYS(xwidget_info != NULL); - - rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); - ASSERT_ALWAYS(rc != 0); -#endif - switch (cmd) { - - case XBOWIOC_LLP_ERROR_ENABLE: - if ((error = xbow_enable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - case XBOWIOC_LLP_ERROR_DISABLE: - - if ((error = xbow_disable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - default: - break; - - } - return error; -} - /* * xbow_widget_present: See if a device is present * on the specified port of this crossbow. @@ -648,12 +497,12 @@ * specified. * If not found, return 0. */ -devfs_handle_t -xbow_widget_lookup(devfs_handle_t vhdl, +vertex_hdl_t +xbow_widget_lookup(vertex_hdl_t vhdl, int widgetnum) { xswitch_info_t xswitch_info; - devfs_handle_t conn; + vertex_hdl_t conn; xswitch_info = xswitch_info_get(vhdl); conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); @@ -713,48 +562,14 @@ XEM_ADD_NVAR("ioe." #n, p); \ } -#ifdef LATER -static void -xem_add_ioe(ioerror_t *ioe) -{ - union tmp { - ushort stmp; - unsigned long long lltmp; - cpuid_t cputmp; - cnodeid_t cntmp; - iopaddr_t iotmp; - caddr_t catmp; - paddr_t patmp; - } tmp; - - XEM_ADD_IOEF(tmp.stmp, errortype); - XEM_ADD_IOEF(tmp.stmp, widgetnum); - XEM_ADD_IOEF(tmp.stmp, widgetdev); - XEM_ADD_IOEF(tmp.cputmp, srccpu); - XEM_ADD_IOEF(tmp.cntmp, srcnode); - XEM_ADD_IOEF(tmp.cntmp, errnode); - XEM_ADD_IOEF(tmp.iotmp, sysioaddr); - XEM_ADD_IOEF(tmp.iotmp, xtalkaddr); - XEM_ADD_IOEF(tmp.iotmp, busspace); - XEM_ADD_IOEF(tmp.iotmp, busaddr); - XEM_ADD_IOEF(tmp.catmp, vaddr); - XEM_ADD_IOEF(tmp.patmp, memaddr); - XEM_ADD_IOEF(tmp.catmp, epc); - XEM_ADD_IOEF(tmp.catmp, ef); - XEM_ADD_IOEF(tmp.stmp, tnum); -} - -#define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* LATER */ - -int xbow_xmit_retry_errors = 0; +int xbow_xmit_retry_errors; int xbow_xmit_retry_error(xbow_soft_t soft, int port) { xswitch_info_t info; - devfs_handle_t vhdl; + vertex_hdl_t vhdl; widget_cfg_t *wid; widgetreg_t id; int part; @@ -904,7 +719,7 @@ link_pend &= ~XB_STAT_XMT_RTRY_ERR; } if (link_pend) { - devfs_handle_t xwidget_vhdl; + vertex_hdl_t xwidget_vhdl; char *xwidget_name; /* Get the widget name corresponding to the current @@ -956,12 +771,6 @@ XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status); -#ifdef LATER - if (dump_ioe) { - XEM_ADD_IOE(); - dump_ioe = 0; - } -#endif #if !DEBUG } #endif @@ -1026,8 +835,8 @@ xbow_soft_t soft = (xbow_soft_t) einfo; int port; - devfs_handle_t conn; - devfs_handle_t busv; + vertex_hdl_t conn; + vertex_hdl_t busv; xbow_t *xbow = soft->base; xbowreg_t wid_stat; @@ -1279,7 +1088,7 @@ } void -xbow_update_perf_counters(devfs_handle_t vhdl) +xbow_update_perf_counters(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; @@ -1307,7 +1116,7 @@ } xbow_perf_link_t * -xbow_get_perf_counters(devfs_handle_t vhdl) +xbow_get_perf_counters(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; @@ -1316,7 +1125,7 @@ } int -xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) +xbow_enable_perf_counter(vertex_hdl_t vhdl, int link, int mode, int counter) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; @@ -1370,7 +1179,7 @@ } xbow_link_status_t * -xbow_get_llp_status(devfs_handle_t vhdl) +xbow_get_llp_status(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; @@ -1379,7 +1188,7 @@ } void -xbow_update_llp_status(devfs_handle_t vhdl) +xbow_update_llp_status(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; @@ -1387,7 +1196,7 @@ xbwX_stat_t lnk_sts; xbow_aux_link_status_t aux_sts; int link; - devfs_handle_t xwidget_vhdl; + vertex_hdl_t xwidget_vhdl; char *xwidget_name; xbow = (xbow_t *) xbow_soft->base; @@ -1421,7 +1230,7 @@ } int -xbow_disable_llp_monitor(devfs_handle_t vhdl) +xbow_disable_llp_monitor(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); int port; @@ -1436,7 +1245,7 @@ } int -xbow_enable_llp_monitor(devfs_handle_t vhdl) +xbow_enable_llp_monitor(vertex_hdl_t vhdl) { xbow_soft_t xbow_soft = xbow_soft_get(vhdl); @@ -1446,7 +1255,7 @@ int -xbow_reset_link(devfs_handle_t xconn_vhdl) +xbow_reset_link(vertex_hdl_t xconn_vhdl) { xwidget_info_t widget_info; xwidgetnum_t port; @@ -1469,7 +1278,7 @@ xbow = XBOW_K1PTR; #else { - devfs_handle_t xbow_vhdl; + vertex_hdl_t xbow_vhdl; xbow_soft_t xbow_soft; hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); @@ -1502,46 +1311,6 @@ return 0; } -/* - * Dump xbow registers. - * input parameter is either a pointer to - * the xbow chip or the vertex handle for - * an xbow vertex. - */ -void -idbg_xbowregs(int64_t regs) -{ - xbow_t *xbow; - int i; - xb_linkregs_t *link; - - xbow = (xbow_t *) regs; - -#ifdef LATER - qprintf("Printing xbow registers starting at 0x%x\n", xbow); - qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", - xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, - xbow->xb_wid_err_lower, xbow->xb_wid_control, - xbow->xb_wid_req_timeout); - qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", - xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, - xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, - xbow->xb_wid_arb_reload); -#endif - - for (i = 8; i <= 0xf; i++) { - link = &xbow->xb_link(i); -#ifdef LATER - qprintf("Link %d registers\n", i); - qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", - link->link_control, link->link_status, - link->link_arb_upper, link->link_arb_lower, - link->link_aux_status); -#endif - } -} - - #define XBOW_ARB_RELOAD_TICKS 25 /* granularity: 4 MB/s, max: 124 MB/s */ #define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) @@ -1601,7 +1370,7 @@ * If bandwidth allocation is successful, return success else return failure. */ int -xbow_prio_bw_alloc(devfs_handle_t vhdl, +xbow_prio_bw_alloc(vertex_hdl_t vhdl, xwidgetnum_t src_wid, xwidgetnum_t dest_wid, unsigned long long old_alloc_bw, diff -Nru a/arch/ia64/sn/io/sn2/xtalk.c b/arch/ia64/sn/io/sn2/xtalk.c --- a/arch/ia64/sn/io/sn2/xtalk.c Mon Feb 24 05:35:59 2003 +++ b/arch/ia64/sn/io/sn2/xtalk.c Fri May 16 04:18:17 2003 @@ -37,8 +37,6 @@ char widget_info_fingerprint[] = "widget_info"; -cdl_p xtalk_registry = NULL; - #define DEV_FUNC(dev,func) hub_##func #define CAST_PIOMAP(x) ((hub_piomap_t)(x)) #define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) @@ -47,71 +45,70 @@ /* ===================================================================== * Function Table of Contents */ -xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); +xtalk_piomap_t xtalk_piomap_alloc(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); void xtalk_piomap_free(xtalk_piomap_t); caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); +caddr_t xtalk_piotrans_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, unsigned); +caddr_t xtalk_pio_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); +xtalk_dmamap_t xtalk_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); void xtalk_dmamap_free(xtalk_dmamap_t); iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); +iopaddr_t xtalk_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); +alenlist_t xtalk_dmatrans_list(vertex_hdl_t, device_desc_t, alenlist_t, unsigned); void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); -xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); -xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); +void xtalk_dmaaddr_drain(vertex_hdl_t, iopaddr_t, size_t); +void xtalk_dmalist_drain(vertex_hdl_t, alenlist_t); +xtalk_intr_t xtalk_intr_alloc(vertex_hdl_t, device_desc_t, vertex_hdl_t); +xtalk_intr_t xtalk_intr_alloc_nothd(vertex_hdl_t, device_desc_t, vertex_hdl_t); void xtalk_intr_free(xtalk_intr_t); int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *); void xtalk_intr_disconnect(xtalk_intr_t); -devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int xtalk_error_devenable(devfs_handle_t, int, int); -void xtalk_provider_startup(devfs_handle_t); -void xtalk_provider_shutdown(devfs_handle_t); -devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); +vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t); +int xtalk_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); +int xtalk_error_devenable(vertex_hdl_t, int, int); +void xtalk_provider_startup(vertex_hdl_t); +void xtalk_provider_shutdown(vertex_hdl_t); +vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t); xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); void *xtalk_intr_sfarg_get(xtalk_intr_t); -devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); +vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t); xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); ulong xtalk_pio_mapsz_get(xtalk_piomap_t); caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); +vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t); xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(devfs_handle_t); -xwidget_info_t xwidget_info_get(devfs_handle_t); -void xwidget_info_set(devfs_handle_t, xwidget_info_t); -devfs_handle_t xwidget_info_dev_get(xwidget_info_t); +xwidget_info_t xwidget_info_chk(vertex_hdl_t); +xwidget_info_t xwidget_info_get(vertex_hdl_t); +void xwidget_info_set(vertex_hdl_t, xwidget_info_t); +vertex_hdl_t xwidget_info_dev_get(xwidget_info_t); xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -devfs_handle_t xwidget_info_master_get(xwidget_info_t); +vertex_hdl_t xwidget_info_master_get(xwidget_info_t); xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); char *xwidget_info_name_get(xwidget_info_t); -void xtalk_init(void); -void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); -void xtalk_provider_unregister(devfs_handle_t); -xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); +void xtalk_provider_register(vertex_hdl_t, xtalk_provider_t *); +void xtalk_provider_unregister(vertex_hdl_t); +xtalk_provider_t *xtalk_provider_fns_get(vertex_hdl_t); int xwidget_driver_register(xwidget_part_num_t, xwidget_mfg_num_t, char *, unsigned); void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, devfs_handle_t, - xwidgetnum_t, devfs_handle_t, - xwidgetnum_t, async_attach_t); -int xwidget_unregister(devfs_handle_t); -void xwidget_reset(devfs_handle_t); -char *xwidget_name_get(devfs_handle_t); +int xwidget_register(xwidget_hwid_t, vertex_hdl_t, + xwidgetnum_t, vertex_hdl_t, + xwidgetnum_t); +int xwidget_unregister(vertex_hdl_t); +void xwidget_reset(vertex_hdl_t); +char *xwidget_name_get(vertex_hdl_t); #if !defined(DEV_FUNC) /* * There is more than one possible provider @@ -126,7 +123,7 @@ #define CAST_INTR(x) ((xtalk_intr_t)(x)) static xtalk_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) +xwidget_to_provider_fns(vertex_hdl_t xconn) { xwidget_info_t widget_info; xtalk_provider_t *provider_fns; @@ -159,7 +156,7 @@ */ xtalk_piomap_t -xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +xtalk_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -198,7 +195,7 @@ caddr_t -xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -209,7 +206,7 @@ } caddr_t -xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_pio_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t addr, /* starting address (or offset in window) */ size_t byte_count, /* map this many bytes */ @@ -326,7 +323,7 @@ */ xtalk_dmamap_t -xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ +xtalk_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags) @@ -373,7 +370,7 @@ iopaddr_t -xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ @@ -385,7 +382,7 @@ alenlist_t -xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_list(vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags) @@ -402,14 +399,14 @@ } void -xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) +xtalk_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) { DEV_FUNC(dev, dmaaddr_drain) (dev, addr, size); } void -xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) +xtalk_dmalist_drain(vertex_hdl_t dev, alenlist_t list) { DEV_FUNC(dev, dmalist_drain) (dev, list); @@ -426,9 +423,9 @@ * Return resource handle in intr_hdl. */ xtalk_intr_t -xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ +xtalk_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) + vertex_hdl_t owner_dev) { /* owner of this interrupt */ return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) (dev, dev_desc, owner_dev); @@ -440,9 +437,9 @@ * Return resource handle in intr_hdl. */ xtalk_intr_t -xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ +xtalk_intr_alloc_nothd(vertex_hdl_t dev, /* which Crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt */ + vertex_hdl_t owner_dev) /* owner of this interrupt */ { return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) (dev, dev_desc, owner_dev); @@ -492,11 +489,10 @@ * Return a hwgraph vertex that represents the CPU currently * targeted by an interrupt. */ -devfs_handle_t +vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) { - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); + return (vertex_hdl_t)0; } @@ -526,7 +522,7 @@ */ int xtalk_error_handler( - devfs_handle_t xconn, + vertex_hdl_t xconn, int error_code, ioerror_mode_t mode, ioerror_t *ioerror) @@ -555,7 +551,7 @@ #if defined(SUPPORT_PRINTING_V_FORMAT) printk(KERN_WARNING "Xbow at %v encountered Fatal error", xconn); #else - printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", xconn); + printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", (void *)xconn); #endif ioerror_dump("xtalk", error_code, mode, ioerror); @@ -563,7 +559,7 @@ } int -xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code) +xtalk_error_devenable(vertex_hdl_t xconn_vhdl, int devnum, int error_code) { return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code); } @@ -577,7 +573,7 @@ * Startup a crosstalk provider */ void -xtalk_provider_startup(devfs_handle_t xtalk_provider) +xtalk_provider_startup(vertex_hdl_t xtalk_provider) { DEV_FUNC(xtalk_provider, provider_startup) (xtalk_provider); @@ -588,7 +584,7 @@ * Shutdown a crosstalk provider */ void -xtalk_provider_shutdown(devfs_handle_t xtalk_provider) +xtalk_provider_shutdown(vertex_hdl_t xtalk_provider) { DEV_FUNC(xtalk_provider, provider_shutdown) (xtalk_provider); @@ -598,22 +594,22 @@ * Enable a device on a xtalk widget */ void -xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) +xtalk_widgetdev_enable(vertex_hdl_t xconn_vhdl, int devnum) { - DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); + return; } /* * Shutdown a device on a xtalk widget */ void -xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) +xtalk_widgetdev_shutdown(vertex_hdl_t xconn_vhdl, int devnum) { - DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); + return; } int -xtalk_dma_enabled(devfs_handle_t xconn_vhdl) +xtalk_dma_enabled(vertex_hdl_t xconn_vhdl) { return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); } @@ -623,7 +619,7 @@ */ /****** Generic crosstalk interrupt interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) { return (xtalk_intr->xi_dev); @@ -654,7 +650,7 @@ } /****** Generic crosstalk pio interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) { return (xtalk_piomap->xp_dev); @@ -686,7 +682,7 @@ /****** Generic crosstalk dma interfaces ******/ -devfs_handle_t +vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) { return (xtalk_dmamap->xd_dev); @@ -707,7 +703,7 @@ * if not, return NULL. */ xwidget_info_t -xwidget_info_chk(devfs_handle_t xwidget) +xwidget_info_chk(vertex_hdl_t xwidget) { arbitrary_info_t ainfo = 0; @@ -717,28 +713,18 @@ xwidget_info_t -xwidget_info_get(devfs_handle_t xwidget) +xwidget_info_get(vertex_hdl_t xwidget) { xwidget_info_t widget_info; widget_info = (xwidget_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef LATER - if ((widget_info != NULL) && - (widget_info->w_fingerprint != widget_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v bad xwidget_info", xwidget); -#else - PRINT_PANIC("%x bad xwidget_info", xwidget); -#endif -#endif /* LATER */ - return (widget_info); } void -xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) +xwidget_info_set(vertex_hdl_t xwidget, xwidget_info_t widget_info) { if (widget_info != NULL) widget_info->w_fingerprint = widget_info_fingerprint; @@ -753,11 +739,11 @@ (arbitrary_info_t) widget_info); } -devfs_handle_t +vertex_hdl_t xwidget_info_dev_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_dev_get: null xwidget_info"); return (xwidget_info->w_vertex); } @@ -765,16 +751,16 @@ xwidget_info_id_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_id_get: null xwidget_info"); return (xwidget_info->w_id); } -devfs_handle_t +vertex_hdl_t xwidget_info_master_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_master_get: null xwidget_info"); return (xwidget_info->w_master); } @@ -782,7 +768,7 @@ xwidget_info_masterid_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_masterid_get: null xwidget_info"); return (xwidget_info->w_masterid); } @@ -790,7 +776,7 @@ xwidget_info_part_num_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_part_num_get: null xwidget_info"); return (xwidget_info->w_hwid.part_num); } @@ -798,7 +784,7 @@ xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget_info"); + panic("xwidget_info_mfg_num_get: null xwidget_info"); return (xwidget_info->w_hwid.mfg_num); } /* Extract the widget name from the widget information @@ -808,49 +794,16 @@ xwidget_info_name_get(xwidget_info_t xwidget_info) { if (xwidget_info == NULL) - panic("null xwidget info"); + panic("xwidget_info_name_get: null xwidget_info"); return(xwidget_info->w_name); } /****** Generic crosstalk initialization interfaces ******/ /* - * One-time initialization needed for systems that support crosstalk. - */ -void -xtalk_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("xtalk_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (xtalk_registry == NULL) { - cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); - if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(xtalk_registry != NULL); -} - -/* * Associate a set of xtalk_provider functions with a vertex. */ void -xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) +xtalk_provider_register(vertex_hdl_t provider, xtalk_provider_t *xtalk_fns) { hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); } @@ -859,7 +812,7 @@ * Disassociate a set of xtalk_provider functions with a vertex. */ void -xtalk_provider_unregister(devfs_handle_t provider) +xtalk_provider_unregister(vertex_hdl_t provider) { hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); } @@ -869,50 +822,19 @@ * provider. */ xtalk_provider_t * -xtalk_provider_fns_get(devfs_handle_t provider) +xtalk_provider_fns_get(vertex_hdl_t provider) { return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); } /* - * Announce a driver for a particular crosstalk part. - * Returns 0 on success or -1 on failure. Failure occurs if the - * specified hardware already has a driver. - */ -/*ARGSUSED4 */ -int -xwidget_driver_register(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine could call - * xwidget_driver_register before the - * system calls xtalk_init; so, we - * make the call here. - */ - if (xtalk_registry == NULL) - xtalk_init(); - - return cdl_add_driver(xtalk_registry, - part_num, mfg_num, - driver_prefix, flags, NULL); -} - -/* * Inform xtalk infrastructure that a driver is no longer available for * handling any widgets. */ void xwidget_driver_unregister(char *driver_prefix) { - /* before a driver calls unregister, - * it must have called registger; so we - * can assume we have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - cdl_del_driver(xtalk_registry, driver_prefix, NULL); + return; } /* @@ -923,9 +845,6 @@ xtalk_iterate(char *driver_prefix, xtalk_iter_f *func) { - ASSERT(xtalk_registry != NULL); - - cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); } /* @@ -939,11 +858,10 @@ */ int xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - devfs_handle_t widget, /* widget to initialize */ + vertex_hdl_t widget, /* widget to initialize */ xwidgetnum_t id, /* widget's target id (0..f) */ - devfs_handle_t master, /* widget's master vertex */ - xwidgetnum_t targetid, /* master's target id (9/a) */ - async_attach_t aa) + vertex_hdl_t master, /* widget's master vertex */ + xwidgetnum_t targetid) /* master's target id (9/a) */ { xwidget_info_t widget_info; char *s,devnm[MAXDEVNAME]; @@ -972,21 +890,11 @@ device_master_set(widget, master); - /* All the driver init routines (including - * xtalk_init) are called before we get into - * attaching devices, so we can assume we - * have a registry here. - */ - ASSERT(xtalk_registry != NULL); - /* * Add pointer to async attach info -- tear down will be done when * the particular descendant is done with the info. */ - if (aa) - async_attach_add_info(widget, aa); - - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, + return cdl_add_connpt(hwid->part_num, hwid->mfg_num, widget, 0); } @@ -995,7 +903,7 @@ * Unregister the xtalk device and detach all its hwgraph namespace. */ int -xwidget_unregister(devfs_handle_t widget) +xwidget_unregister(vertex_hdl_t widget) { xwidget_info_t widget_info; xwidget_hwid_t hwid; @@ -1011,9 +919,6 @@ hwid = &(widget_info->w_hwid); - cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); - /* Clean out the xwidget information */ (void)kfree(widget_info->w_name); BZERO((void *)widget_info, sizeof(widget_info)); @@ -1023,7 +928,7 @@ } void -xwidget_error_register(devfs_handle_t xwidget, +xwidget_error_register(vertex_hdl_t xwidget, error_handler_f *efunc, error_handler_arg_t einfo) { @@ -1039,37 +944,23 @@ * Issue a link reset to a widget. */ void -xwidget_reset(devfs_handle_t xwidget) +xwidget_reset(vertex_hdl_t xwidget) { xswitch_reset_link(xwidget); - } void -xwidget_gfx_reset(devfs_handle_t xwidget) +xwidget_gfx_reset(vertex_hdl_t xwidget) { - xwidget_info_t info; - - xswitch_reset_link(xwidget); - info = xwidget_info_get(xwidget); -#ifdef LATER - ASSERT_ALWAYS(info != NULL); -#endif - - /* - * Enable this for other architectures once we add widget_reset to the - * xtalk provider interface. - */ - DEV_FUNC(xtalk_provider, widget_reset) - (xwidget_info_master_get(info), xwidget_info_id_get(info)); + return; } #define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ /* Get the canonical hwgraph name of xtalk widget */ char * -xwidget_name_get(devfs_handle_t xwidget_vhdl) +xwidget_name_get(vertex_hdl_t xwidget_vhdl) { xwidget_info_t info; diff -Nru a/arch/ia64/sn/io/stubs.c b/arch/ia64/sn/io/stubs.c --- a/arch/ia64/sn/io/stubs.c Tue Dec 3 10:07:28 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,140 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/****** - ****** hack defines ...... - ******/ - -int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; -int default_intr_pri; -int force_fire_and_forget = 1; -int ignore_conveyor_override = 0; - -devfs_handle_t dummy_vrtx; /* Needed for cpuid_to_vertex() in hack.h */ - - -/* ARGSUSED */ -void hub_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) - {FIXME("hub_widgetdev_enable");} - -/* ARGSUSED */ -void hub_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) - {FIXME("hub_widgetdev_shutdown");} - -/* ARGSUSED */ -void hub_widget_reset(devfs_handle_t hubv, xwidgetnum_t widget) - {FIXME("hub_widget_reset");} - -boolean_t -is_sys_critical_vertex(devfs_handle_t x) -{ - FIXME("is_sys_critical_vertex : returns 0"); - return(0); -} - -void * -snia_kmem_zone_alloc(register struct zone *zone, int flags) -{ - FIXME("snia_kmem_zone_alloc : return null"); - return((void *)0); -} - -void -snia_kmem_zone_free(register struct zone *zone, void *ptr) -{ - FIXME("snia_kmem_zone_free : no-op"); -} - -struct zone * -snia_kmem_zone_init(register int size, char *zone_name) -{ - FIXME("snia_kmem_zone_free : returns NULL"); - return((struct zone *)0); -} - -int -compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) -{ - FIXME("compare_and_swap_ptr : NOT ATOMIC"); - if (*location == old_ptr) { - *location = new_ptr; - return(1); - } - else - return(0); -} - -/* For ml/SN/SN1/slots.c */ -/* ARGSUSED */ -slotid_t get_widget_slotnum(int xbow, int widget) - {FIXME("get_widget_slotnum"); return (unsigned char)NULL;} - -/* For router */ -int -router_init(cnodeid_t cnode,int writeid, void *npda_rip) - {FIXME("router_init"); return(0);} - -/* From io/ioerror_handling.c */ -error_return_code_t -sys_critical_graph_vertex_add(devfs_handle_t parent, devfs_handle_t child) - {FIXME("sys_critical_graph_vertex_add"); return(0);} - -/* From io/ioc3.c */ -devfs_handle_t -ioc3_console_vhdl_get(void) - {FIXME("ioc3_console_vhdl_get"); return( (devfs_handle_t)-1);} - -void -nic_vmc_check(devfs_handle_t vhdl, char *nicinfo) -{ - - FIXME("nic_vmc_check\n"); - -} - -char * -nic_vertex_info_get(devfs_handle_t v) -{ - FIXME("nic_vertex_info_get\n"); - return(NULL); -} - -int -vector_read_node(net_vec_t dest, nasid_t nasid, - int write_id, int address, - uint64_t *value) -{ - FIXME("vector_read_node\n"); - return(0); -} - -int -vector_write_node(net_vec_t dest, nasid_t nasid, - int write_id, int address, - uint64_t value) -{ - FIXME("vector_write_node\n"); - return(0); -} diff -Nru a/arch/ia64/sn/io/xbow.c b/arch/ia64/sn/io/xbow.c --- a/arch/ia64/sn/io/xbow.c Tue Feb 18 10:31:36 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1325 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG 1 */ -/* #define XBOW_DEBUG 1 */ - - -/* - * Files needed to get the device driver entry points - */ - -#include -#include -#include -#include - -#include -#include - - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -int xbow_devflag = D_MP; - -/* - * This file supports the Xbow chip. Main functions: initializtion, - * error handling, and GBR. - */ - -/* - * each vertex corresponding to an xbow chip - * has a "fastinfo" pointer pointing at one - * of these things. - */ -typedef struct xbow_soft_s *xbow_soft_t; - -struct xbow_soft_s { - devfs_handle_t conn; /* our connection point */ - devfs_handle_t vhdl; /* xbow's private vertex */ - devfs_handle_t busv; /* the xswitch vertex */ - xbow_t *base; /* PIO pointer to crossbow chip */ - char *name; /* hwgraph name */ - - xbow_perf_t xbow_perfcnt[XBOW_PERF_COUNTERS]; - xbow_perf_link_t xbow_perflink[MAX_XBOW_PORTS]; - xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - spinlock_t xbow_perf_lock; - int link_monitor; - widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ - - /* Bandwidth allocation state. Bandwidth values are for the - * destination port since contention happens there. - * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. - */ - spinlock_t xbow_bw_alloc_lock; /* bw allocation lock */ - unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ - unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ -}; - -#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) -#define xbow_soft_get(v) ((xbow_soft_t)hwgraph_fastinfo_get((v))) - -/* - * Function Table of Contents - */ - -void xbow_mlreset(xbow_t *); -void xbow_init(void); -int xbow_attach(devfs_handle_t); - -int xbow_open(devfs_handle_t *, int, int, cred_t *); -int xbow_close(devfs_handle_t, int, int, cred_t *); - -int xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint); -int xbow_unmap(devfs_handle_t, vhandl_t *); -int xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *); - -int xbow_widget_present(xbow_t *, int); -static int xbow_link_alive(xbow_t *, int); -devfs_handle_t xbow_widget_lookup(devfs_handle_t, int); - -#ifdef LATER -static void xbow_setwidint(xtalk_intr_t); -static void xbow_errintr_handler(intr_arg_t); -#endif -void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); - - - -void xbow_update_perf_counters(devfs_handle_t); -xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -int xbow_enable_perf_counter(devfs_handle_t, int, int, int); -xbow_link_status_t *xbow_get_llp_status(devfs_handle_t); -void xbow_update_llp_status(devfs_handle_t); - -int xbow_disable_llp_monitor(devfs_handle_t); -int xbow_enable_llp_monitor(devfs_handle_t); -int xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t, - unsigned long long, unsigned long long); - -xswitch_reset_link_f xbow_reset_link; - -void idbg_xbowregs(int64_t); - -xswitch_provider_t xbow_provider = -{ - xbow_reset_link, -}; - -/* - * xbow_mlreset: called at mlreset time if the - * platform specific code determines that there is - * a crossbow in a critical path that must be - * functional before the driver would normally get - * the device properly set up. - * - * what do we need to do, that the boot prom can - * not be counted on to have already done, that is - * generic across all platforms using crossbows? - */ -/*ARGSUSED */ -void -xbow_mlreset(xbow_t * xbow) -{ -} - -/* - * xbow_init: called with the rest of the device - * driver XXX_init routines. This platform *might* - * have a Crossbow chip, or even several, but it - * might have none. Register with the crosstalk - * generic provider so when we encounter the chip - * the right magic happens. - */ -void -xbow_init(void) -{ - -#if DEBUG && ATTACH_DEBUG - printf("xbow_init\n"); -#endif - - xwidget_driver_register(XXBOW_WIDGET_PART_NUM, - 0, /* XXBOW_WIDGET_MFGR_NUM, */ - "xbow_", - CDL_PRI_HI); /* attach before friends */ - - xwidget_driver_register(XBOW_WIDGET_PART_NUM, - XBOW_WIDGET_MFGR_NUM, - "xbow_", - CDL_PRI_HI); /* attach before friends */ -} - -#ifdef XBRIDGE_REGS_SIM -/* xbow_set_simulated_regs: sets xbow regs as needed - * for powering through the boot - */ -void -xbow_set_simulated_regs(xbow_t *xbow, int port) -{ - /* - * turn on link - */ - xbow->xb_link(port).link_status = (1<<31); - /* - * and give it a live widget too - */ - xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; - /* - * zero the link control reg - */ - xbow->xb_link(port).link_control = 0x0; -} -#endif /* XBRIDGE_REGS_SIM */ - -/* - * xbow_attach: the crosstalk provider has - * determined that there is a crossbow widget - * present, and has handed us the connection - * point for that vertex. - * - * We not only add our own vertex, but add - * some "xtalk switch" data to the switch - * vertex (at the connect point's parent) if - * it does not have any. - */ - -/*ARGSUSED */ -int -xbow_attach(devfs_handle_t conn) -{ - /*REFERENCED */ - devfs_handle_t vhdl; - devfs_handle_t busv; - xbow_t *xbow; - xbow_soft_t soft; - int port; - xswitch_info_t info; -#ifdef LATER - xtalk_intr_t intr_hdl; - device_desc_t dev_desc; -#endif - char devnm[MAXDEVNAME], *s; - xbowreg_t id; - int rev; - int i; - int xbow_num; - -#if DEBUG && ATTACH_DEBUG -#if defined(SUPPORT_PRINTING_V_FORMAT - printk("%v: xbow_attach\n", conn); -#else - printk("0x%x: xbow_attach\n", conn); -#endif -#endif - - /* - * Get a PIO pointer to the base of the crossbow - * chip. - */ -#ifdef XBRIDGE_REGS_SIM - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); - xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); - /* - * turn on ports e and f like in a real live ibrick - */ - xbow_set_simulated_regs(xbow, 0xe); - xbow_set_simulated_regs(xbow, 0xf); -#else - xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); -#endif /* XBRIDGE_REGS_SIM */ - - /* - * Locate the "switch" vertex: it is the parent - * of our connection point. - */ - busv = hwgraph_connectpt_get(conn); -#if DEBUG && ATTACH_DEBUG - printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); -#endif - - ASSERT(busv != GRAPH_VERTEX_NONE); - - /* - * Create our private vertex, and connect our - * driver information to it. This makes it possible - * for diagnostic drivers to open the crossbow - * vertex for access to registers. - */ - - /* - * We need to teach xbow drivers to provide the right set of - * file ops. - */ - vhdl = NULL; - vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, - 0, DEVFS_FL_AUTO_DEVNUM, - 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - /* &hcl_fops */ (void *)&vhdl, NULL); - if (!vhdl) { - printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", - (void *)conn); - } - - /* - * Allocate the soft state structure and attach - * it to the xbow's vertex - */ - NEW(soft); - soft->conn = conn; - soft->vhdl = vhdl; - soft->busv = busv; - soft->base = xbow; - /* does the universe really need another macro? */ - /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ - hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); - -#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" - - /* Add xbow number as a suffix to the hwgraph name of the xbow. - * This is helpful while looking at the error/warning messages. - */ - xbow_num = 0; - - /* - * get the name of this xbow vertex and keep the info. - * This is needed during errors and interrupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(vhdl, devnm, MAXDEVNAME); - soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, - GFP_KERNEL); - sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); - -#ifdef XBRIDGE_REGS_SIM - /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined - * as 0xd000, so I'm using that for the partnum bitfield. - */ - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); - id = 0x2d000049; -#else - id = xbow->xb_wid_id; -#endif /* XBRIDGE_REGS_SIM */ - rev = XWIDGET_PART_REV_NUM(id); - - /* - * Print the revision if DEBUG, or SHOW_REVS and kdebug, - * or the xbow is downrev. - * - * If xbow is downrev, make it a WARNING that the - * Crossbow is DOWNREV: these chips are not good - * to have around, and the operator should be told. - */ -#ifdef LATER -#if !DEBUG - if ( -#if SHOW_REVS - (kdebug) || -#endif /* SHOW_REVS */ - (rev < XBOW_REV_1_1)) -#endif /* !DEBUG */ - printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s", - (rev < XBOW_REV_1_1) ? "DOWNREV " : "", - (rev == XBOW_REV_1_0) ? "1.0" : - (rev == XBOW_REV_1_1) ? "1.1" : - (rev == XBOW_REV_1_2) ? "1.2" : - (rev == XBOW_REV_1_3) ? "1.3" : - (rev == XBOW_REV_2_0) ? "2.0" : - (rev == XXBOW_PART_REV_1_0) ? "Xbridge 1.0" : - (rev == XXBOW_PART_REV_2_0) ? "Xbridge 2.0" : - "unknown", - rev, soft->name, - (rev < XBOW_REV_1_1) ? "" : "\n"); -#endif /* LATER */ - mutex_spinlock_init(&soft->xbow_perf_lock); - soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a; - soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b; - - /* Initialization for GBR bw allocation */ - mutex_spinlock_init(&soft->xbow_bw_alloc_lock); - -#define XBOW_8_BIT_PORT_BW_MAX (400 * 1000 * 1000) /* 400 MB/s */ -#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ - - /* Set bandwidth hiwatermark and current values */ - for (i = 0; i < MAX_XBOW_PORTS; i++) { - soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ - soft->bw_cur_used[i] = 0; - } - - /* - * Enable xbow error interrupts - */ - xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); - - /* - * take a census of the widgets present, - * leaving notes at the switch vertex. - */ - info = xswitch_info_new(busv); - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; ++port) { - if (!xbow_link_alive(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is not alive\n", - busv, port); -#endif - continue; - } - if (!xbow_widget_present(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port); -#endif - continue; - } -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d has a widget\n", - busv, port); -#endif - - xswitch_info_link_is_ok(info, port); - /* - * Turn some error interrupts on - * and turn others off. The PROM has - * some things turned on we don't - * want to see (bandwidth allocation - * errors for instance); so if it - * is not listed here, it is not on. - */ - xbow->xb_link(port).link_control = - ( (xbow->xb_link(port).link_control - /* - * Turn off these bits; they are non-fatal, - * but we might want to save some statistics - * on the frequency of these errors. - * XXX FIXME XXX - */ - & ~XB_CTRL_RCV_CNT_OFLOW_IE - & ~XB_CTRL_XMT_CNT_OFLOW_IE - & ~XB_CTRL_BNDWDTH_ALLOC_IE - & ~XB_CTRL_RCV_IE) - /* - * These are the ones we want to turn on. - */ - | (XB_CTRL_ILLEGAL_DST_IE - | XB_CTRL_OALLOC_IBUF_IE - | XB_CTRL_XMT_MAX_RTRY_IE - | XB_CTRL_MAXREQ_TOUT_IE - | XB_CTRL_XMT_RTRY_IE - | XB_CTRL_SRC_TOUT_IE) ); - } - - xswitch_provider_register(busv, &xbow_provider); - - return 0; /* attach successful */ -} - -/*ARGSUSED */ -int -xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp) -{ - return 0; - -} - -/*ARGSUSED */ -int -xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp) -{ - return 0; -} - -/*ARGSUSED */ -int -xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot) -{ - devfs_handle_t vhdl = dev_to_vhdl(dev); - xbow_soft_t soft = xbow_soft_get(vhdl); - int error; - - ASSERT(soft); - len = ctob(btoc(len)); - /* XXX- this ignores the offset!!! */ - error = v_mapphys(vt, (void *) soft->base, len); - return error; -} - -/*ARGSUSED */ -int -xbow_unmap(devfs_handle_t dev, vhandl_t *vt) -{ - return 0; -} - -/* This contains special-case code for grio. There are plans to make - * this general sometime in the future, but till then this should - * be good enough. - */ -xwidgetnum_t -xbow_widget_num_get(devfs_handle_t dev) -{ - devfs_handle_t tdev; - char devname[MAXDEVNAME]; - xwidget_info_t xwidget_info; - int i; - - vertex_to_name(dev, devname, MAXDEVNAME); - - /* If this is a pci controller vertex, traverse up using - * the ".." links to get to the widget. - */ - if (strstr(devname, EDGE_LBL_PCI) && - strstr(devname, EDGE_LBL_CONTROLLER)) { - tdev = dev; - for (i=0; i< 2; i++) { - if (hwgraph_edge_get(tdev, - HWGRAPH_EDGELBL_DOTDOT, &tdev) != - GRAPH_SUCCESS) - return XWIDGET_NONE; - } - - if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) { - return (xwidget_info_id_get(xwidget_info)); - } else { - return XWIDGET_NONE; - } - } - - return XWIDGET_NONE; -} - -int -xbow_ioctl(devfs_handle_t dev, - int cmd, - void *arg, - int flag, - struct cred *cr, - int *rvalp) -{ - devfs_handle_t vhdl; - int error = 0; - -#if defined (DEBUG) - int rc; - devfs_handle_t conn; - struct xwidget_info_s *xwidget_info; - xbow_soft_t xbow_soft; -#endif - *rvalp = 0; - - vhdl = dev_to_vhdl(dev); -#if defined (DEBUG) - xbow_soft = xbow_soft_get(vhdl); - conn = xbow_soft->conn; - - xwidget_info = xwidget_info_get(conn); - ASSERT_ALWAYS(xwidget_info != NULL); - - rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid); - ASSERT_ALWAYS(rc != 0); -#endif - switch (cmd) { -#ifdef LATER - case XBOWIOC_PERF_ENABLE: - case XBOWIOC_PERF_DISABLE: - { - struct xbow_perfarg_t xbow_perf_en; - - if (!_CAP_CRABLE(cr, CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - if ((flag & FWRITE) == 0) { - error = EBADF; - break; - } - if (COPYIN(arg, &xbow_perf_en, sizeof(xbow_perf_en))) { - error = EFAULT; - break; - } - if (error = xbow_enable_perf_counter(vhdl, - xbow_perf_en.link, - (cmd == XBOWIOC_PERF_DISABLE) ? 0 : xbow_perf_en.mode, - xbow_perf_en.counter)) { - error = EINVAL; - break; - } - break; - } -#endif - -#ifdef LATER - case XBOWIOC_PERF_GET: - { - xbow_perf_link_t *xbow_perf_cnt; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_perf_cnt = xbow_get_perf_counters(vhdl); - ASSERT_ALWAYS(xbow_perf_cnt != NULL); - - if (COPYOUT((void *) xbow_perf_cnt, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_perf_link_t))) { - error = EFAULT; - break; - } - break; - } -#endif - - case XBOWIOC_LLP_ERROR_ENABLE: - if ((error = xbow_enable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - - case XBOWIOC_LLP_ERROR_DISABLE: - - if ((error = xbow_disable_llp_monitor(vhdl)) != 0) - error = EINVAL; - - break; - -#ifdef LATER - case XBOWIOC_LLP_ERROR_GET: - { - xbow_link_status_t *xbow_llp_status; - - if ((flag & FREAD) == 0) { - error = EBADF; - break; - } - xbow_llp_status = xbow_get_llp_status(vhdl); - ASSERT_ALWAYS(xbow_llp_status != NULL); - - if (COPYOUT((void *) xbow_llp_status, (void *) arg, - MAX_XBOW_PORTS * sizeof(xbow_link_status_t))) { - error = EFAULT; - break; - } - break; - } -#endif - -#ifdef LATER - case GIOCSETBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth allocation is bi-directional. Since bandwidth - * reservations have already been done at an earlier stage, - * we cannot fail here for lack of bandwidth. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - 0, info.reqbw); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - 0, info.reqbw); - - break; - } - - case GIOCRELEASEBW: - { - grio_ioctl_info_t info; - xwidgetnum_t src_widgetnum, dest_widgetnum; - - if (!cap_able(CAP_DEVICE_MGT)) { - error = EPERM; - break; - } - - if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) { - error = EFAULT; - break; - } -#ifdef GRIO_DEBUG - printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n", - info.prev_vhdl, info.next_vhdl, info.reqbw); -#endif /* GRIO_DEBUG */ - - src_widgetnum = xbow_widget_num_get(info.prev_vhdl); - dest_widgetnum = xbow_widget_num_get(info.next_vhdl); - - /* Bandwidth reservation is bi-directional. Hence, remove - * bandwidth reservations for both directions. - */ - xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum, - info.reqbw, (-1 * info.reqbw)); - xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum, - info.reqbw, (-1 * info.reqbw)); - - break; - } -#endif - - default: - break; - - } - return error; -} - -/* - * xbow_widget_present: See if a device is present - * on the specified port of this crossbow. - */ -int -xbow_widget_present(xbow_t * xbow, int port) -{ - if ( IS_RUNNING_ON_SIMULATOR() ) { - if ( (port == 14) || (port == 15) ) { - return 1; - } - else { - return 0; - } - } - else { - return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; - } -} - -static int -xbow_link_alive(xbow_t * xbow, int port) -{ - xbwX_stat_t xbow_linkstat; - - xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; - return (xbow_linkstat.link_alive); -} - -/* - * xbow_widget_lookup - * Lookup the edges connected to the xbow specified, and - * retrieve the handle corresponding to the widgetnum - * specified. - * If not found, return 0. - */ -devfs_handle_t -xbow_widget_lookup(devfs_handle_t vhdl, - int widgetnum) -{ - xswitch_info_t xswitch_info; - devfs_handle_t conn; - - xswitch_info = xswitch_info_get(vhdl); - conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); - return conn; -} - -/* - * xbow_setwidint: called when xtalk - * is establishing or migrating our - * interrupt service. - */ -#ifdef LATER -static void -xbow_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); - - xbow_intr_preset((void *) xbow, 0, targ, addr, vect); -} -#endif /* LATER */ - -/* - * xbow_intr_preset: called during mlreset time - * if the platform specific code needs to route - * an xbow interrupt before the xtalk infrastructure - * is available for use. - * - * Also called from xbow_setwidint, so we don't - * replicate the guts of the routine. - * - * XXX- probably should be renamed xbow_wid_intr_set or - * something to reduce confusion. - */ -/*ARGSUSED3 */ -void -xbow_intr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - xbow_t *xbow = (xbow_t *) which_widget; - - xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | - (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); -} - -#define XEM_ADD_STR(s) printk("%s", (s)) -#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%x\n", (n), (v)) -#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) -#define XEM_ADD_IOEF(n) if (IOERROR_FIELDVALID(ioe,n)) \ - XEM_ADD_NVAR("ioe." #n, \ - IOERROR_GETVALUE(ioe,n)) - -#ifdef LATER -static void -xem_add_ioe(ioerror_t *ioe) -{ - XEM_ADD_IOEF(errortype); - XEM_ADD_IOEF(widgetnum); - XEM_ADD_IOEF(widgetdev); - XEM_ADD_IOEF(srccpu); - XEM_ADD_IOEF(srcnode); - XEM_ADD_IOEF(errnode); - XEM_ADD_IOEF(sysioaddr); - XEM_ADD_IOEF(xtalkaddr); - XEM_ADD_IOEF(busspace); - XEM_ADD_IOEF(busaddr); - XEM_ADD_IOEF(vaddr); - XEM_ADD_IOEF(memaddr); - XEM_ADD_IOEF(epc); - XEM_ADD_IOEF(ef); -} - -#define XEM_ADD_IOE() (xem_add_ioe(ioe)) -#endif /* LATER */ - -int xbow_xmit_retry_errors = 0; - -int -xbow_xmit_retry_error(xbow_soft_t soft, - int port) -{ - xswitch_info_t info; - devfs_handle_t vhdl; - widget_cfg_t *wid; - widgetreg_t id; - int part; - int mfgr; - - wid = soft->wpio[port - BASE_XBOW_PORT]; - if (wid == NULL) { - /* If we can't track down a PIO - * pointer to our widget yet, - * leave our caller knowing that - * we are interested in this - * interrupt if it occurs in - * the future. - */ - info = xswitch_info_get(soft->busv); - if (!info) - return 1; - vhdl = xswitch_info_vhdl_get(info, port); - if (vhdl == GRAPH_VERTEX_NONE) - return 1; - wid = (widget_cfg_t *) xtalk_piotrans_addr - (vhdl, 0, 0, sizeof *wid, 0); - if (!wid) - return 1; - soft->wpio[port - BASE_XBOW_PORT] = wid; - } - id = wid->w_id; - part = XWIDGET_PART_NUM(id); - mfgr = XWIDGET_MFG_NUM(id); - - /* If this thing is not a Bridge, - * do not activate the WAR, and - * tell our caller we do not need - * to be called again. - */ - if ((part != BRIDGE_WIDGET_PART_NUM) || - (mfgr != BRIDGE_WIDGET_MFGR_NUM)) { - /* FIXME: add Xbridge to the WAR. - * Shouldn't hurt anything. Later need to - * check if we can remove this. - */ - if ((part != XBRIDGE_WIDGET_PART_NUM) || - (mfgr != XBRIDGE_WIDGET_MFGR_NUM)) - return 0; - } - - /* count how many times we - * have picked up after - * LLP Transmit problems. - */ - xbow_xmit_retry_errors++; - - /* rewrite the control register - * to fix things up. - */ - wid->w_control = wid->w_control; - wid->w_control; - - return 1; -} - -void -xbow_update_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; - xbow_perfcount_t perf_reg; - unsigned long s; - int link, i; - - for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { - if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) - continue; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - - link = perf_reg.xb_perf.link_select; - - (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += - ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); - xbow_perf->xp_current = perf_reg.xb_perf.count; - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - } - /* Do port /mode multiplexing here */ - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - -} - -xbow_perf_link_t * -xbow_get_perf_counters(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; - - return xbow_perf_link; -} - -int -xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; - xbow_linkctrl_t xbow_link_ctrl; - xbow_t *xbow = xbow_soft->base; - xbow_perfcount_t perf_reg; - unsigned long s; - int i; - - link -= BASE_XBOW_PORT; - if ((link < 0) || (link >= MAX_XBOW_PORTS)) - return -1; - - if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) - return -1; - - if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) - return -1; - - s = mutex_spinlock(&xbow_soft->xbow_perf_lock); - - if ((xbow_perf + counter)->xp_mode && mode) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - for (i = 0; i < XBOW_PERF_COUNTERS; i++) { - if (i == counter) - continue; - if (((xbow_perf + i)->xp_link == link) && - ((xbow_perf + i)->xp_mode)) { - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - return -1; - } - } - xbow_perf += counter; - - xbow_perf->xp_curlink = xbow_perf->xp_link = link; - xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; - - xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; - xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; - xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; - - perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; - perf_reg.xb_perf.link_select = link; - *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; - xbow_perf->xp_current = perf_reg.xb_perf.count; - -#ifdef LATER - (void) timeout(xbow_update_perf_counters, - (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT); -#endif - - mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); - - return 0; -} - -xbow_link_status_t * -xbow_get_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - - return xbow_llp_status; -} - -void -xbow_update_llp_status(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; - xbow_t *xbow; - xbwX_stat_t lnk_sts; - xbow_aux_link_status_t aux_sts; - int link; - devfs_handle_t xwidget_vhdl; - char *xwidget_name; - - xbow = (xbow_t *) xbow_soft->base; - for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { - /* Get the widget name corresponding the current link. - * Note : 0 <= link < MAX_XBOW_PORTS(8). - * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) - */ - xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); - xwidget_name = xwidget_name_get(xwidget_vhdl); - aux_sts.aux_linkstatus - = xbow->xb_link_raw[link].link_aux_status; - lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; - - if (lnk_sts.link_alive == 0) - continue; - - xbow_llp_status->rx_err_count += - aux_sts.xb_aux_linkstatus.rx_err_cnt; - - xbow_llp_status->tx_retry_count += - aux_sts.xb_aux_linkstatus.tx_retry_cnt; - - if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) { -#ifdef LATER - printk(KERN_WARNING "link %d[%s]: bad status 0x%x\n", - link, xwidget_name, lnk_sts.linkstatus); -#endif - } - } -#ifdef LATER - if (xbow_soft->link_monitor) - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif -} - -int -xbow_disable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - int port; - - for (port = 0; port < MAX_XBOW_PORTS; port++) { - xbow_soft->xbow_link_status[port].rx_err_count = 0; - xbow_soft->xbow_link_status[port].tx_retry_count = 0; - } - - xbow_soft->link_monitor = 0; - return 0; -} - -int -xbow_enable_llp_monitor(devfs_handle_t vhdl) -{ - xbow_soft_t xbow_soft = xbow_soft_get(vhdl); - -#ifdef LATER - (void) timeout(xbow_update_llp_status, - (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT); -#endif - xbow_soft->link_monitor = 1; - return 0; -} - - -int -xbow_reset_link(devfs_handle_t xconn_vhdl) -{ - xwidget_info_t widget_info; - xwidgetnum_t port; - xbow_t *xbow; - xbowreg_t ctrl; - xbwX_stat_t stat; - unsigned itick; - unsigned dtick; - static int ticks_per_ms = 0; - - if (!ticks_per_ms) { - itick = get_timestamp(); - us_delay(1000); - ticks_per_ms = get_timestamp() - itick; - } - widget_info = xwidget_info_get(xconn_vhdl); - port = xwidget_info_id_get(widget_info); - -#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ - xbow = XBOW_K1PTR; -#else - { - devfs_handle_t xbow_vhdl; - xbow_soft_t xbow_soft; - - hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); - xbow_soft = xbow_soft_get(xbow_vhdl); - xbow = xbow_soft->base; - } -#endif - - /* - * This requires three PIOs (reset the link, check for the - * reset, restore the control register for the link) plus - * 10us to wait for the reset. We allow up to 1ms for the - * widget to come out of reset before giving up and - * returning a failure. - */ - ctrl = xbow->xb_link(port).link_control; - xbow->xb_link(port).link_reset = 0; - itick = get_timestamp(); - while (1) { - stat.linkstatus = xbow->xb_link(port).link_status; - if (stat.link_alive) - break; - dtick = get_timestamp() - itick; - if (dtick > ticks_per_ms) { - return -1; /* never came out of reset */ - } - DELAY(2); /* don't beat on link_status */ - } - xbow->xb_link(port).link_control = ctrl; - return 0; -} - -/* - * Dump xbow registers. - * input parameter is either a pointer to - * the xbow chip or the vertex handle for - * an xbow vertex. - */ -void -idbg_xbowregs(int64_t regs) -{ - xbow_t *xbow; - int i; - xb_linkregs_t *link; - -#ifdef LATER - if (dev_is_vertex((devfs_handle_t) regs)) { - devfs_handle_t vhdl = (devfs_handle_t) regs; - xbow_soft_t soft = xbow_soft_get(vhdl); - - xbow = soft->base; - } else -#endif - { - xbow = (xbow_t *) regs; - } - -#ifdef LATER - qprintf("Printing xbow registers starting at 0x%x\n", xbow); - qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", - xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, - xbow->xb_wid_err_lower, xbow->xb_wid_control, - xbow->xb_wid_req_timeout); - qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", - xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, - xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, - xbow->xb_wid_arb_reload); -#endif - - for (i = 8; i <= 0xf; i++) { - link = &xbow->xb_link(i); -#ifdef LATER - qprintf("Link %d registers\n", i); - qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", - link->link_control, link->link_status, - link->link_arb_upper, link->link_arb_lower, - link->link_aux_status); -#endif - } -} - - -#define XBOW_ARB_RELOAD_TICKS 25 - /* granularity: 4 MB/s, max: 124 MB/s */ -#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS) - -#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY) - -#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY) - -#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ - ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr) - -#define XBOW_ARB_GBR_MAX 31 - -#define ABS(x) ((x > 0) ? (x) : (-1 * x)) - /* absolute value */ - -int -xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec) -{ - int gbr_granted; - int new_total_gbr; - int change_gbr; - bandwidth_t new_total_bw; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", - old_bytes_per_sec, bytes_per_sec); -#endif /* GRIO_DEBUG */ - - gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), - old_bytes_per_sec); - new_total_bw = old_bytes_per_sec + bytes_per_sec; - new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), - new_total_bw); - - change_gbr = new_total_gbr - gbr_granted; - -#ifdef GRIO_DEBUG - printf("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", - gbr_granted, new_total_gbr, change_gbr); -#endif /* GRIO_DEBUG */ - - return (change_gbr); -} - -/* Conversion from GBR to bytes */ -bandwidth_t -xbow_gbr_to_bytes(int gbr) -{ - return (XBOW_GBR_TO_BYTES(gbr)); -} - -/* Given the vhdl for the desired xbow, the src and dest. widget ids - * and the req_bw value, this xbow driver entry point accesses the - * xbow registers and allocates the desired bandwidth if available. - * - * If bandwidth allocation is successful, return success else return failure. - */ -int -xbow_prio_bw_alloc(devfs_handle_t vhdl, - xwidgetnum_t src_wid, - xwidgetnum_t dest_wid, - unsigned long long old_alloc_bw, - unsigned long long req_bw) -{ - xbow_soft_t soft = xbow_soft_get(vhdl); - volatile xbowreg_t *xreg; - xbowreg_t mask; - unsigned long s; - int error = 0; - bandwidth_t old_bw_BYTES, req_bw_BYTES; - xbowreg_t old_xreg; - int old_bw_GBR, req_bw_GBR, new_bw_GBR; - -#ifdef GRIO_DEBUG - printf("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", - (int) vhdl, (int) src_wid, (int) dest_wid, req_bw); -#endif - - ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); - ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); - - s = mutex_spinlock(&soft->xbow_bw_alloc_lock); - - /* Get pointer to the correct register */ - xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); - - /* Get mask for GBR count value */ - mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); - - req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); - req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) - : xbow_gbr_to_bytes(req_bw_GBR); - -#ifdef GRIO_DEBUG - printf("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", - req_bw, req_bw_BYTES, req_bw_GBR); -#endif /* GRIO_DEBUG */ - - old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; - old_xreg = *xreg; - old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid)); - -#ifdef GRIO_DEBUG - ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); - - printf("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); - - printf("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", - req_bw_BYTES, old_bw_BYTES, - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); - -#endif /* GRIO_DEBUG */ - - /* Accept the request only if we don't exceed the destination - * port HIWATER_MARK *AND* the max. link GBR arbitration count - */ - if (((old_bw_BYTES + req_bw_BYTES) <= - soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && - (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { - - new_bw_GBR = (old_bw_GBR + req_bw_GBR); - - /* Set this in the xbow link register */ - *xreg = (old_xreg & ~mask) | \ - (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); - - soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = - xbow_gbr_to_bytes(new_bw_GBR); - } else { - error = 1; - } - - mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); - - return (error); -} diff -Nru a/arch/ia64/sn/io/xswitch.c b/arch/ia64/sn/io/xswitch.c --- a/arch/ia64/sn/io/xswitch.c Wed Dec 4 07:10:30 2002 +++ b/arch/ia64/sn/io/xswitch.c Fri May 23 03:37:38 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -23,8 +23,6 @@ #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) #define DEL(ptr) (kfree(ptr)) -int xswitch_devflag = D_MP; - /* * This file provides generic support for Crosstalk * Switches, in a way that insulates crosstalk providers @@ -45,9 +43,9 @@ #define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func static xswitch_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) +xwidget_to_provider_fns(vertex_hdl_t xconn) { - devfs_handle_t busv; + vertex_hdl_t busv; xswitch_info_t xswitch_info; xswitch_provider_t provider_fns; @@ -75,27 +73,18 @@ struct xswitch_info_s { char *fingerprint; unsigned census; - devfs_handle_t vhdl[XSWITCH_CENSUS_PORTS]; - devfs_handle_t master_vhdl[XSWITCH_CENSUS_PORTS]; + vertex_hdl_t vhdl[XSWITCH_CENSUS_PORTS]; + vertex_hdl_t master_vhdl[XSWITCH_CENSUS_PORTS]; xswitch_provider_t *xswitch_fns; }; xswitch_info_t -xswitch_info_get(devfs_handle_t xwidget) +xswitch_info_get(vertex_hdl_t xwidget) { xswitch_info_t xswitch_info; xswitch_info = (xswitch_info_t) hwgraph_fastinfo_get(xwidget); -#ifdef LATER - if ((xswitch_info != NULL) && - (xswitch_info->fingerprint != xswitch_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget); -#else - PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget); -#endif -#endif /* LATER */ return (xswitch_info); } @@ -103,7 +92,7 @@ void xswitch_info_vhdl_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t xwidget) + vertex_hdl_t xwidget) { #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) @@ -115,15 +104,10 @@ xswitch_info->vhdl[port - XSWITCH_CENSUS_PORT_MIN] = xwidget; } -devfs_handle_t +vertex_hdl_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { -#ifdef LATER - if (xswitch_info == NULL) - PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info"); -#endif - #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) return GRAPH_VERTEX_NONE; @@ -142,7 +126,7 @@ void xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t master_vhdl) + vertex_hdl_t master_vhdl) { #if XSWITCH_CENSUS_PORT_MIN if (port < XSWITCH_CENSUS_PORT_MIN) @@ -154,7 +138,7 @@ xswitch_info->master_vhdl[port - XSWITCH_CENSUS_PORT_MIN] = master_vhdl; } -devfs_handle_t +vertex_hdl_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, xwidgetnum_t port) { @@ -169,14 +153,14 @@ } void -xswitch_info_set(devfs_handle_t xwidget, xswitch_info_t xswitch_info) +xswitch_info_set(vertex_hdl_t xwidget, xswitch_info_t xswitch_info) { xswitch_info->fingerprint = xswitch_info_fingerprint; hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) xswitch_info); } xswitch_info_t -xswitch_info_new(devfs_handle_t xwidget) +xswitch_info_new(vertex_hdl_t xwidget) { xswitch_info_t xswitch_info; @@ -202,7 +186,7 @@ } void -xswitch_provider_register(devfs_handle_t busv, +xswitch_provider_register(vertex_hdl_t busv, xswitch_provider_t * xswitch_fns) { xswitch_info_t xswitch_info = xswitch_info_get(busv); @@ -232,35 +216,8 @@ } int -xswitch_reset_link(devfs_handle_t xconn_vhdl) +xswitch_reset_link(vertex_hdl_t xconn_vhdl) { return DEV_FUNC(xconn_vhdl, reset_link) (xconn_vhdl); -} - -/* Given a vertex handle to the xswitch get its logical - * id. - */ -int -xswitch_id_get(devfs_handle_t xconn_vhdl) -{ - arbitrary_info_t xbow_num; - graph_error_t rv; - - rv = hwgraph_info_get_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID,&xbow_num); - ASSERT(rv == GRAPH_SUCCESS); - return(xbow_num); -} - -/* Given a vertex handle to the xswitch set its logical - * id. - */ -void -xswitch_id_set(devfs_handle_t xconn_vhdl,int xbow_num) -{ - graph_error_t rv; - - rv = hwgraph_info_add_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID, - (arbitrary_info_t)xbow_num); - ASSERT(rv == GRAPH_SUCCESS); } diff -Nru a/arch/ia64/sn/io/xtalk.c b/arch/ia64/sn/io/xtalk.c --- a/arch/ia64/sn/io/xtalk.c Tue Feb 18 10:31:36 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1024 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Implement crosstalk provider operations. The xtalk* layer provides a - * platform-independent interface for crosstalk devices. This layer - * switches among the possible implementations of a crosstalk adapter. - * - * On platforms with only one possible xtalk provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -#define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL)) -#define DEL(ptr) (kfree(ptr)) - -char widget_info_fingerprint[] = "widget_info"; - -cdl_p xtalk_registry = NULL; - -#define DEV_FUNC(dev,func) hub_##func -#define CAST_PIOMAP(x) ((hub_piomap_t)(x)) -#define CAST_DMAMAP(x) ((hub_dmamap_t)(x)) -#define CAST_INTR(x) ((hub_intr_t)(x)) - -/* ===================================================================== - * Function Table of Contents - */ -xtalk_piomap_t xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); -void xtalk_piomap_free(xtalk_piomap_t); -caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); -void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); -void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned); -void xtalk_dmamap_free(xtalk_dmamap_t); -iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); -alenlist_t xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned); -void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned); -alenlist_t xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned); -void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t); -void xtalk_dmalist_drain(devfs_handle_t, alenlist_t); -xtalk_intr_t xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t); -xtalk_intr_t xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t); -void xtalk_intr_free(xtalk_intr_t); -int xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *); -void xtalk_intr_disconnect(xtalk_intr_t); -devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -int xtalk_error_devenable(devfs_handle_t, int, int); -void xtalk_provider_startup(devfs_handle_t); -void xtalk_provider_shutdown(devfs_handle_t); -devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t); -xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); -xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); -iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); -void *xtalk_intr_sfarg_get(xtalk_intr_t); -devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t); -xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); -iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); -ulong xtalk_pio_mapsz_get(xtalk_piomap_t); -caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t); -xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(devfs_handle_t); -xwidget_info_t xwidget_info_get(devfs_handle_t); -void xwidget_info_set(devfs_handle_t, xwidget_info_t); -devfs_handle_t xwidget_info_dev_get(xwidget_info_t); -xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -devfs_handle_t xwidget_info_master_get(xwidget_info_t); -xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); -xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); -xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); -char *xwidget_info_name_get(xwidget_info_t); -void xtalk_init(void); -void xtalk_provider_register(devfs_handle_t, xtalk_provider_t *); -void xtalk_provider_unregister(devfs_handle_t); -xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t); -int xwidget_driver_register(xwidget_part_num_t, - xwidget_mfg_num_t, - char *, unsigned); -void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, devfs_handle_t, - xwidgetnum_t, devfs_handle_t, - xwidgetnum_t, async_attach_t); -int xwidget_unregister(devfs_handle_t); -void xwidget_reset(devfs_handle_t); -char *xwidget_name_get(devfs_handle_t); -#if !defined(DEV_FUNC) -/* - * There is more than one possible provider - * for this platform. We need to examine the - * master vertex of the current vertex for - * a provider function structure, and indirect - * through the appropriately named member. - */ -#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) -#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) -#define CAST_INTR(x) ((xtalk_intr_t)(x)) - -static xtalk_provider_t * -xwidget_to_provider_fns(devfs_handle_t xconn) -{ - xwidget_info_t widget_info; - xtalk_provider_t *provider_fns; - - widget_info = xwidget_info_get(xconn); - ASSERT(widget_info != NULL); - - provider_fns = xwidget_info_pops_get(widget_info); - ASSERT(provider_fns != NULL); - - return (provider_fns); -} -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) -#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * xtalk space on a specified widget - */ - -xtalk_piomap_t -xtalk_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); -} - - -void -xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_free) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk address */ - size_t byte_count) -{ /* map this many bytes */ - return PIOMAP_FUNC(xtalk_piomap, piomap_addr) - (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); -} - - -void -xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_done) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piotrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, xtalk_addr, byte_count, flags); -} - -caddr_t -xtalk_pio_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - xtalk_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - xtalk_piomap_t map = 0; - caddr_t res; - - if (mapp) - *mapp = 0; /* record "no map used" */ - - res = xtalk_piotrans_addr - (dev, dev_desc, addr, byte_count, flags); - if (res) - return res; /* xtalk_piotrans worked */ - - map = xtalk_piomap_alloc - (dev, dev_desc, addr, byte_count, byte_count, flags); - if (!map) - return res; /* xtalk_piomap_alloc failed */ - - res = xtalk_piomap_addr - (map, addr, byte_count); - if (!res) { - xtalk_piomap_free(map); - return res; /* xtalk_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* xtalk_piomap_addr succeeded */ -} - -/* ===================================================================== - * EARLY PIOTRANS SUPPORT - * - * There are places where drivers (mgras, for instance) - * need to get PIO translations before the infrastructure - * is extended to them (setting up textports, for - * instance). These drivers should call - * xtalk_early_piotrans_addr with their xtalk ID - * information, a sequence number (so we can use the second - * mgras for instance), and the usual piotrans parameters. - * - * Machine specific code should provide an implementation - * of early_piotrans_addr, and present a pointer to this - * function to xtalk_set_early_piotrans_addr so it can be - * used by clients without the clients having to know what - * platform or what xtalk provider is in use. - */ - -static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; - -xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; - -/* xtalk_set_early_piotrans_addr: - * specify the early_piotrans_addr implementation function. - */ -void -xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) -{ - impl_early_piotrans_addr = impl; -} - -/* xtalk_early_piotrans_addr: - * figure out a PIO address for the "nth" crosstalk widget that - * matches the specified part and mfgr number. Returns NULL if - * there is no such widget, or if the requested mapping can not - * be constructed. - * Limitations on which crosstalk slots (and busses) are - * checked, and definitions of the ordering of the search across - * the crosstalk slots, are defined by the platform. - */ -caddr_t -xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ - return impl_early_piotrans_addr - (part_num, mfg_num, which, xtalk_addr, byte_count, flags); -} - -/* null_xtalk_early_piotrans_addr: - * used as the early_piotrans_addr implementation until and - * unless a real implementation is provided. In DEBUG kernels, - * we want to know who is calling before the implementation is - * registered; in non-DEBUG kernels, return NULL representing - * lack of mapping support. - */ -/*ARGSUSED */ -static caddr_t -null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ -#if DEBUG - PRINT_PANIC("null_xtalk_early_piotrans_addr"); -#endif - return NULL; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from crosstalk space to system - * physical space. - */ - -xtalk_dmamap_t -xtalk_dmamap_alloc(devfs_handle_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - - -void -xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_free) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) - (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); -} - - -alenlist_t -xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this Address/Length List */ - unsigned flags) -{ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_list) - (CAST_DMAMAP(xtalk_dmamap), alenlist, flags); -} - - -void -xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_done) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmatrans_addr(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - - -alenlist_t -xtalk_dmatrans_list(devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_list) - (dev, dev_desc, palenlist, flags); -} - -void -xtalk_dmamap_drain(xtalk_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -void -xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list) -{ - DEV_FUNC(dev, dmalist_drain) - (dev, list); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) -{ /* owner of this interrupt */ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, owner_dev); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Unconditionally setup resources to be non-threaded. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc_nothd(devfs_handle_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev) /* owner of this interrupt */ -{ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) - (dev, dev_desc, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -xtalk_intr_free(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - - -/* - * Associate resources allocated with a previous xtalk_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), setfunc, setfunc_arg); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -xtalk_intr_disconnect(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -devfs_handle_t -xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -xtalk_provider_startup(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_startup) - (xtalk_provider); -} - - -/* - * Shutdown a crosstalk provider - */ -void -xtalk_provider_shutdown(devfs_handle_t xtalk_provider) -{ - DEV_FUNC(xtalk_provider, provider_shutdown) - (xtalk_provider); -} - -/* - * Enable a device on a xtalk widget - */ -void -xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum); -} - -/* - * Shutdown a device on a xtalk widget - */ -void -xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum) -{ - DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum); -} - -int -xtalk_dma_enabled(devfs_handle_t xconn_vhdl) -{ - return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl); -} -/* - * Generic crosstalk functions, for use with all crosstalk providers - * and all crosstalk devices. - */ - -/****** Generic crosstalk interrupt interfaces ******/ -devfs_handle_t -xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_dev); -} - -xwidgetnum_t -xtalk_intr_target_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_target); -} - -xtalk_intr_vector_t -xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_vector); -} - -iopaddr_t -xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) -{ - return (xtalk_intr->xi_addr); -} - -void * -xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_sfarg); -} - -/****** Generic crosstalk pio interfaces ******/ -devfs_handle_t -xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_dev); -} - -xwidgetnum_t -xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_target); -} - -iopaddr_t -xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_xtalk_addr); -} - -ulong -xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_mapsz); -} - -caddr_t -xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_kvaddr); -} - - -/****** Generic crosstalk dma interfaces ******/ -devfs_handle_t -xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_dev); -} - -xwidgetnum_t -xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_target); -} - - -/****** Generic crosstalk widget information interfaces ******/ - -/* xwidget_info_chk: - * check to see if this vertex is a widget; - * if so, return its widget_info (if any). - * if not, return NULL. - */ -xwidget_info_t -xwidget_info_chk(devfs_handle_t xwidget) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); - return (xwidget_info_t) ainfo; -} - - -xwidget_info_t -xwidget_info_get(devfs_handle_t xwidget) -{ - xwidget_info_t widget_info; - - widget_info = (xwidget_info_t) - hwgraph_fastinfo_get(xwidget); - -#ifdef LATER - if ((widget_info != NULL) && - (widget_info->w_fingerprint != widget_info_fingerprint)) -#ifdef SUPPORT_PRINTING_V_FORMAT - PRINT_PANIC("%v bad xwidget_info", xwidget); -#else - PRINT_PANIC("%x bad xwidget_info", xwidget); -#endif -#endif /* LATER */ - - return (widget_info); -} - -void -xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info) -{ - if (widget_info != NULL) - widget_info->w_fingerprint = widget_info_fingerprint; - - hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); - - /* Also, mark this vertex as an xwidget, - * and use the widget_info, so xwidget_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, - (arbitrary_info_t) widget_info); -} - -devfs_handle_t -xwidget_info_dev_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_vertex); -} - -xwidgetnum_t -xwidget_info_id_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_id); -} - - -devfs_handle_t -xwidget_info_master_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_master); -} - -xwidgetnum_t -xwidget_info_masterid_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_masterid); -} - -xwidget_part_num_t -xwidget_info_part_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.part_num); -} - -xwidget_mfg_num_t -xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget_info"); - return (xwidget_info->w_hwid.mfg_num); -} -/* Extract the widget name from the widget information - * for the xtalk widget. - */ -char * -xwidget_info_name_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("null xwidget info"); - return(xwidget_info->w_name); -} -/****** Generic crosstalk initialization interfaces ******/ - -/* - * One-time initialization needed for systems that support crosstalk. - */ -void -xtalk_init(void) -{ - cdl_p cp; - -#if DEBUG && ATTACH_DEBUG - printf("xtalk_init\n"); -#endif - /* Allocate the registry. - * We might already have one. - * If we don't, go get one. - * MPness: someone might have - * set one up for us while we - * were not looking; use an atomic - * compare-and-swap to commit to - * using the new registry if and - * only if nobody else did first. - * If someone did get there first, - * toss the one we allocated back - * into the pool. - */ - if (xtalk_registry == NULL) { - cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr"); - if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) { - cdl_del(cp); - } - } - ASSERT(xtalk_registry != NULL); -} - -/* - * Associate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); -} - -/* - * Disassociate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_unregister(devfs_handle_t provider) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); -} - -/* - * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk - * provider. - */ -xtalk_provider_t * -xtalk_provider_fns_get(devfs_handle_t provider) -{ - return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); -} - -/* - * Announce a driver for a particular crosstalk part. - * Returns 0 on success or -1 on failure. Failure occurs if the - * specified hardware already has a driver. - */ -/*ARGSUSED4 */ -int -xwidget_driver_register(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - char *driver_prefix, - unsigned flags) -{ - /* a driver's init routine could call - * xwidget_driver_register before the - * system calls xtalk_init; so, we - * make the call here. - */ - if (xtalk_registry == NULL) - xtalk_init(); - - return cdl_add_driver(xtalk_registry, - part_num, mfg_num, - driver_prefix, flags, NULL); -} - -/* - * Inform xtalk infrastructure that a driver is no longer available for - * handling any widgets. - */ -void -xwidget_driver_unregister(char *driver_prefix) -{ - /* before a driver calls unregister, - * it must have called registger; so we - * can assume we have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - cdl_del_driver(xtalk_registry, driver_prefix, NULL); -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -xtalk_iterate(char *driver_prefix, - xtalk_iter_f *func) -{ - ASSERT(xtalk_registry != NULL); - - cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func); -} - -/* - * xwidget_register: - * Register a xtalk device (xwidget) by doing the following. - * -allocate and initialize xwidget_info data - * -allocate a hwgraph vertex with name based on widget number (id) - * -look up the widget's initialization function and call it, - * or remember the vertex for later initialization. - * - */ -int -xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - devfs_handle_t widget, /* widget to initialize */ - xwidgetnum_t id, /* widget's target id (0..f) */ - devfs_handle_t master, /* widget's master vertex */ - xwidgetnum_t targetid, /* master's target id (9/a) */ - async_attach_t aa) -{ - xwidget_info_t widget_info; - char *s,devnm[MAXDEVNAME]; - - /* Allocate widget_info and associate it with widget vertex */ - NEW(widget_info); - - /* Initialize widget_info */ - widget_info->w_vertex = widget; - widget_info->w_id = id; - widget_info->w_master = master; - widget_info->w_masterid = targetid; - widget_info->w_hwid = *hwid; /* structure copy */ - widget_info->w_efunc = 0; - widget_info->w_einfo = 0; - /* - * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interrupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(widget,devnm,MAXDEVNAME); - widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(widget_info->w_name,s); - - xwidget_info_set(widget, widget_info); - - device_master_set(widget, master); - - /* All the driver init routines (including - * xtalk_init) are called before we get into - * attaching devices, so we can assume we - * have a registry here. - */ - ASSERT(xtalk_registry != NULL); - - /* - * Add pointer to async attach info -- tear down will be done when - * the particular descendant is done with the info. - */ - if (aa) - async_attach_add_info(widget, aa); - - return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); -} - -/* - * xwidget_unregister : - * Unregister the xtalk device and detach all its hwgraph namespace. - */ -int -xwidget_unregister(devfs_handle_t widget) -{ - xwidget_info_t widget_info; - xwidget_hwid_t hwid; - - /* Make sure that we have valid widget information initialized */ - if (!(widget_info = xwidget_info_get(widget))) - return(1); - - /* Remove the inventory information associated - * with the widget. - */ - hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1); - - hwid = &(widget_info->w_hwid); - - cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num, - widget, 0); - - /* Clean out the xwidget information */ - (void)kfree(widget_info->w_name); - BZERO((void *)widget_info, sizeof(widget_info)); - DEL(widget_info); - - return(0); -} - -/* - * Issue a link reset to a widget. - */ -void -xwidget_reset(devfs_handle_t xwidget) -{ - xswitch_reset_link(xwidget); - -} - - -void -xwidget_gfx_reset(devfs_handle_t xwidget) -{ - xwidget_info_t info; - - xswitch_reset_link(xwidget); - info = xwidget_info_get(xwidget); -#ifdef LATER - ASSERT_ALWAYS(info != NULL); -#endif - - /* - * Enable this for other architectures once we add widget_reset to the - * xtalk provider interface. - */ - DEV_FUNC(xtalk_provider, widget_reset) - (xwidget_info_master_get(info), xwidget_info_id_get(info)); -} - -#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ - -/* Get the canonical hwgraph name of xtalk widget */ -char * -xwidget_name_get(devfs_handle_t xwidget_vhdl) -{ - xwidget_info_t info; - - /* If we have a bogus widget handle then return - * a default anonymous widget name. - */ - if (xwidget_vhdl == GRAPH_VERTEX_NONE) - return(ANON_XWIDGET_NAME); - /* Read the widget name stored in the widget info - * for the widget setup during widget initialization. - */ - info = xwidget_info_get(xwidget_vhdl); - ASSERT(info != NULL); - return(xwidget_info_name_get(info)); -} - -/* - * xtalk_device_shutdown - * Disable the specified xtalk widget and clean out all the software - * state associated with it. - */ -int -xtalk_device_shutdown(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) -{ - devfs_handle_t widget_vhdl; - char edge_name[8]; - - sprintf(edge_name, "%d", widget); - if (hwgraph_traverse(xbus_vhdl, edge_name, &widget_vhdl) - != GRAPH_SUCCESS) - return(1); - - xwidget_unregister(widget_vhdl); - - return(0); -} diff -Nru a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile --- a/arch/ia64/sn/kernel/Makefile Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/kernel/Makefile Mon May 19 05:42:08 2003 @@ -9,11 +9,7 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y := probe.o setup.o sn_asm.o sv.o bte.o iomv.o \ - irq.o mca.o +obj-y := probe.o setup.o sv.o bte.o irq.o mca.o sn2/ -obj-$(CONFIG_IA64_SGI_SN2) += sn2/ -obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o obj-$(CONFIG_IA64_GENERIC) += machvec.o obj-$(CONFIG_MODULES) += sn_ksyms.o -obj-$(CONFIG_IA64_SGI_SN_BRT) += bte_regr_test.o diff -Nru a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c --- a/arch/ia64/sn/kernel/bte.c Tue Dec 3 10:07:29 2002 +++ b/arch/ia64/sn/kernel/bte.c Fri May 16 04:18:18 2003 @@ -1,7 +1,7 @@ /* * * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -38,124 +38,160 @@ #include #include #include -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif #include #include #include #include -#include +#include -int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; +#ifndef L1_CACHE_MASK +#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) +#endif /* - * bte_init_node(nodepda, cnode) + * The base address of for each set of bte registers. + */ +static int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 }; + + +/************************************************************************ + * Block Transfer Engine copy related functions. * - * Initialize the nodepda structure with BTE base addresses and - * spinlocks. + ***********************************************************************/ + + +/* + * bte_copy(src, dest, len, mode, notification) + * + * Use the block transfer engine to move kernel memory from src to dest + * using the assigned mode. + * + * Paramaters: + * src - physical address of the transfer source. + * dest - physical address of the transfer destination. + * len - number of bytes to transfer from source to dest. + * mode - hardware defined. See reference information + * for IBCT0/1 in the SHUB Programmers Reference + * notification - kernel virtual address of the notification cache + * line. If NULL, the default is used and + * the bte_copy is synchronous. * - * NOTE: The kernel parameter btetest will cause the initialization - * code to reserve blocks of physically contiguous memory to be - * used by the bte test module. + * NOTE: This function requires src, dest, and len to + * be cacheline aligned. */ -void -bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +bte_result_t +bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) { - int i; + int bte_to_use; + u64 transfer_size; + struct bteinfo_s *bte; + bte_result_t bte_status; + unsigned long irq_flags; - /* - * Indicate that all the block transfer engines on this node - * are available. - */ - for (i = 0; i < BTES_PER_NODE; i++) { -#ifdef CONFIG_IA64_SGI_SN2 - /* >>> Don't know why the 0x1800000L is here. Robin */ - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + BTE_PRINTK(("bte_copy(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%p)\n", + src, dest, len, mode, notification)); -#elif CONFIG_IA64_SGI_SN1 - mynodepda->bte_if[i].bte_base_addr = - (char *)LOCAL_HUB_ADDR(bte_offsets[i]); -#else -#error BTE Not defined for this hardware platform. -#endif + if (len == 0) { + return BTE_SUCCESS; + } - /* - * Initialize the notification and spinlock - * so the first transfer can occur. - */ - mynodepda->bte_if[i].most_rcnt_na = - &(mynodepda->bte_if[i].notify); - mynodepda->bte_if[i].notify = 0L; -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_lock_init(&mynodepda->bte_if[i].spinlock); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ + ASSERT(!((len & L1_CACHE_MASK) || + (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); + ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); + + do { + local_irq_save(irq_flags); + + bte_to_use = 0; + /* Attempt to lock one of the BTE interfaces. */ + while ((bte_to_use < BTES_PER_NODE) && + BTE_LOCK_IF_AVAIL(bte_to_use)) { + bte_to_use++; + } - mynodepda->bte_if[i].bte_test_buf = - alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + if (bte_to_use < BTES_PER_NODE) { + break; + } + + local_irq_restore(irq_flags); + + if (!(mode & BTE_WACQUIRE)) { + return BTEFAIL_NOTAVAIL; + } + + /* Wait until a bte is available. */ + udelay(10); + } while (1); + + bte = pda->cpu_bte_if[bte_to_use]; + BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); + + + if (notification == NULL) { + /* User does not want to be notified. */ + bte->most_rcnt_na = &bte->notify; + } else { + bte->most_rcnt_na = notification; } -} + /* Calculate the number of cache lines to transfer. */ + transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); + /* Initialize the notification to a known value. */ + *bte->most_rcnt_na = -1L; -/* - * bte_reset_nasid(nasid_t) - * - * Does a soft reset of the BTEs on the specified nasid. - * This is followed by a one-line transfer from each of the - * virtual interfaces. - */ -void -bte_reset_nasid(nasid_t n) -{ - ii_ibcr_u_t ibcr; + /* Set the status reg busy bit and transfer length */ + BTE_PRINTKV(("IBLS - HUB_S(0x%p, 0x%lx)\n", + BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); + HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); + + /* Set the source and destination registers */ + BTE_PRINTKV(("IBSA - HUB_S(0x%p, 0x%lx)\n", BTEREG_SRC_ADDR, + (TO_PHYS(src)))); + HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); + BTE_PRINTKV(("IBDA - HUB_S(0x%p, 0x%lx)\n", BTEREG_DEST_ADDR, + (TO_PHYS(dest)))); + HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); + + /* Set the notification register */ + BTE_PRINTKV(("IBNA - HUB_S(0x%p, 0x%lx)\n", BTEREG_NOTIF_ADDR, + (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na))))); + HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(ia64_tpa((unsigned long)bte->most_rcnt_na)))); - ibcr.ii_ibcr_regval = REMOTE_HUB_L(n, IIO_IBCR); - ibcr.ii_ibcr_fld_s.i_soft_reset = 1; - REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval); - - /* One line transfer on virtual interface 0 */ - REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_0, - TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS0)) { - /* >>> Need some way out in case of hang... */ + + /* Initiate the transfer */ + BTE_PRINTK(("IBCT - HUB_S(0x%p, 0x%lx)\n", BTEREG_CTRL_ADDR, + BTE_VALID_MODE(mode))); + HUB_S(BTEREG_CTRL_ADDR, BTE_VALID_MODE(mode)); + + spin_unlock_irqrestore(&bte->spinlock, irq_flags); + + + if (notification != NULL) { + return BTE_SUCCESS; } - /* One line transfer on virtual interface 1 */ - REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1); - REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup))); - REMOTE_HUB_S(n, IIO_IBDA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBNA_1, - TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES]))); - REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY); - while (REMOTE_HUB_L(n, IIO_IBLS1)) { - /* >>> Need some way out in case of hang... */ + while (*bte->most_rcnt_na == -1UL) { } -} -/* - * bte_init_cpu() - * - * Initialize the cpupda structure with pointers to the - * nodepda bte blocks. - * - */ -void -bte_init_cpu(void) -{ - pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); - pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, most_rcnt_na = 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + if (*bte->most_rcnt_na & IBLS_ERROR) { + bte_status = *bte->most_rcnt_na & ~IBLS_ERROR; + *bte->most_rcnt_na = 0L; + } else { + bte_status = BTE_SUCCESS; + } + BTE_PRINTK(("Returning status is 0x%lx and most_rcnt_na is 0x%lx\n", + HUB_L(BTEREG_LNSTAT_ADDR), *bte->most_rcnt_na)); + + return bte_status; } @@ -192,15 +228,11 @@ char *bteBlock; if (len == 0) { - return (BTE_SUCCESS); + return BTE_SUCCESS; } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING -#error bte_unaligned_copy() assumes single BTE selection in bte_copy(). -#else /* temporary buffer used during unaligned transfers */ - bteBlock = pda->cpu_bte_if[0]->bte_test_buf; -#endif + bteBlock = pda->cpu_bte_if[0]->scratch_buf; headBcopySrcOffset = src & L1_CACHE_MASK; destFirstCacheOffset = dest & L1_CACHE_MASK; @@ -265,15 +297,15 @@ headBteLen += footBteLen; } else if (footBcopyLen > 0) { rv = bte_copy(footBteSource, - __pa(bteBlock), + ia64_tpa((unsigned long)bteBlock), footBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } memcpy(__va(footBcopyDest), - (char *)bteBlock, footBcopyLen); + (char *) bteBlock, footBcopyLen); } } else { footBcopyLen = 0; @@ -288,7 +320,7 @@ (len - headBcopyLen - footBcopyLen), mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } } @@ -315,14 +347,93 @@ if (headBcopyLen > 0) { rv = bte_copy(headBteSource, - __pa(bteBlock), headBteLen, mode, NULL); + ia64_tpa((unsigned long)bteBlock), headBteLen, mode, NULL); if (rv != BTE_SUCCESS) { - return (rv); + return rv; } - memcpy(__va(headBcopyDest), ((char *)bteBlock + + memcpy(__va(headBcopyDest), ((char *) bteBlock + headBcopySrcOffset), headBcopyLen); } - return (BTE_SUCCESS); + return BTE_SUCCESS; +} + + +/************************************************************************ + * Block Transfer Engine initialization functions. + * + ***********************************************************************/ + + +/* + * bte_init_node(nodepda, cnode) + * + * Initialize the nodepda structure with BTE base addresses and + * spinlocks. + */ +void +bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode) +{ + int i; + + + /* + * Indicate that all the block transfer engines on this node + * are available. + */ + + /* + * Allocate one bte_recover_t structure per node. It holds + * the recovery lock for node. All the bte interface structures + * will point at this one bte_recover structure to get the lock. + */ + spin_lock_init(&mynodepda->bte_recovery_lock); + init_timer(&mynodepda->bte_recovery_timer); + mynodepda->bte_recovery_timer.function = bte_error_handler; + mynodepda->bte_recovery_timer.data = (unsigned long) mynodepda; + + for (i = 0; i < BTES_PER_NODE; i++) { + /* >>> Don't know why the 0x1800000L is here. Robin */ + mynodepda->bte_if[i].bte_base_addr = + (char *) LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L); + + /* + * Initialize the notification and spinlock + * so the first transfer can occur. + */ + mynodepda->bte_if[i].most_rcnt_na = + &(mynodepda->bte_if[i].notify); + mynodepda->bte_if[i].notify = 0L; + spin_lock_init(&mynodepda->bte_if[i].spinlock); + + mynodepda->bte_if[i].scratch_buf = + alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER); + mynodepda->bte_if[i].bte_cnode = cnode; + mynodepda->bte_if[i].bte_error_count = 0; + mynodepda->bte_if[i].bte_num = i; + mynodepda->bte_if[i].cleanup_active = 0; + mynodepda->bte_if[i].bh_error = 0; + } + +} + +/* + * bte_init_cpu() + * + * Initialize the cpupda structure with pointers to the + * nodepda bte blocks. + * + */ +void +bte_init_cpu(void) +{ + /* Called by setup.c as each cpu is being added to the nodepda */ + if (local_node_data->active_cpu_count & 0x1) { + pda->cpu_bte_if[0] = &(nodepda->bte_if[0]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[1]); + } else { + pda->cpu_bte_if[0] = &(nodepda->bte_if[1]); + pda->cpu_bte_if[1] = &(nodepda->bte_if[0]); + } } diff -Nru a/arch/ia64/sn/kernel/idle.c b/arch/ia64/sn/kernel/idle.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/kernel/idle.c Wed May 14 16:13:42 2003 @@ -0,0 +1,36 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. + */ + +#include +#include +#include + +void snidle(int state) { + if (state) { + if (pda.idle_flag == 0) { + /* + * Turn the activity LED off. + */ + set_led_bits(0, LED_CPU_ACTIVITY); + } + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) + SIMULATOR_SLEEP(); +#endif + + pda.idle_flag = 1; + } else { + /* + * Turn the activity LED on. + */ + set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); + + pda.idle_flag = 0; + } +} diff -Nru a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c --- a/arch/ia64/sn/kernel/iomv.c Mon Feb 24 04:47:33 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,115 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include - -extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */ - -/** - * sn_inb - read a byte from a port - * @port: port to read from - * - * Reads a byte from @port and returns it to the caller. - */ -unsigned int -sn_inb (unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - unsigned char ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inw - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inw (unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - unsigned short ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_inl - read a word from a port - * @port: port to read from - * - * Reads a word from @port and returns it to the caller. - */ -unsigned int -sn_inl (unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - unsigned int ret; - - ret = *addr; - __ia64_mf_a(); - return ret; -} - -/** - * sn_outb - write a byte to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outb (unsigned char val, unsigned long port) -{ - volatile unsigned char *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outw - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outw (unsigned short val, unsigned long port) -{ - volatile unsigned short *addr = sn_io_addr(port); - - *addr = val; -} - -/** - * sn_outl - write a word to a port - * @port: port to write to - * @val: value to write - * - * Writes @val to @port. - */ -void -sn_outl (unsigned int val, unsigned long port) -{ - volatile unsigned int *addr = sn_io_addr(port); - - *addr = val; -} - -EXPORT_SYMBOL(sn_inb); -EXPORT_SYMBOL(sn_inw); -EXPORT_SYMBOL(sn_inl); -EXPORT_SYMBOL(sn_outb); -EXPORT_SYMBOL(sn_outw); -EXPORT_SYMBOL(sn_outl); diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c --- a/arch/ia64/sn/kernel/irq.c Tue Dec 3 10:07:29 2002 +++ b/arch/ia64/sn/kernel/irq.c Fri May 16 04:18:17 2003 @@ -1,7 +1,7 @@ /* - * Platform dependent support for SGI SN1 + * Platform dependent support for SGI SN * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -32,12 +32,12 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include #include #include #include #include #include +#include #include #include #include @@ -49,19 +49,25 @@ #include #include #include -#ifdef ajmtestintr #include #include -#endif /* ajmtestintr */ #include #include #include #include #include #include -#include +#include +#include +#include +#include int irq_to_bit_pos(int irq); +static void force_interrupt(int irq); +extern void pcibr_force_interrupt(pcibr_intr_t intr); +extern int sn_force_interrupt_flag; + + static unsigned int sn_startup_irq(unsigned int irq) @@ -87,49 +93,11 @@ static void sn_ack_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - int bit = -1; - unsigned long long intpend_val; - int subnode; -#endif -#ifdef CONFIG_IA64_SGI_SN2 unsigned long event_occurred, mask = 0; -#endif int nasid; irq = irq & 0xff; nasid = smp_physical_node_id(); -#ifdef CONFIG_IA64_SGI_SN1 - subnode = cpuid_to_subnode(smp_processor_id()); - if (irq == SGI_UART_IRQ) { - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & (1L<sn_in_service_ivecs); } static void sn_end_irq(unsigned int irq) { -#ifdef CONFIG_IA64_SGI_SN1 - unsigned long long intpend_val, mask = 0x70L; - int subnode; -#endif int nasid; -#ifdef CONFIG_IA64_SGI_SN2 + int ivec; unsigned long event_occurred; -#endif - irq = irq & 0xff; -#ifdef CONFIG_IA64_SGI_SN1 - if (irq == SGI_UART_IRQ) { - nasid = smp_physical_node_id(); - subnode = cpuid_to_subnode(smp_processor_id()); - intpend_val = REMOTE_HUB_PI_L(nasid, subnode, PI_INT_PEND0); - if (intpend_val & mask) { - platform_send_ipi(smp_processor_id(), SGI_UART_IRQ, IA64_IPI_DM_INT, 0); - } - } -#endif -#ifdef CONFIG_IA64_SGI_SN2 - if (irq == SGI_UART_VECTOR) { + ivec = irq & 0xff; + if (ivec == SGI_UART_VECTOR) { nasid = smp_physical_node_id(); event_occurred = HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid,SH_EVENT_OCCURRED) ); // If the UART bit is set here, we may have received an interrupt from the @@ -181,8 +133,9 @@ platform_send_ipi(smp_processor_id(), SGI_UART_VECTOR, IA64_IPI_DM_INT, 0); } } -#endif - + __clear_bit(ivec, (volatile void *)pda->sn_in_service_ivecs); + if (sn_force_interrupt_flag) + force_interrupt(irq); } static void @@ -191,7 +144,7 @@ } -struct hw_interrupt_type irq_type_iosapic_level = { +struct hw_interrupt_type irq_type_sn = { "SN hub", sn_startup_irq, sn_shutdown_irq, @@ -203,29 +156,17 @@ }; -#define irq_type_sn irq_type_iosapic_level -struct irq_desc *_sn_irq_desc[NR_CPUS]; - struct irq_desc * sn_irq_desc(unsigned int irq) { - int cpu = irq >> 8; - irq = irq & 0xff; + irq = SN_IVEC_FROM_IRQ(irq); - return(_sn_irq_desc[cpu] + irq); + return(_irq_desc + irq); } u8 sn_irq_to_vector(u8 irq) { - return(irq & 0xff); -} - -int gsi_to_vector(u32 irq) { - return irq & 0xff; -} - -int gsi_to_irq(u32 irq) { - return irq & 0xff; + return(irq); } unsigned int @@ -233,47 +174,24 @@ return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector)); } -void *kmalloc(size_t, int); - void sn_irq_init (void) { int i; irq_desc_t *base_desc = _irq_desc; - for (i=IA64_FIRST_DEVICE_VECTOR; i 118) bit = 118; -#ifdef CONFIG_IA64_SGI_SN1 - if (bit >= GFX_INTR_A && bit <= CC_PEND_B) { - return SGI_UART_IRQ; - } -#endif - return bit + BIT_TO_IRQ; } @@ -285,53 +203,181 @@ return bit; } -#ifdef ajmtestintr - -#include -struct timer_list intr_test_timer = TIMER_INITIALIZER(NULL, 0, 0); -int intr_test_icount[NR_IRQS]; -struct intr_test_reg_struct { - pcibr_soft_t pcibr_soft; - int slot; +struct pcibr_intr_list_t { + struct pcibr_intr_list_t *next; + pcibr_intr_t intr; }; -struct intr_test_reg_struct intr_test_registered[NR_IRQS]; + +static struct pcibr_intr_list_t **pcibr_intr_list; + +void +register_pcibr_intr(int irq, pcibr_intr_t intr) { + struct pcibr_intr_list_t *p = kmalloc(sizeof(struct pcibr_intr_list_t), GFP_KERNEL); + struct pcibr_intr_list_t *list; + int cpu = SN_CPU_FROM_IRQ(irq); + + if (pcibr_intr_list == NULL) { + pcibr_intr_list = kmalloc(sizeof(struct pcibr_intr_list_t *) * NR_IRQS, GFP_KERNEL); + if (pcibr_intr_list == NULL) panic("Could not allocate memory for pcibr_intr_list\n"); + memset( (void *)pcibr_intr_list, 0, sizeof(struct pcibr_intr_list_t *) * NR_IRQS); + } + if (pdacpu(cpu)->sn_last_irq < irq) { + pdacpu(cpu)->sn_last_irq = irq; + } + if (pdacpu(cpu)->sn_first_irq > irq) pdacpu(cpu)->sn_first_irq = irq; + if (!p) panic("Could not allocate memory for pcibr_intr_list_t\n"); + if ((list = pcibr_intr_list[irq])) { + while (list->next) list = list->next; + list->next = p; + p->next = NULL; + p->intr = intr; + } else { + pcibr_intr_list[irq] = p; + p->next = NULL; + p->intr = intr; + } +} void -intr_test_handle_timer(unsigned long data) { +force_polled_int(void) { int i; - bridge_t *bridge; + struct pcibr_intr_list_t *p; - for (i=0;ibs_intr[intr_test_registered[i].slot].bsi_xtalk_intr; - /* send interrupt */ - bridge = pcibr_soft->bs_base; - bridge->b_force_always[intr_test_registered[i].slot].intr = 1; + for (i=0; iintr){ + pcibr_force_interrupt(p->intr); + } + p = p->next; } } - del_timer(&intr_test_timer); - intr_test_timer.expires = jiffies + HZ/100; - add_timer(&intr_test_timer); } -void -intr_test_set_timer(void) { - intr_test_timer.expires = jiffies + HZ/100; - intr_test_timer.function = intr_test_handle_timer; - add_timer(&intr_test_timer); +static void +force_interrupt(int irq) { + struct pcibr_intr_list_t *p = pcibr_intr_list[irq]; + + while (p) { + if (p->intr) { + pcibr_force_interrupt(p->intr); + } + p = p->next; + } +} + +/* +Check for lost interrupts. If the PIC int_status reg. says that +an interrupt has been sent, but not handled, and the interrupt +is not pending in either the cpu irr regs or in the soft irr regs, +and the interrupt is not in service, then the interrupt may have +been lost. Force an interrupt on that pin. It is possible that +the interrupt is in flight, so we may generate a spurious interrupt, +but we should never miss a real lost interrupt. +*/ + +static void +sn_check_intr(int irq, pcibr_intr_t intr) { + unsigned long regval; + int irr_reg_num; + int irr_bit; + unsigned long irr_reg; + + + regval = intr->bi_soft->bs_base->p_int_status_64; + irr_reg_num = irq_to_vector(irq) / 64; + irr_bit = irq_to_vector(irq) % 64; + switch (irr_reg_num) { + case 0: + irr_reg = ia64_get_irr0(); + break; + case 1: + irr_reg = ia64_get_irr1(); + break; + case 2: + irr_reg = ia64_get_irr2(); + break; + case 3: + irr_reg = ia64_get_irr3(); + break; + } + if (!test_bit(irr_bit, &irr_reg) ) { + if (!test_bit(irq, pda->sn_soft_irr) ) { + if (!test_bit(irq, pda->sn_in_service_ivecs) ) { + regval &= 0xff; + if (intr->bi_ibits & regval & intr->bi_last_intr) { + regval &= ~(intr->bi_ibits & regval); + pcibr_force_interrupt(intr); + } + } + } + } + intr->bi_last_intr = regval; } void -intr_test_register_irq(int irq, pcibr_soft_t pcibr_soft, int slot) { - irq = irq & 0xff; - intr_test_registered[irq].pcibr_soft = pcibr_soft; - intr_test_registered[irq].slot = slot; +sn_lb_int_war_check(void) { + int i; + + if (pda->sn_first_irq == 0) return; + for (i=pda->sn_first_irq; + i <= pda->sn_last_irq; i++) { + struct pcibr_intr_list_t *p = pcibr_intr_list[i]; + if (p == NULL) { + continue; + } + while (p) { + sn_check_intr(i, p->intr); + p = p->next; + } + } +} + +static inline int +sn_get_next_bit(void) { + int i; + int bit; + + for (i = 3; i >= 0; i--) { + if (pda->sn_soft_irr[i] != 0) { + bit = (i * 64) + __ffs(pda->sn_soft_irr[i]); + __change_bit(bit, (volatile void *)pda->sn_soft_irr); + return(bit); + } + } + return IA64_SPURIOUS_INT_VECTOR; } void -intr_test_handle_intr(int irq, void *junk, struct pt_regs *morejunk) { - intr_test_icount[irq]++; - printk("RECEIVED %d INTERRUPTS ON IRQ %d\n",intr_test_icount[irq], irq); +sn_set_tpr(int vector) { + if (vector > IA64_LAST_DEVICE_VECTOR || vector < IA64_FIRST_DEVICE_VECTOR) { + ia64_set_tpr(vector); + } else { + ia64_set_tpr(IA64_LAST_DEVICE_VECTOR); + } +} + +static inline void +sn_get_all_ivr(void) { + int vector; + + vector = ia64_get_ivr(); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + __set_bit(vector, (volatile void *)pda->sn_soft_irr); + ia64_eoi(); + if (vector > IA64_LAST_DEVICE_VECTOR) return; + vector = ia64_get_ivr(); + } +} + +int +sn_get_ivr(void) { + int vector; + + vector = sn_get_next_bit(); + if (vector == IA64_SPURIOUS_INT_VECTOR) { + sn_get_all_ivr(); + vector = sn_get_next_bit(); + } + return vector; } -#endif /* ajmtestintr */ diff -Nru a/arch/ia64/sn/kernel/llsc4.c b/arch/ia64/sn/kernel/llsc4.c --- a/arch/ia64/sn/kernel/llsc4.c Tue Feb 25 02:41:47 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1044 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "llsc4.h" - - -#ifdef STANDALONE -#include "lock.h" -#endif - -#ifdef INTTEST -static int inttest=0; -#endif - -#ifdef IA64_SEMFIX_INSN -#undef IA64_SEMFIX_INSN -#endif -#ifdef IA64_SEMFIX -#undef IA64_SEMFIX -#endif -# define IA64_SEMFIX_INSN -# define IA64_SEMFIX "" - -#define NOLOCK 0xdead -#define BGUARD(linei) (0xbbbb0000 | (linei)); -#define EGUARD(linei) (0xeeee0000 | (linei)); -#define GUARDLINE(v) ((v)&0xffff) - -/* - * Test parameter table for AUTOTEST - */ -typedef struct { - int passes; - int linecount; - int linepad; -} autotest_table_t; - -autotest_table_t autotest_table[] = { - {50000000, 2, 0x2b4 }, - {50000000, 16, 0, }, - {50000000, 16, 4, }, - {50000000, 128, 0x44 }, - {50000000, 128, 0x84 }, - {50000000, 128, 0x200 }, - {50000000, 128, 0x204 }, - {50000000, 128, 0x2b4 }, - {50000000, 2, 8*MB+0x2b4 }, - {50000000, 16, 8*MB+0 }, - {50000000, 16, 8*MB+4 }, - {50000000, 128, 8*MB+0x44 }, - {50000000, 128, 8*MB+0x84 }, - {50000000, 128, 8*MB+0x200 }, - {50000000, 128, 8*MB+0x204 }, - {50000000, 128, 8*MB+0x2b4 }, - {0}}; - -/* - * Array of virtual addresses available for test purposes. - */ - -typedef struct { - long vstart; - long vend; - long nextaddr; - long nextinit; - int wrapcount; -} memmap_t; - -#define MAPCHUNKS 128 -memmap_t memmap[MAPCHUNKS]; -int memmapx=0; - -typedef struct { - void *addr; - long data[16]; - long data_fc[16]; -} capture_line_t; - -typedef struct { - int size; - void *blockaddr; - void *shadaddr; - long blockdata[48]; - long shaddata[48]; - long blockdata_fc[48]; - long shaddata_fc[48]; - long synerr; -} capture_t; - -/* - * PORTING NOTE: revisit this statement. On hardware we put mbase at 0 and - * the rest of the tables have to start at 1MB to skip PROM tables. - */ -#define THREADPRIVATESZ() ((sizeof(threadprivate_t)+511)/512*512) -#define THREADPRIVATE(t) ((threadprivate_t*)(((long)mbase)+4096+t*THREADPRIVATESZ())) - -#define k_capture mbase->sk_capture -#define k_go mbase->sk_go -#define k_linecount mbase->sk_linecount -#define k_passes mbase->sk_passes -#define k_napticks mbase->sk_napticks -#define k_stop_on_error mbase->sk_stop_on_error -#define k_verbose mbase->sk_verbose -#define k_threadprivate mbase->sk_threadprivate -#define k_blocks mbase->sk_blocks -#define k_iter_msg mbase->sk_iter_msg -#define k_vv mbase->sk_vv -#define k_linepad mbase->sk_linepad -#define k_options mbase->sk_options -#define k_testnumber mbase->sk_testnumber -#define k_currentpass mbase->sk_currentpass - -static long blocks[MAX_LINECOUNT]; /* addresses of data blocks */ -static control_t *mbase; -static vint initialized=0; - -static unsigned int ran_conf_llsc(int); -static int rerr(capture_t *, char *, void *, void *, int, int, int, int, int, int); -static void dumpline(void *, char *, char *, void *, void *, int); -static int checkstop(int, int, uint); -static void spin(int); -static void capturedata(capture_t *, uint, void *, void *, int); -static int randn(uint max, uint *seed); -static uint zrandom (uint *zranseed); -static int set_lock(uint *, uint); -static int clr_lock(uint *, uint); -static void Speedo(void); - -int autotest_enabled=0; -static int llsctest_number=-1; -static int errstop_enabled=0; -static int fail_enabled=0; -static int l4_opt=0; -static int selective_trigger=0; -static int dump_block_addrs_opt=0; -static lock_t errlock=NOLOCK; -static private_t init_private[LLSC_MAXCPUS]; - -static int __init autotest_enable(char *str) -{ - autotest_enabled = 1; - return 1; -} -static int __init set_llscblkadr(char *str) -{ - dump_block_addrs_opt = 1; - return 1; -} -static int __init set_llscselt(char *str) -{ - selective_trigger = 1; - return 1; -} -static int __init set_llsctest(char *str) -{ - llsctest_number = simple_strtol(str, &str, 10); - if (llsctest_number < 0 || llsctest_number > 15) - llsctest_number = -1; - return 1; -} -static int __init set_llscerrstop(char *str) -{ - errstop_enabled = 1; - return 1; -} -static int __init set_llscfail(char *str) -{ - fail_enabled = 8; - return 1; -} -static int __init set_llscl4(char *str) -{ - l4_opt = 1; - return 1; -} - -static void print_params(void) -{ - printk ("********* Enter AUTOTEST facility on master cpu *************\n"); - printk (" Test options:\n"); - printk (" llsctest=\t%d\tTest number to run (all = -1)\n", llsctest_number); - printk (" llscerrstop \t%s\tStop on error\n", errstop_enabled ? "on" : "off"); - printk (" llscfail \t%s\tForce a failure to test the trigger & error messages\n", fail_enabled ? "on" : "off"); - printk (" llscselt \t%s\tSelective triger on failures\n", selective_trigger ? "on" : "off"); - printk (" llscblkadr \t%s\tDump data block addresses\n", dump_block_addrs_opt ? "on" : "off"); - printk (" llscl4 \t%s\tRun only tests that evict from L4\n", l4_opt ? "on" : "off"); - printk (" SEMFIX: %s\n", IA64_SEMFIX); - printk ("\n"); -} -__setup("autotest", autotest_enable); -__setup("llsctest=", set_llsctest); -__setup("llscerrstop", set_llscerrstop); -__setup("llscfail", set_llscfail); -__setup("llscselt", set_llscselt); -__setup("llscblkadr", set_llscblkadr); -__setup("llscl4", set_llscl4); - - - -static inline int -set_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_acq(lock, NOLOCK, id); - return (old == NOLOCK); -} - -static inline int -clr_lock(uint *lock, uint id) -{ - uint old; - old = cmpxchg_rel(lock, id, NOLOCK); - return (old == id); -} - -static inline void -init_lock(uint *lock) -{ - *lock = NOLOCK; -} - -/*------------------------------------------------------------------------+ -| Routine : ran_conf_llsc - ll/sc shared data test | -| Description: This test checks the coherency of shared data | -+------------------------------------------------------------------------*/ -static unsigned int -ran_conf_llsc(int thread) -{ - private_t pval; - share_t sval, sval2; - uint vv, linei, slinei, sharei, pass; - long t; - lock_t lockpat; - share_t *sharecopy; - long verbose, napticks, passes, linecount, lcount; - dataline_t *linep, *slinep; - int s, seed; - threadprivate_t *tp; - uint iter_msg, iter_msg_i=0; - int vv_mask; - int correct_errors; - int errs=0; - int stillbad; - capture_t capdata; - private_t *privp; - share_t *sharep; - - - linecount = k_linecount; - napticks = k_napticks; - verbose = k_verbose; - passes = k_passes; - iter_msg = k_iter_msg; - seed = (thread + 1) * 647; - tp = THREADPRIVATE(thread); - vv_mask = (k_vv>>((thread%16)*4)) & 0xf; - correct_errors = k_options&0xff; - - memset (&capdata, 0, sizeof(capdata)); - for (linei=0; lineiprivate[linei] = thread; - - for (pass = 1; passes == 0 || pass < passes; pass++) { - lockpat = (pass & 0x0fffffff) + (thread <<28); - if (lockpat == NOLOCK) - continue; - tp->threadpasses = pass; - if (checkstop(thread, pass, lockpat)) - return 0; - iter_msg_i++; - if (iter_msg && iter_msg_i > iter_msg) { - printk("Thread %d, Pass %d\n", thread, pass); - iter_msg_i = 0; - } - lcount = 0; - - /* - * Select line to perform operations on. - */ - linei = randn(linecount, &seed); - sharei = randn(2, &seed); - slinei = (linei + (linecount/2))%linecount; /* I don't like this - fix later */ - - linep = (dataline_t *)blocks[linei]; - slinep = (dataline_t *)blocks[slinei]; - if (sharei == 0) - sharecopy = &slinep->share0; - else - sharecopy = &slinep->share1; - - - vv = randn(4, &seed); - if ((vv_mask & (1<private[thread]; - sharep = &linep->share[sharei]; - - switch(vv) { - case 0: - /* Read and verify private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - if (correct_errors) { - tp->private[linei] = *privp; - } - errs++; - } - break; - - case 1: - /* Read, verify, and increment private count on line. */ - pval = *privp; - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, tp->private[linei]); - if (pval != tp->private[linei]) { - capturedata(&capdata, pass, privp, NULL, sizeof(*privp)); - stillbad = (*privp != tp->private[linei]); - if (rerr(&capdata, "Private count & inc", linep, slinep, thread, pass, linei, tp->private[linei], pval, stillbad)) { - return 1; - } - errs++; - } - pval = (pval==255) ? 0 : pval+1; - *privp = pval; - tp->private[linei] = pval; - break; - - case 2: - /* Lock line, read and verify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - - sval = *sharep; - sval2 = *sharecopy; - if (pass > 12 && thread == 0 && fail_enabled == 1) - sval++; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - if (correct_errors) - *sharep = *sharecopy; - errs++; - } - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data unlock", linep, slinep, thread, pass, linei, lockpat, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - - case 3: - /* Lock line, read and verify shared data, modify shared data. */ - if (verbose) - printk("Line:%3d, Thread:%d:%d. Val: %x\n", linei, thread, vv, *sharecopy); - lcount = 0; - while (LOCK(sharei) != 1) { - if (checkstop(thread, pass, lockpat)) - return 0; - if (lcount++>1000000) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, sizeof(lock_t)); - stillbad = (GETLOCK(sharei) != 0); - rerr(&capdata, "Shared data lock & inc", linep, slinep, thread, pass, linei, 0, GETLOCK(sharei), stillbad); - return 1; - } - if ((lcount&0x3fff) == 0) - udelay(1000); - } - sval = *sharep; - sval2 = *sharecopy; - if (sval != sval2) { - capturedata(&capdata, pass, sharep, sharecopy, sizeof(*sharecopy)); - stillbad = (*sharep != *sharecopy); - if (!stillbad && *sharep != sval && *sharecopy == sval2) - stillbad = 2; - if (rerr(&capdata, "Shared data & inc", linep, slinep, thread, pass, linei, sval2, sval, stillbad)) { - return 1; - } - errs++; - } - - *sharep = lockpat; - *sharecopy = lockpat; - - - if ( (s=UNLOCK(sharei)) != 1) { - capturedata(&capdata, pass, LOCKADDR(sharei), NULL, 4); - stillbad = (GETLOCK(sharei) != lockpat); - if (rerr(&capdata, "Shared data & inc unlock", linep, slinep, thread, pass, linei, thread, GETLOCK(sharei), stillbad)) - return 1; - if (correct_errors) - ZEROLOCK(sharei); - errs++; - } - break; - } - } - - return (errs > 0); -} - -static void -trigger_la(long val) -{ - long *p; - - p = (long*)0xc0000a0001000020L; /* PI_CPU_NUM */ - *p = val; -} - -static long -getsynerr(void) -{ - long err, *errp; - - errp = (long*)0xc0000e0000000340L; /* SYN_ERR */ - err = *errp; - if (err) - *errp = -1L; - return (err & ~0x60); -} - -static int -rerr(capture_t *cap, char *msg, void *lp, void *slp, int thread, int pass, int badlinei, int exp, int found, int stillbad) -{ - int cpu, i, linei; - long synerr; - int selt; - - - selt = selective_trigger && stillbad > 1 && - memcmp(cap->blockdata, cap->blockdata_fc, 128) != 0 && - memcmp(cap->shaddata, cap->shaddata_fc, 128) == 0; - if (selt) { - trigger_la(pass); - } else if (selective_trigger) { - k_go = ST_STOP; - return k_stop_on_error;; - } - - spin(1); - i = 100; - while (i && set_lock(&errlock, 1) != 1) { - spin(1); - i--; - } - printk ("\nDataError!: %-20s, test %ld, thread %d, line:%d, pass %d (0x%x), time %ld expected:%x, found:%x\n", - msg, k_testnumber, thread, badlinei, pass, pass, jiffies, exp, found); - - dumpline (lp, "Corrupted data", "D ", cap->blockaddr, cap->blockdata, cap->size); -#ifdef ZZZ - if (memcmp(cap->blockdata, cap->blockdata_fc, 128)) - dumpline (lp, "Corrupted data", "DF", cap->blockaddr, cap->blockdata_fc, cap->size); -#endif - - if (cap->shadaddr) { - dumpline (slp, "Shadow data", "S ", cap->shadaddr, cap->shaddata, cap->size); -#ifdef ZZZ - if (memcmp(cap->shaddata, cap->shaddata_fc, 128)) - dumpline (slp, "Shadow data", "SF", cap->shadaddr, cap->shaddata_fc, cap->size); -#endif - } - - printk("Threadpasses: "); - for (cpu=0,i=0; cputhreadpasses) { - if (i && (i%8) == 0) - printk("\n : "); - printk(" %d:0x%x", cpu, k_threadprivate[cpu]->threadpasses); - i++; - } - printk("\n"); - - for (linei=0; lineiguard1); - g2linei = GUARDLINE(linep->guard2); - g1err = (g1linei != linei); - g2err = (g2linei != linei); - sh0err = (linep->share[0] != slinep->share0); - sh1err = (linep->share[1] != slinep->share1); - - if (g1err || g2err || sh0err || sh1err) { - printk("Line 0x%lx (%03d), %sG1 0x%lx (%03d), %sG2 0x%lx (%03d), %sSH0 %08x (%08x), %sSH1 %08x (%08x)\n", - blocks[linei], linei, - g1err ? "*" : " ", blocks[g1linei], g1linei, - g2err ? "*" : " ", blocks[g2linei], g2linei, - sh0err ? "*" : " ", linep->share[0], slinep->share0, - sh1err ? "*" : " ", linep->share[1], slinep->share1); - - - } - } - - printk("\nData was %sfixed by flushcache\n", (stillbad == 1 ? "**** NOT **** " : " ")); - synerr = getsynerr(); - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - spin(2); - printk("\n\n"); - clr_lock(&errlock, 1); - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - return k_stop_on_error; -} - - -static void -dumpline(void *lp, char *str1, char *str2, void *addr, void *data, int size) -{ - long *p; - int i, off; - - printk("%s at 0x%lx, size %d, block starts at 0x%lx\n", str1, (long)addr, size, (long)lp); - p = (long*) data; - for (i=0; i<48; i++, p++) { - if (i%8 == 0) printk("%2s", i==16 ? str2 : " "); - printk(" %016lx", *p); - if ((i&7)==7) printk("\n"); - } - printk(" "); - off = (((long)addr) ^ size) & 63L; - for (i=0; i=off) ? "--" : " "); - if ((i%8) == 7) - printk(" "); - } - - off = ((long)addr) & 127; - printk(" (line %d)\n", 2+off/64+1); -} - - -static int -randn(uint max, uint *seedp) -{ - if (max == 1) - return(0); - else - return((int)(zrandom(seedp)>>10) % max); -} - - -static int -checkstop(int thread, int pass, uint lockpat) -{ - long synerr; - - if (k_go == ST_RUN) - return 0; - if (k_go == ST_STOP) - return 1; - - if (errstop_enabled) { - local_irq_disable(); - while(1); - } - synerr = getsynerr(); - spin(2); - if (k_go == ST_STOP) - return 1; - if (synerr) - printk("SYNERR: Thread %d, Synerr: 0x%lx\n", thread, synerr); - return 1; -} - - -static void -spin(int j) -{ - udelay(j * 500000); -} - -static void -capturedata(capture_t *cap, uint pass, void *blockaddr, void *shadaddr, int size) -{ - - if (!selective_trigger) - trigger_la (pass); - - memcpy (cap->blockdata, CACHEALIGN(blockaddr)-128, 3*128); - if (shadaddr) - memcpy (cap->shaddata, CACHEALIGN(shadaddr)-128, 3*128); - - if (k_stop_on_error) { - k_go = ST_ERRSTOP; - } - - cap->size = size; - cap->blockaddr = blockaddr; - cap->shadaddr = shadaddr; - - asm volatile ("fc %0" :: "r"(blockaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->blockdata_fc, CACHEALIGN(blockaddr)-128, 3*128); - - if (shadaddr) { - asm volatile ("fc %0" :: "r"(shadaddr) : "memory"); - ia64_sync_i(); - ia64_srlz_d(); - memcpy (cap->shaddata_fc, CACHEALIGN(shadaddr)-128, 3*128); - } -} - -int zranmult = 0x48c27395; - -static uint -zrandom (uint *seedp) -{ - *seedp = (*seedp * zranmult) & 0x7fffffff; - return (*seedp); -} - - -void -set_autotest_params(void) -{ - static int testnumber=-1; - - if (llsctest_number >= 0) { - testnumber = llsctest_number; - } else { - testnumber++; - if (autotest_table[testnumber].passes == 0) { - testnumber = 0; - dump_block_addrs_opt = 0; - } - } - if (testnumber == 0 && l4_opt) testnumber = 9; - - k_passes = autotest_table[testnumber].passes; - k_linepad = autotest_table[testnumber].linepad; - k_linecount = autotest_table[testnumber].linecount; - k_testnumber = testnumber; - - if (IS_RUNNING_ON_SIMULATOR()) { - printk ("llsc start test %ld\n", k_testnumber); - k_passes = 1000; - } -} - - -static void -set_leds(int errs) -{ - unsigned char leds=0; - - /* - * Leds are: - * ppppeee- - * where - * pppp = test number - * eee = error count but top bit is stick - */ - - leds = ((errs&7)<<1) | ((k_testnumber&15)<<4) | (errs ? 0x08 : 0); - set_led_bits(leds, LED_MASK_AUTOTEST); -} - -static void -setup_block_addresses(void) -{ - int i, stride, memmapi; - dataline_t *dp; - long *ip, *ipe; - - - stride = k_linepad + sizeof(dataline_t); - memmapi = 0; - for (i=0; i= memmap[memmapi].vend) { - memmap[memmapi].wrapcount++; - memmap[memmapi].nextaddr = memmap[memmapi].vstart + - memmap[memmapi].wrapcount * sizeof(dataline_t); - } - - ip = (long*)((memmap[memmapi].nextinit+7)&~7); - ipe = (long*)(memmap[memmapi].nextaddr+2*sizeof(dataline_t)+8); - while(ip <= ipe && ip < ((long*)memmap[memmapi].vend-8)) - *ip++ = (long)ip; - memmap[memmapi].nextinit = (long) ipe; - dp->guard1 = BGUARD(i); - dp->guard2 = EGUARD(i); - dp->lock[0] = dp->lock[1] = NOLOCK; - dp->share[0] = dp->share0 = 0x1111; - dp->share[1] = dp->share1 = 0x2222; - memcpy(dp->private, init_private, LLSC_MAXCPUS*sizeof(private_t)); - - - if (stride > 16384) { - memmapi++; - if (memmapi == memmapx) - memmapi = 0; - } - } - -} - -static void -dump_block_addrs(void) -{ - int i; - - printk("LLSC TestNumber %ld\n", k_testnumber); - - for (i=0; ithreadstate == TS_KILLED) { - set_led_bits(LED_MASK_AUTOTEST, LED_MASK_AUTOTEST); - while(1); - } - k_threadprivate[cpuid]->threadstate = state; -} - -#define MINBLK (16*1024*1024) -static int -build_mem_map(unsigned long start, unsigned long end, void *arg) -{ - long lstart, lend; - long align = 8*MB; - - printk ("LLSC memmap: start 0x%lx, end 0x%lx, (0x%lx - 0x%lx)\n", - start, end, (long) virt_to_page(start), (long) virt_to_page(end-PAGE_SIZE)); - - if (memmapx >= MAPCHUNKS || (end-start) < MINBLK) - return 0; - - /* - * Start in the middle of the range & find the first non-free page in both directions - * from the midpoint. This is likely to be the bigest free block. - */ - lend = lstart = start + (end-start)/2; - while (lend < end && !PageReserved(virt_to_page(lend)) && virt_to_page(lend)->count.counter == 0) - lend += PAGE_SIZE; - lend -= PAGE_SIZE; - - while (lstart >= start && !PageReserved(virt_to_page(lstart)) && virt_to_page(lstart)->count.counter == 0) - lstart -= PAGE_SIZE; - lstart += PAGE_SIZE; - - lstart = (lstart + align -1) /align * align; - end = end / align * align; - if (lstart >= end) - return 0; - printk (" memmap: start 0x%lx, end 0x%lx\n", lstart, end); - - memmap[memmapx].vstart = lstart; - memmap[memmapx].vend = end; - memmapx++; - return 0; -} - -void int_test(void); - -int -llsc_main (int cpuid) -{ - int i, cpu, is_master, repeatcnt=0; - unsigned int preverr=0, errs=0, pass=0; - int automode=0; - -#ifdef INTTEST - if (inttest) - int_test(); -#endif - - if (!autotest_enabled) - return 0; - -#ifdef CONFIG_SMP - is_master = !smp_processor_id(); -#else - is_master = 1; -#endif - - - if (is_master) { - mbase = (control_t*) __get_free_pages(GFP_KERNEL, get_order(4096+THREADPRIVATESZ()*LLSC_MAXCPUS)); - printk("LLSC: mbase 0x%lx\n", (long)mbase); - print_params(); - if(!IS_RUNNING_ON_SIMULATOR()) - spin(10); - k_currentpass = 0; - k_go = ST_IDLE; - k_passes = DEF_PASSES; - k_napticks = DEF_NAPTICKS; - k_stop_on_error = DEF_STOP_ON_ERROR; - k_verbose = DEF_VERBOSE; - k_linecount = DEF_LINECOUNT; - k_iter_msg = DEF_ITER_MSG; - k_vv = DEF_VV; - k_linepad = DEF_LINEPAD; - k_blocks = (void*)blocks; - efi_memmap_walk(build_mem_map, 0); - -#ifdef CONFIG_IA64_SGI_AUTOTEST - automode = 1; -#endif - - for (i=0; i 5) { - set_autotest_params(); - repeatcnt = 0; - } - } else { - while (k_go == ST_IDLE); - } - - k_go = ST_INIT; - if (k_linecount > MAX_LINECOUNT) k_linecount = MAX_LINECOUNT; - k_linecount = k_linecount & ~1; - setup_block_addresses(); - if (!preverr && dump_block_addrs_opt) - dump_block_addrs(); - - k_currentpass = pass++; - k_go = ST_RUN; - if (fail_enabled) - fail_enabled--; - - } else { - while (k_go != ST_RUN || k_currentpass != pass); - pass++; - } - - - set_leds(errs); - set_thread_state(cpuid, TS_RUNNING); - - errs += ran_conf_llsc(cpuid); - preverr = (k_go == ST_ERRSTOP); - - set_leds(errs); - set_thread_state(cpuid, TS_STOPPED); - - if (is_master) { - Speedo(); - for (i=0, cpu=0; cputhreadstate == TS_RUNNING) { - i++; - if (i == 10000) { - k_go = ST_STOP; - printk (" llsc master stopping test number %ld\n", k_testnumber); - } - if (i > 100000) { - k_threadprivate[cpu]->threadstate = TS_KILLED; - printk (" llsc: master killing cpuid %d, running test number %ld\n", - cpu, k_testnumber); - } - udelay(1000); - } - } - } - - goto loop; -} - - -static void -Speedo(void) -{ - static int i = 0; - - switch (++i%4) { - case 0: - printk("|\b"); - break; - case 1: - printk("\\\b"); - break; - case 2: - printk("-\b"); - break; - case 3: - printk("/\b"); - break; - } -} - -#ifdef INTTEST - -/* ======================================================================================================== - * - * Some test code to verify that interrupts work - * - * Add the following to the arch/ia64/kernel/smp.c after the comment "Reschedule callback" - * if (zzzprint_resched) printk(" cpu %d got interrupt\n", smp_processor_id()); - * - * Enable the code in arch/ia64/sn/sn1/smp.c to print sending IPIs. - * - */ - -static int __init set_inttest(char *str) -{ - inttest = 1; - autotest_enabled = 1; - - return 1; -} - -__setup("inttest=", set_inttest); - -int zzzprint_resched=0; - -void -int_test() { - int mycpu, cpu; - static volatile int control_cpu=0; - - mycpu = smp_processor_id(); - zzzprint_resched = 2; - - printk("Testing cross interrupts\n"); - - while (control_cpu != smp_num_cpus) { - if (mycpu == cpu_logical_map(control_cpu)) { - for (cpu=0; cpulock[(i)] -#define LOCK(i) set_lock(LOCKADDR(i), lockpat) -#define UNLOCK(i) clr_lock(LOCKADDR(i), lockpat) -#define GETLOCK(i) *LOCKADDR(i) -#define ZEROLOCK(i) init_lock(LOCKADDR(i)) - -#define CACHEALIGN(a) ((char*)((long)(a) & ~127L)) - -typedef uint guard_t; -typedef uint lock_t; -typedef uint share_t; -typedef uchar private_t; - -typedef struct { - guard_t guard1; - lock_t lock[2]; - share_t share[2]; - private_t private[LLSC_MAXCPUS]; - share_t share0; - share_t share1; - guard_t guard2; -} dataline_t ; - - -#define LINEPAD k_linepad -#define LINESTRIDE (((sizeof(dataline_t)+CACHELINE-1)/CACHELINE)*CACHELINE + LINEPAD) - - -typedef struct { - vint threadstate; - uint threadpasses; - private_t private[MAX_LINECOUNT]; -} threadprivate_t; - -typedef struct { - vlong sk_go; /* 0=idle, 1=init, 2=run */ - long sk_linecount; - long sk_passes; - long sk_napticks; - long sk_stop_on_error; - long sk_verbose; - long sk_iter_msg; - long sk_vv; - long sk_linepad; - long sk_options; - long sk_testnumber; - vlong sk_currentpass; - void *sk_blocks; - threadprivate_t *sk_threadprivate[LLSC_MAXCPUS]; -} control_t; - -/* Run state (k_go) constants */ -#define ST_IDLE 0 -#define ST_INIT 1 -#define ST_RUN 2 -#define ST_STOP 3 -#define ST_ERRSTOP 4 - - -/* Threadstate constants */ -#define TS_STOPPED 0 -#define TS_RUNNING 1 -#define TS_KILLED 2 - - - -int llsc_main (int cpuid); - diff -Nru a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c --- a/arch/ia64/sn/kernel/machvec.c Sat May 10 02:28:47 2003 +++ b/arch/ia64/sn/kernel/machvec.c Fri May 16 04:18:18 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -30,32 +30,5 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan */ -#include - -#ifdef CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn1 -#define MACHVEC_PLATFORM_HEADER -#else CONFIG_IA64_SGI_SN1 -#define MACHVEC_PLATFORM_NAME sn2 -#define MACHVEC_PLATFORM_HEADER -#else -#error "unknown platform" -#endif - +#define MACHVEC_PLATFORM_NAME sn2 #include -#include -#include -void* -sn_mk_io_addr_MACRO - -dma_addr_t -sn_pci_map_single_MACRO - -int -sn_pci_map_sg_MACRO - -unsigned long -sn_virt_to_phys_MACRO - -void * -sn_phys_to_virt_MACRO diff -Nru a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c --- a/arch/ia64/sn/kernel/mca.c Mon Feb 24 04:50:23 2003 +++ b/arch/ia64/sn/kernel/mca.c Fri May 16 04:18:17 2003 @@ -2,7 +2,7 @@ * File: mca.c * Purpose: SN specific MCA code. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -34,247 +34,101 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_KDB -#include -#endif - -#include -#include -#include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include - -static char *shub_mmr_names[] = { - "sh_event_occurred", - "sh_first_error", - "sh_event_overflow", - -/* PI */ - "sh_pi_first_error", - "sh_pi_error_summary", - "sh_pi_error_overflow", - -/* PI HW */ - "sh_pi_error_detail_1", - "sh_pi_error_detail_2", - "sh_pi_hw_time_stamp", - -/* PI UCE */ - "sh_pi_uncorrected_detail_1", - "sh_pi_uncorrected_detail_2", - "sh_pi_uncorrected_detail_3", - "sh_pi_uncorrected_detail_4", - "sh_pi_uncor_time_stamp", - -/* PI CE */ - "sh_pi_corrected_detail_1", - "sh_pi_corrected_detail_2", - "sh_pi_corrected_detail_3", - "sh_pi_corrected_detail_4", - "sh_pi_cor_time_stamp", - -/* MD */ - "sh_mem_error_summary", - "sh_mem_error_overflow", -/* MD HW */ - "sh_misc_err_hdr_upper", - "sh_misc_err_hdr_lower", - "sh_md_dqlp_mmr_xperr_val", - "sh_md_dqlp_mmr_yperr_val", - "sh_md_dqrp_mmr_xperr_val", - "sh_md_dqrp_mmr_yperr_val", - "sh_md_hw_time_stamp", - -/* MD UCE */ - "sh_dir_uc_err_hdr_lower", - "sh_dir_uc_err_hdr_upper", - "sh_md_dqlp_mmr_xuerr1", - "sh_md_dqlp_mmr_xuerr2", - "sh_md_dqlp_mmr_yuerr1", - "sh_md_dqlp_mmr_yuerr2", - "sh_md_dqrp_mmr_xuerr1", - "sh_md_dqrp_mmr_xuerr2", - "sh_md_dqrp_mmr_yuerr1", - "sh_md_dqrp_mmr_yuerr2", - "sh_md_uncor_time_stamp", - -/* MD CE */ - "sh_dir_cor_err_hdr_lower", - "sh_dir_cor_err_hdr_upper", - "sh_md_dqlp_mmr_xcerr1", - "sh_md_dqlp_mmr_xcerr2", - "sh_md_dqlp_mmr_ycerr1", - "sh_md_dqlp_mmr_ycerr2", - "sh_md_dqrp_mmr_xcerr1", - "sh_md_dqrp_mmr_xcerr2", - "sh_md_dqrp_mmr_ycerr1", - "sh_md_dqrp_mmr_ycerr2", - "sh_md_cor_time_stamp", - -/* MD CE, UCE */ - "sh_md_dqls_mmr_xamopw_err", - "sh_md_dqrs_mmr_yamopw_err", - -/* XN */ - "sh_xn_error_summary", - "sh_xn_first_error", - "sh_xn_error_overflow", - -/* XN HW */ - "sh_xniilb_error_summary", - "sh_xniilb_first_error", - "sh_xniilb_error_overflow", - "sh_xniilb_error_detail_1", - "sh_xniilb_error_detail_2", - "sh_xniilb_error_detail_3", - - "sh_ni0_error_summary_1", - "sh_ni0_first_error_1", - "sh_ni0_error_overflow_1", - - "sh_ni0_error_summary_2", - "sh_ni0_first_error_2", - "sh_ni0_error_overflow_2", - "sh_ni0_error_detail_1", - "sh_ni0_error_detail_2", - "sh_ni0_error_detail_3", - - "sh_ni1_error_summary_1", - "sh_ni1_first_error_1", - "sh_ni1_error_overflow_1", - - "sh_ni1_error_summary_2", - "sh_ni1_first_error_2", - "sh_ni1_error_overflow_2", - - "sh_ni1_error_detail_1", - "sh_ni1_error_detail_2", - "sh_ni1_error_detail_3", - - "sh_xn_hw_time_stamp", - -/* XN HW & UCE & SBE */ - "sh_xnpi_error_summary", - "sh_xnpi_first_error", - "sh_xnpi_error_overflow", - "sh_xnpi_error_detail_1", - - "sh_xnmd_error_summary", - "sh_xnmd_first_error", - "sh_xnmd_error_overflow", - "sh_xnmd_ecc_err_report", - "sh_xnmd_error_detail_1", - -/* XN UCE */ - "sh_xn_uncorrected_detail_1", - "sh_xn_uncorrected_detail_2", - "sh_xn_uncorrected_detail_3", - "sh_xn_uncorrected_detail_4", - "sh_xn_uncor_time_stamp", - -/* XN CE */ - "sh_xn_corrected_detail_1", - "sh_xn_corrected_detail_2", - "sh_xn_corrected_detail_3", - "sh_xn_corrected_detail_4", - "sh_xn_cor_time_stamp", - -/* LB HW */ - "sh_lb_error_summary", - "sh_lb_first_error", - "sh_lb_error_overflow", - "sh_lb_error_detail_1", - "sh_lb_error_detail_2", - "sh_lb_error_detail_3", - "sh_lb_error_detail_4", - "sh_lb_error_detail_5", - "sh_junk_error_status", -}; -void -sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) + +/* + * Interval for calling SAL to poll for errors that do NOT cause error + * interrupts. SAL will raise a CPEI if any errors are present that + * need to be logged. + */ +#define CPEI_INTERVAL (5*HZ) + + +struct timer_list sn_cpei_timer; +void sn_init_cpei_timer(void); + + +/* + * print_hook + * + * This function is the callback routine that SAL calls to log error + * info for platform errors. + */ +static int +print_hook(const char *fmt, ...) { - sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data; - u64 *mmr_val = (u64 *)&(sh_info->shub_state); - char **mmr_name = shub_mmr_names; - int mmr_count = sizeof(sal_log_shub_state_t)>>3; - - while(mmr_count) { - if(*mmr_val) { - prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val); - } - mmr_name++; - mmr_val++; - mmr_count--; - } + static int newline=1; + char buf[400], *p; + va_list args; + int len=0; -} -void -sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) { + va_start(args, fmt); + if (newline) { + strcpy(buf, "+ "); + len += 2; + } + len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args); - struct ia64_sal_retval isrv; -// this function's sole purpose is to call SAL when we receive -// a CE interrupt from SHUB or when the timer routine decides -// we need to call SAL to check for CEs. + /* Prefix each line with "+ " to be consistent with mca.c. */ + p = buf; + while ((p=strchr(p, '\n')) && *++p != '\0') { + memmove(p+2, p, 1+strlen(p)); + strncpy(p, "+ ", 2); + len += 2; + } + newline = (p != 0); - // CALL SAL_LOG_CE - SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0); + va_end(args); + printk("%s", buf); + return len; } -#include -#define CPEI_INTERVAL (HZ/100) -struct timer_list sn_cpei_timer = TIMER_INITIALIZER(NULL, 0, 0); -void sn_init_cpei_timer(void); +/* + * ia64_sn2_platform_plat_specific_err_print + * + * Called by the MCA handler to log platform-specific errors. + */ void -sn_cpei_timer_handler(unsigned long dummy) { - sn_cpei_handler(-1, NULL, NULL); - del_timer(&sn_cpei_timer); - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_cpei_timer); +ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) +{ + ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len); } -void -sn_init_cpei_timer() { - sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; - sn_cpei_timer.function = sn_cpei_timer_handler; - add_timer(&sn_cpei_timer); -} -#ifdef ajmtestceintr -struct timer_list sn_ce_timer; +static void +sn_cpei_handler(int irq, void *devid, struct pt_regs *regs) +{ + /* + * this function's sole purpose is to call SAL when we receive + * a CE interrupt from SHUB or when the timer routine decides + * we need to call SAL to check for CEs. + */ + + /* CALL SAL_LOG_CE */ -void -sn_ce_timer_handler(long dummy) { - unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00; + ia64_sn_plat_cpei_handler(); +} - *pi_ce_error_inject_reg = 0x0000000000000100; - del_timer(&sn_ce_timer); - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - add_timer(&sn_ce_timer); + +static void +sn_cpei_timer_handler(unsigned long dummy) { + sn_cpei_handler(-1, NULL, NULL); + mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL); } -sn_init_ce_timer() { - sn_ce_timer.expires = jiffies + CPEI_INTERVAL; - sn_ce_timer.function = sn_ce_timer_handler; - add_timer(&sn_ce_timer); +void +sn_init_cpei_timer() { + sn_cpei_timer.expires = jiffies + CPEI_INTERVAL; + sn_cpei_timer.function = sn_cpei_timer_handler; + add_timer(&sn_cpei_timer); } -#endif /* ajmtestceintr */ diff -Nru a/arch/ia64/sn/kernel/misctest.c b/arch/ia64/sn/kernel/misctest.c --- a/arch/ia64/sn/kernel/misctest.c Wed Dec 4 07:10:56 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,371 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern int autotest_enabled; -long mcatest=0, debug0, debug1, debug2, debug3; - -#define HDELAY(t) (IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t)) - -/* - * mcatest - * mactest contains a decimal number (RPTT) where - * R - flag, if non zero, run forever - * - * P - identifies when to run the test - * 0 execute test at cpu 0 early init - * 1 execute test at cpu 0 idle - * 2 execute test at last (highest numbered) cpu idle - * 3 execute test on all cpus at idle - * - * TT- identifies test to run - * 01 = MCA via dup TLB dropin - * 02 = MCA via garbage address - * 03 = lfetch via garbage address - * 05 = INIT self - * 06 = INIT other cpu - * 07 = INIT non-existent cpu - * 10 = IPI stress test. Target cpu 0 - * 11 = IPI stress test. Target all cpus - * 12 = TLB stress test - * 13 = Park cpu (spinloop) - * 14 = One shot TLB test with tlb spinlock - * 15 = One shot TLB test - * 16 = One shot TLB test sync'ed with RTC - * 20 = set led to the cpuid & spin. - * 21 = Try mixed cache/uncached refs & see what happens - * 22 = Call SAL reboot - * 23 = Call PAL halt - */ -static int __init set_mcatest(char *str) -{ - int val; - get_option(&str, &val); - mcatest = val; - return 1; -} -__setup("mcatest=", set_mcatest); - -static int __init set_debug0(char *str) -{ - int val; - get_option(&str, &val); - debug0 = val; - return 1; -} -__setup("debug0=", set_debug0); - -static int __init set_debug1(char *str) -{ - int val; - get_option(&str, &val); - debug1 = val; - return 1; -} -__setup("debug1=", set_debug1); - -static int __init set_debug2(char *str) -{ - int val; - get_option(&str, &val); - debug2 = val; - return 1; -} -__setup("debug2=", set_debug2); - -static int __init set_debug3(char *str) -{ - int val; - get_option(&str, &val); - debug3 = val; - return 1; -} -__setup("debug3=", set_debug3); - -static volatile int go; - -static void -do_sync(int pos) { - if (pos != 3) - return; - else if (smp_processor_id() == 0) - go = 1; - else - while (!go); -} - -static void -sgi_mcatest_bkpt(void) -{ -} - - -/* - * Optional test - * pos - 0 called from early init - * pos - called when cpu about to go idle (fully initialized - */ -void -sgi_mcatest(int pos) -{ - long spos, test, repeat; - int cpu, curcpu, i, n; - - //if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323; - repeat = mcatest/1000; - spos = (mcatest/100)%10; - test = mcatest % 100; - curcpu = smp_processor_id(); - - if ( mcatest == 0 || !((pos == 0 && spos == 0) || - (pos == 1 && spos == 3) || - (pos == 1 && spos == 1 && curcpu == 0) || - (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1))) - return; - -again: - if (test == 1 || test == 2 || test == 3) { - void zzzmca(int); - printk("CPU %d: About to cause unexpected MCA\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - zzzmca(test-1); - - HDELAY(100000); - } - - if (test == 4) { - long result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL, 0xc00000180e022004UL, 0xc00000180e023004UL }; - long size[] = {1,2,4,8}; - int r, i, j, k; - - for (k=0; k<2; k++) { - for (i=0; i<6; i++) { - for (j=0; j<4; j++) { - printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]); - result = -1; - r = ia64_sn_probe_io_slot (adrs[i], size[j], &result); - printk(" status %d, val 0x%lx\n", r, result); - udelay(100000); - } - } - } - - } - - if (test == 5) { - cpu = curcpu; - printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Returned from INIT\n", curcpu); - } - - if (test == 6) { - cpu = curcpu ^ 1; - printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 7) { - printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 10) { - n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000; - cpu = 0; - printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i 2 && cpu != curcpu) - platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); - - HDELAY(100000); - printk("CPU %d: Done\n", curcpu); - } - - if (test == 12) { - long adr = 0xe002200000000000UL; - n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000; - printk("CPU %d: TLB flush stress test\n", curcpu); - HDELAY(100000); - sgi_mcatest_bkpt(); - do_sync(spos); - - for (i=0; i= smp_num_cpus-2) { - printk("Parking cpu %d\n", curcpu); - local_irq_disable(); - while(1); - } else { - printk("Waiting cpu %d\n", curcpu); - HDELAY(1000000); - } - HDELAY(1000000); - inited = 1; - } - if (test == 16 || test == 17) { - unsigned long t, shift, mask; - mask = (smp_num_cpus > 16) ? 0x1f : 0xf; - shift = 25-debug1; - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t == curcpu); - do { - t = get_cycles(); - if (IS_RUNNING_ON_SIMULATOR()) - t = (t>>8); - else - t = (t>>shift); - t = t & mask; - } while (t != curcpu); - } - if(debug3) printk("CPU %d: One TLB start\n", curcpu); - if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14); - if(debug3) printk("CPU %d: One TLB flush done\n", curcpu); - } - if (test == 20) { - local_irq_disable(); - set_led_bits(smp_processor_id(), 0xff); - while(1); - } - if (test == 21) { - extern long ia64_mca_stack[]; - int i, n; - volatile long *p, *up; - p = (volatile long*)__imva(ia64_mca_stack); - up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET); - - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n"); - for (n=0, i=0; i<100; i++) - n += *(p+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n"); - for (n=0, i=0; i<100; i++) - *(p+i) = i; - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n"); - for (n=0, i=0; i<100; i++) - n += *(up+i); - if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n"); - for (n=0, i=0; i<100; i++) - ia64_fc((void*)(p+i)); - printk("ZZZ done\n"); - } - if (test == 21) { - int i; - volatile long tb, t[10]; - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - sgi_mcatest_bkpt(); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ NULL 0x%lx\n", t[i]); - } - for (i=0; i<10; i++) { - tb = debug3+ia64_get_itc(); - ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0); - t[i] = ia64_get_itc() - tb; - } - for (i=0; i<10; i++) { - printk("ZZZ DRAIN 0x%lx\n", t[i]); - } - } - if (test == 22) { - extern void machine_restart(char*); - printk("ZZZ machine_restart\n"); - machine_restart(0); - } - if (test == 23) { - printk("ZZZ ia64_pal_halt_light\n"); - ia64_pal_halt_light(); - } - if (repeat) - goto again; - -} diff -Nru a/arch/ia64/sn/kernel/probe.c b/arch/ia64/sn/kernel/probe.c --- a/arch/ia64/sn/kernel/probe.c Fri Mar 8 18:11:41 2002 +++ b/arch/ia64/sn/kernel/probe.c Fri May 16 04:18:17 2003 @@ -1,7 +1,7 @@ /* * Platform dependent support for IO probing. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c --- a/arch/ia64/sn/kernel/setup.c Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/kernel/setup.c Fri May 16 04:18:17 2003 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -69,23 +69,26 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif DEFINE_PER_CPU(struct pda_s, pda_percpu); +#define pxm_to_nasid(pxm) ((pxm)<<1) + extern void bte_init_node (nodepda_t *, cnodeid_t); extern void bte_init_cpu (void); +extern void sn_timer_init (void); +extern void (*ia64_mark_idle)(int); +void snidle(int); unsigned long sn_rtc_cycles_per_second; -unsigned long sn_rtc_usec_per_cyc; partid_t sn_partid = -1; char sn_system_serial_number_string[128]; u64 sn_partition_serial_number; +short physical_node_map[MAX_PHYSNODE_ID]; + /* * This is the address of the RRegs in the HSpace of the global * master. It is used by a hack in serial.c (serial_[in|out], @@ -94,21 +97,14 @@ * early_printk won't try to access the UART before * master_node_bedrock_address is properly calculated. */ -u64 master_node_bedrock_address = 0UL; +u64 master_node_bedrock_address; static void sn_init_pdas(char **); -extern struct irq_desc *_sn_irq_desc[]; - -#if defined(CONFIG_IA64_SGI_SN1) -extern synergy_da_t *Synergy_da_indr[]; -#endif static nodepda_t *nodepdaindr[MAX_COMPACT_NODES]; -#ifdef CONFIG_IA64_SGI_SN2 -irqpda_t *irqpdaindr[NR_CPUS]; -#endif /* CONFIG_IA64_SGI_SN2 */ +irqpda_t *irqpdaindr; /* @@ -135,29 +131,19 @@ * running in the simulator. Note that passing zeroes in DRIVE_INFO * is sufficient (the IDE driver will autodetect the drive geometry). */ +#ifdef CONFIG_IA64_GENERIC +extern char drive_info[4*16]; +#else char drive_info[4*16]; - -/** - * sn_map_nr - return the mem_map entry for a given kernel address - * @addr: kernel address to query - * - * Finds the mem_map entry for the kernel address given. Used by - * virt_to_page() (asm-ia64/page.h), among other things. - */ -unsigned long -sn_map_nr (unsigned long addr) -{ - return BANK_MAP_NR(addr); -} +#endif /** * early_sn_setup - early setup routine for SN platforms * * Sets up an initial console to aid debugging. Intended primarily - * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK - * are turned on. See start_kernel() in init/main.c. + * for bringup. See start_kernel() in init/main.c. */ -#if defined(CONFIG_IA64_EARLY_PRINTK) +#if defined(CONFIG_IA64_EARLY_PRINTK) || defined(CONFIG_IA64_SGI_SN_SIM) void __init early_sn_setup(void) @@ -195,21 +181,48 @@ } if ( IS_RUNNING_ON_SIMULATOR() ) { -#if defined(CONFIG_IA64_SGI_SN1) - master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0); -#else master_node_bedrock_address = (u64)REMOTE_HUB(get_nasid(), SH_JUNK_BUS_UART0); -#endif printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address); } } -#endif /* CONFIG_IA64_SGI_SN1 */ +#endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_IA64_MCA extern int platform_intr_list[]; #endif extern nasid_t master_nasid; +static int shub_1_1_found __initdata; + + +/* + * sn_check_for_wars + * + * Set flag for enabling shub specific wars + */ + +static inline int __init +is_shub_1_1(int nasid) +{ + unsigned long id; + int rev; + + id = REMOTE_HUB_L(nasid, SH_SHUB_ID); + rev = (id & SH_SHUB_ID_REVISION_MASK) >> SH_SHUB_ID_REVISION_SHFT; + return rev <= 2; +} + +static void __init +sn_check_for_wars(void) +{ + int cnode; + + for (cnode=0; cnode< numnodes; cnode++) + if (is_shub_1_1(cnodeid_to_nasid(cnode))) + shub_1_1_found = 1; +} + + /** * sn_setup - SN platform setup routine @@ -223,8 +236,18 @@ sn_setup(char **cmdline_p) { long status, ticks_per_sec, drift; - int i; + int pxm; int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); + extern void io_sh_swapper(int, int); + extern nasid_t get_master_baseio_nasid(void); + extern void sn_cpu_init(void); + + MAX_DMA_ADDRESS = PAGE_OFFSET + MAX_PHYS_MEMORY; + + memset(physical_node_map, -1, sizeof(physical_node_map)); + for (pxm=0; pxmthread.flags |= IA64_THREAD_FPEMU_NOPRINT; + sn_timer_init(); + + ia64_mark_idle = &snidle; } /** @@ -325,22 +327,19 @@ * Make sure that the PDA fits entirely in the same page as the * cpu_data area. */ - if ( (((unsigned long)pda & ~PAGE_MASK) + sizeof(pda_t)) > PAGE_SIZE) + if ((((unsigned long)pda & (~PAGE_MASK)) + sizeof(pda_t)) > PAGE_SIZE) panic("overflow of cpu_data page"); + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (cnode=0; cnodecnodeid_to_nasid_table[cnode] = pxm_to_nasid(nid_to_pxm_map[cnode]); + /* * Allocate & initalize the nodepda for each node. */ for (cnode=0; cnode < numnodes; cnode++) { nodepdaindr[cnode] = alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t)); memset(nodepdaindr[cnode], 0, sizeof(nodepda_t)); - -#if defined(CONFIG_IA64_SGI_SN1) - Synergy_da_indr[cnode * 2] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - Synergy_da_indr[cnode * 2 + 1] = (synergy_da_t *) alloc_bootmem_node(NODE_DATA(cnode), sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2], 0, sizeof(synergy_da_t)); - memset(Synergy_da_indr[cnode * 2 + 1], 0, sizeof(synergy_da_t)); -#endif } /* @@ -349,7 +348,7 @@ for (cnode=0; cnode < numnodes; cnode++) memcpy(nodepdaindr[cnode]->pernode_pdaindr, nodepdaindr, sizeof(nodepdaindr)); -#ifdef CONFIG_PCI + /* * Set up IO related platform-dependent nodepda fields. * The following routine actually sets up the hubinfo struct @@ -359,7 +358,6 @@ init_platform_nodepda(nodepdaindr[cnode], cnode); bte_init_node (nodepdaindr[cnode], cnode); } -#endif } /** @@ -374,7 +372,11 @@ void __init sn_cpu_init(void) { - int cpuid, cpuphyid, nasid, nodeid, slice; + int cpuid; + int cpuphyid; + int nasid; + int slice; + int cnode, i; /* * The boot cpu makes this call again after platform initialization is @@ -386,14 +388,43 @@ cpuid = smp_processor_id(); cpuphyid = ((ia64_get_lid() >> 16) & 0xffff); nasid = cpu_physical_id_to_nasid(cpuphyid); - nodeid = cpu_to_node_map[cpuphyid]; + cnode = nasid_to_cnodeid(nasid); slice = cpu_physical_id_to_slice(cpuphyid); - memset(pda, 0, sizeof(pda_t)); - pda->p_nodepda = nodepdaindr[nodeid]; + printk("CPU %d: nasid %d, slice %d, cnode %d\n", + smp_processor_id(), nasid, slice, cnode); + + memset(pda, 0, sizeof(pda)); + pda->p_nodepda = nodepdaindr[cnode]; + pda->led_address = (typeof(pda->led_address)) (LED0 + (slice<led_state = LED_ALWAYS_SET; pda->hb_count = HZ/2; pda->hb_state = 0; pda->idle_flag = 0; + pda->shub_1_1_found = shub_1_1_found; + + memset(pda->cnodeid_to_nasid_table, -1, sizeof(pda->cnodeid_to_nasid_table)); + for (i=0; icnodeid_to_nasid_table[i] = pxm_to_nasid(nid_to_pxm_map[i]); + + if (local_node_data->active_cpu_count == 1) + nodepda->node_first_cpu = cpuid; + + + + /* + * We must use different memory allocators for first cpu (bootmem + * allocator) than for the other cpus (regular allocator). + */ + if (cpuid == 0) + irqpdaindr = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t)); + + memset(irqpdaindr, 0, sizeof(irqpda_t)); + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_PCIBR_ERROR] |= SN2_IRQ_RESERVED; + irqpdaindr->irq_flags[SGI_II_ERROR] = SN2_IRQ_SHARED; + irqpdaindr->irq_flags[SGI_II_ERROR] |= SN2_IRQ_RESERVED; + pda->pio_write_status_addr = (volatile unsigned long *) LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) ); pda->mem_write_status_addr = (volatile u64 *) @@ -401,89 +432,25 @@ if (nodepda->node_first_cpu == cpuid) { int buddy_nasid; - buddy_nasid = cnodeid_to_nasid(local_nodeid == numnodes - 1 ? 0 : local_nodeid + 1); + buddy_nasid = cnodeid_to_nasid(numa_node_id() == numnodes-1 ? 0 : numa_node_id()+ 1); pda->pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL); } bte_init_cpu(); } -#ifdef II_PRTE_TLB_WAR -long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */ -#endif - -#ifdef BUS_INT_WAR - -#include -#include - -void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs); - -static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; - -#define IRQCPU(irq) ((irq)>>8) - -void -sn_add_polled_interrupt(int irq, int interval) +void snidle(int idleness) { - unsigned long flags, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - irq_list[irq_cnt].irq = irq; - irq_list[irq_cnt].interval = interval; - irq_list[irq_cnt].tick = interval; - pdacpu(IRQCPU(irq)).pda_poll_entry_count++; - spin_unlock_irqrestore(&irq_lock, flags); - - -} - -void -sn_delete_polled_interrupt(int irq) -{ - unsigned long flags, i, irq_cnt; - sn_poll_entry_t *irq_list; - - irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries; - - spin_lock_irqsave(&irq_lock, flags); - irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count; - for (i=0; iidle_flag == 0) { + set_led_bits(0, LED_CPU_ACTIVITY); } - } - spin_unlock_irqrestore(&irq_lock, flags); -} -void -sn_irq_poll(int cpu, int reason) -{ - unsigned long flags, i; - sn_poll_entry_t *irq_list; - - - ia64_handle_irq(IA64_IPI_VECTOR, 0); - - if (reason == 0) - return; - - irq_list = pda->pda_poll_entries; - - for (i=0; ipda_poll_entry_count; i++, irq_list++) { - if (--irq_list->tick <= 0) { - irq_list->tick = irq_list->interval; - local_irq_save(flags); - ia64_handle_irq(irq_to_vector(irq_list->irq), 0); - local_irq_restore(flags); - } + pda->idle_flag = 1; } -} + else { + set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); -#endif + pda->idle_flag = 0; + } +} diff -Nru a/arch/ia64/sn/kernel/sn1/Makefile b/arch/ia64/sn/kernel/sn1/Makefile --- a/arch/ia64/sn/kernel/sn1/Makefile Mon Dec 16 15:41:30 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,45 +0,0 @@ -# -# arch/ia64/sn/kernel/sn1/Makefile -# -# Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# Further, this software is distributed without any warranty that it is -# free of the rightful claim of any third person regarding infringement -# or the like. Any license provided herein, whether implied or -# otherwise, applies only to this software file. Patent licenses, if -# any, provided herein do not apply to combinations of this program with -# other software, or any other product whatsoever. -# -# You should have received a copy of the GNU General Public -# License along with this program; if not, write the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, -# Mountain View, CA 94043, or: -# -# http://www.sgi.com -# -# For further information regarding this notice, see: -# -# http://oss.sgi.com/projects/GenInfo/NoticeExplan -# - - -EXTRA_CFLAGS := -DLITTLE_ENDIAN - -.S.s: - $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -o $*.s $< -.S.o: - $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< - -O_TARGET = sn1.o - -obj-y = cache.o error.o iomv.o synergy.o sn1_smp.o diff -Nru a/arch/ia64/sn/kernel/sn1/cache.c b/arch/ia64/sn/kernel/sn1/cache.c --- a/arch/ia64/sn/kernel/sn1/cache.c Sat Mar 9 02:24:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,81 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - */ - -#include -#include -#include -#include -#include -#include - -#ifndef MB -#define MB (1024*1024) -#endif - -/* - * Lock for protecting SYN_TAG_DISABLE_WAY. - * Consider making this a per-FSB lock. - */ -static spinlock_t flush_lock = SPIN_LOCK_UNLOCKED; - -/** - * sn_flush_all_caches - flush a range of addresses from all caches (incl. L4) - * @flush_addr: identity mapped region 7 address to start flushing - * @bytes: number of bytes to flush - * - * Flush a range of addresses from all caches including L4. All addresses - * fully or partially contained within @flush_addr to @flush_addr + @bytes - * are flushed from the all caches. - */ -void -sn_flush_all_caches(long flush_addr, long bytes) -{ - ulong addr, baddr, eaddr, bitbucket; - int way, alias; - - /* - * Because of the way synergy implements "fc", this flushes the - * data from all caches on all cpus & L4's on OTHER FSBs. It also - * flushes both cpus on the local FSB. It does NOT flush it from - * the local FSB. - */ - flush_icache_range(flush_addr, flush_addr+bytes); - - /* - * Memory DIMMs are a minimum of 256MB and start on 256MB - * boundaries. Convert the start address to an address - * that is between +0MB & +128 of the same DIMM. - * Then add 8MB to skip the uncached MinState areas if the address - * is on the master node. - */ - if (bytes > SYNERGY_L4_BYTES_PER_WAY) - bytes = SYNERGY_L4_BYTES_PER_WAY; - baddr = TO_NODE(smp_physical_node_id(), PAGE_OFFSET + (flush_addr & (128*MB-1)) + 8*MB); - eaddr = (baddr+bytes+SYNERGY_BLOCK_SIZE-1) & ~(SYNERGY_BLOCK_SIZE-1); - baddr = baddr & ~(SYNERGY_BLOCK_SIZE-1); - - /* - * Now flush the local synergy. - */ - spin_lock(&flush_lock); - for(way=0; way -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/** - * snia_error_intr_handler - handle SN specific error interrupts - * @irq: error interrupt received - * @devid: device causing the interrupt - * @pt_regs: saved register state - * - * This routine is called when certain interrupts occur on SN systems. - * It will either recover from the situations that caused the interrupt - * or panic. - */ -void -snia_error_intr_handler(int irq, void *devid, struct pt_regs *pt_regs) -{ - unsigned long long intpend_val; - unsigned long long bit; - - switch (irq) { - case SGI_UART_IRQ: - /* - * This isn't really an error interrupt. We're just - * here because we have to do something with them. - * This is probably wrong, and this code will be - * removed. - */ - intpend_val = LOCAL_HUB_L(PI_INT_PEND0); - if ( (bit = ~(1L< -#include -#include -#include -#include - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = __IA64_UNCACHED_OFFSET | 0x00000FFFFC000000; - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -/** - * sn1_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN1, we wait for the PIO_WRITE_STATUS Bedrock register to clear. - */ -void -sn1_mmiob (void) -{ - (volatile unsigned long) (*pda.bedrock_rev_id); - while (!(volatile unsigned long) (*pda.pio_write_status_addr)) - udelay(5); -} diff -Nru a/arch/ia64/sn/kernel/sn1/sn1_smp.c b/arch/ia64/sn/kernel/sn1/sn1_smp.c --- a/arch/ia64/sn/kernel/sn1/sn1_smp.c Tue Feb 25 02:41:50 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,476 +0,0 @@ -/* - * SN1 Platform specific SMP Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - union { - struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - } ptc; - char pad[SMP_CACHE_BYTES]; - }; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - -/* - * The following table/struct is for remembering PTC coherency domains. It - * is also used to translate sapicid into cpuids. We don't want to start - * cpus unless we know their cache domain. - */ -#ifdef PTC_NOTYET -sn_sapicid_info_t sn_sapicid_info[NR_CPUS]; -#endif - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->ptc.start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->ptc.end; - nbits = ptcParams->ptc.nbits; - rid = ptcParams->ptc.rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->ptc.unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu= &ptcParamArray[0]) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->ptc.unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->ptc.unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->ptc.unfinished_count) == 0) { - if (atomic_read(&next->ptc.unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->ptc.unfinished_count) > 0) { - barrier(); - } - } - - params->ptc.start = start; - params->ptc.end = end; - params->ptc.nbits = nbits; - params->ptc.rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->ptc.unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* Currently we don't think global TLB purges need to be atomic. - * All CPUs get sent IPIs, so if they haven't done the purge, - * they're busy with interrupts that are at the IPI level, which is - * priority 15. We're asserting that any code at that level - * shouldn't be using user TLB entries. To change this to wait - * for all the flushes to complete, enable the following code. - */ -#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR) - /* this code is not tested */ - /* wait for the flush to complete */ - while (atomic_read(¶ms->ptc.unfinished_count) > 0) - barrier(); -#endif -} - -/** - * sn_send_IPI_phys - send an IPI to a Nasid and slice - * @physid: physical cpuid to receive the interrupt. - * @vector: command to send - * @delivery_mode: delivery mechanism - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @physid - * - * @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn_send_IPI_phys(long physid, int vector, int delivery_mode) -{ - long *p; - long nasid, slice; - - static int off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088}; - -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector) { - return; - } -#endif - - nasid = cpu_physical_id_to_nasid(physid); - slice = cpu_physical_id_to_slice(physid); - - p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]); - - mb(); - *p = (delivery_mode << 8) | (vector & 0xff); -} - - -/** - * sn1_send_IPI - send an IPI to a processor - * @cpuid: target of the IPI - * @vector: command to send - * @delivery_mode: delivery mechanism - * @redirect: redirect the IPI? - * - * Sends an IPI (interprocessor interrupt) to the processor specified by - * @cpuid. @delivery_mode can be one of the following - * - * %IA64_IPI_DM_INT - pend an interrupt - * %IA64_IPI_DM_PMI - pend a PMI - * %IA64_IPI_DM_NMI - pend an NMI - * %IA64_IPI_DM_INIT - pend an INIT interrupt - */ -void -sn1_send_IPI(int cpuid, int vector, int delivery_mode, int redirect) -{ - long physid; - - physid = cpu_physical_id(cpuid); - - sn_send_IPI_phys(physid, vector, delivery_mode); -} -#ifdef CONFIG_SMP - -#ifdef PTC_NOTYET -static void __init -process_sal_ptc_domain_info(ia64_sal_ptc_domain_info_t *di, int domain) -{ - ia64_sal_ptc_domain_proc_entry_t *pe; - int i, sapicid, cpuid; - - pe = __va(di->proc_list); - for (i=0; iproc_count; i++, pe++) { - sapicid = id_eid_to_sapicid(pe->id, pe->eid); - cpuid = cpu_logical_id(sapicid); - sn_sapicid_info[cpuid].domain = domain; - sn_sapicid_info[cpuid].sapicid = sapicid; - } -} - - -static void __init -process_sal_desc_ptc(ia64_sal_desc_ptc_t *ptc) -{ - ia64_sal_ptc_domain_info_t *di; - int i; - - di = __va(ptc->domain_info); - for (i=0; inum_domains; i++, di++) { - process_sal_ptc_domain_info(di, i); - } -} -#endif /* PTC_NOTYET */ - -/** - * init_sn1_smp_config - setup PTC domains per processor - */ -void __init -init_sn1_smp_config(void) -{ - if (!ia64_ptc_domain_info) { - printk("SMP: Can't find PTC domain info. Forcing UP mode\n"); - smp_num_cpus = 1; - return; - } - -#ifdef PTC_NOTYET - memset (sn_sapicid_info, -1, sizeof(sn_sapicid_info)); - process_sal_desc_ptc(ia64_ptc_domain_info); -#endif -} - -#else /* CONFIG_SMP */ - -void __init -init_sn1_smp_config(void) -{ - -#ifdef PTC_NOTYET - sn_sapicid_info[0].sapicid = hard_smp_processor_id(); -#endif -} - -#endif /* CONFIG_SMP */ diff -Nru a/arch/ia64/sn/kernel/sn1/synergy.c b/arch/ia64/sn/kernel/sn1/synergy.c --- a/arch/ia64/sn/kernel/sn1/synergy.c Tue Dec 3 10:07:30 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,533 +0,0 @@ -/* - * SN1 Platform specific synergy Support - * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int bit_pos_to_irq(int bit); -void setclear_mask_b(int irq, int cpuid, int set); -void setclear_mask_a(int irq, int cpuid, int set); -void * kmalloc(size_t size, int flags); - -static int synergy_perf_initialized = 0; - -void -synergy_intr_alloc(int bit, int cpuid) { - return; -} - -int -synergy_intr_connect(int bit, - int cpuid) -{ - int irq; - unsigned is_b; - - irq = bit_pos_to_irq(bit); - - is_b = (cpuid_to_slice(cpuid)) & 1; - if (is_b) { - setclear_mask_b(irq,cpuid,1); - setclear_mask_a(irq,cpuid, 0); - } else { - setclear_mask_a(irq, cpuid, 1); - setclear_mask_b(irq, cpuid, 0); - } - return 0; -} -void -setclear_mask_a(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0A; - addr = VEC_MASK0A_ADDR; - break; - case 1: - reg = VEC_MASK1A; - addr = VEC_MASK1A_ADDR; - break; - case 2: - reg = VEC_MASK2A; - addr = VEC_MASK2A_ADDR; - break; - case 3: - reg = VEC_MASK3A; - addr = VEC_MASK3A_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -void -setclear_mask_b(int irq, int cpuid, int set) -{ - int synergy; - int nasid; - int reg_num; - unsigned long mask; - unsigned long addr; - unsigned long reg; - unsigned long val; - int my_cnode, my_synergy; - int target_cnode, target_synergy; - - /* - * Perform some idiot checks .. - */ - if ( (irq < 0) || (irq > 255) || - (cpuid < 0) || (cpuid > 512) ) { - printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid); - return; - } - - target_cnode = cpuid_to_cnodeid(cpuid); - target_synergy = cpuid_to_synergy(cpuid); - my_cnode = cpuid_to_cnodeid(smp_processor_id()); - my_synergy = cpuid_to_synergy(smp_processor_id()); - - reg_num = irq / 64; - mask = 1; - mask <<= (irq % 64); - switch (reg_num) { - case 0: - reg = VEC_MASK0B; - addr = VEC_MASK0B_ADDR; - break; - case 1: - reg = VEC_MASK1B; - addr = VEC_MASK1B_ADDR; - break; - case 2: - reg = VEC_MASK2B; - addr = VEC_MASK2B_ADDR; - break; - case 3: - reg = VEC_MASK3B; - addr = VEC_MASK3B_ADDR; - break; - default: - reg = addr = 0; - break; - } - if (my_cnode == target_cnode && my_synergy == target_synergy) { - // local synergy - val = READ_LOCAL_SYNERGY_REG(addr); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - WRITE_LOCAL_SYNERGY_REG(addr, val); - val = READ_LOCAL_SYNERGY_REG(addr); - } else { /* remote synergy */ - synergy = cpuid_to_synergy(cpuid); - nasid = cpuid_to_nasid(cpuid); - val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg); - if (set) { - val |= mask; - } else { - val &= ~mask; - } - REMOTE_SYNERGY_STORE(nasid, synergy, reg, val); - } -} - -/* - * Synergy perf stats. Multiplexed via timer_interrupt. - */ - -static int -synergy_perf_append(uint64_t modesel) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int checked = 0; - int err = 0; - unsigned long flags; - - /* bit 45 is enable */ - modesel |= (1UL << 45); - - for (cnode=0; cnode < numnodes; cnode++) { - /* for each node, insert a new synergy_perf entry */ - if ((npdap = NODEPDA(cnode)) == NULL) { - printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, (void *)nodepda); - continue; - } - - if (npdap->synergy_perf_enabled) { - /* user must disable counting to append new events */ - err = -EBUSY; - break; - } - - if (!checked && npdap->synergy_perf_data != NULL) { - checked = 1; - for (p = npdap->synergy_perf_first; ;) { - if (p->modesel == modesel) - return 0; /* event already registered */ - if ((p = p->next) == npdap->synergy_perf_first) - break; - } - } - - /* XX use kmem_alloc_node() when it is implemented */ - p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL); - if ((((uint64_t)p) & 7UL) != 0) - BUG(); /* bad alignment */ - if (p == NULL) { - err = -ENOMEM; - break; - } - else { - memset(p, 0, sizeof(synergy_perf_t)); - p->modesel = modesel; - - spin_lock_irqsave(&npdap->synergy_perf_lock, flags); - if (npdap->synergy_perf_data == NULL) { - /* circular list */ - p->next = p; - npdap->synergy_perf_first = p; - npdap->synergy_perf_data = p; - } - else { - p->next = npdap->synergy_perf_data->next; - npdap->synergy_perf_data->next = p; - } - spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags); - } - } - - return err; -} - -static void -synergy_perf_set_freq(int freq) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_freq = freq; - } -} - -static void -synergy_perf_set_enable(int enable) -{ - int cnode; - nodepda_t *npdap; - - for (cnode=0; cnode < numnodes; cnode++) { - if ((npdap = NODEPDA(cnode)) != NULL) - npdap->synergy_perf_enabled = enable; - } - printk("NOTICE: synergy perf counting %sabled on all nodes\n", enable ? "en" : "dis"); -} - -static int -synergy_perf_size(nodepda_t *npdap) -{ - synergy_perf_t *p; - int n; - - if (npdap->synergy_perf_enabled == 0) { - /* no stats to return */ - return 0; - } - - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - n++; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* bytes == n pairs of {event,counter} */ - return n * 2 * sizeof(uint64_t); -} - -static int -synergy_perf_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int cnode; - nodepda_t *npdap; - synergy_perf_t *p; - int intarg; - int fsb; - uint64_t longarg; - uint64_t *stats; - int n; - devfs_handle_t d; - arbitrary_info_t info; - - if ((d = devfs_get_handle_from_inode(inode)) == NULL) - return -ENODEV; - info = hwgraph_fastinfo_get(d); - - cnode = SYNERGY_PERF_INFO_CNODE(info); - fsb = SYNERGY_PERF_INFO_FSB(info); - npdap = NODEPDA(cnode); - - switch (cmd) { - case SNDRV_GET_SYNERGY_VERSION: - /* return int, version of data structure for SNDRV_GET_SYNERGYINFO */ - intarg = 1; /* version 1 */ - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_INFOSIZE: - /* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */ - intarg = synergy_perf_size(npdap); - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_GET_SYNERGYINFO: - /* return array of event/value pairs, this node only */ - if ((intarg = synergy_perf_size(npdap)) <= 0) - return -ENODATA; - if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL) - return -ENOMEM; - spin_lock_irq(&npdap->synergy_perf_lock); - for (n=0, p = npdap->synergy_perf_first; p;) { - stats[n++] = p->modesel; - if (p->intervals > 0) - stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals; - else - stats[n++] = 0; - p = p->next; - if (p == npdap->synergy_perf_first) - break; - } - spin_unlock_irq(&npdap->synergy_perf_lock); - - if (copy_to_user((void *)arg, stats, intarg)) { - kfree(stats); - return -EFAULT; - } - - kfree(stats); - break; - - case SNDRV_SYNERGY_APPEND: - /* reads 64bit event, append synergy perf event to all nodes */ - if (copy_from_user(&longarg, (void *)arg, sizeof(longarg))) - return -EFAULT; - return synergy_perf_append(longarg); - break; - - case SNDRV_GET_SYNERGY_STATUS: - /* return int, 1 if enabled else 0 */ - intarg = npdap->synergy_perf_enabled; - if (copy_to_user((void *)arg, &intarg, sizeof(intarg))) - return -EFAULT; - break; - - case SNDRV_SYNERGY_ENABLE: - /* read int, if true enable counting else disable */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - synergy_perf_set_enable(intarg); - break; - - case SNDRV_SYNERGY_FREQ: - /* read int, set jiffies per update */ - if (copy_from_user(&intarg, (void *)arg, sizeof(intarg))) - return -EFAULT; - if (intarg < 0 || intarg >= HZ) - return -EINVAL; - synergy_perf_set_freq(intarg); - break; - - default: - printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%d\n", cmd, cnode, fsb); - return -EINVAL; - } - return(0); -} - -struct file_operations synergy_mon_fops = { - .ioctl = synergy_perf_ioctl, -}; - -void -synergy_perf_update(int cpu) -{ - nasid_t nasid; - cnodeid_t cnode; - struct nodepda_s *npdap; - - /* - * synergy_perf_initialized is set by synergy_perf_init() - * which is called last thing by sn_mp_setup(), i.e. well - * after nodepda has been initialized. - */ - if (!synergy_perf_initialized) - return; - - cnode = cpuid_to_cnodeid(cpu); - npdap = NODEPDA(cnode); - - if (npdap == NULL || cnode < 0 || cnode >= numnodes) - /* this should not happen: still in early io init */ - return; - -#if 0 - /* use this to check nodepda initialization */ - if (((uint64_t)npdap) & 0x7) { - printk("\nERROR on cpu %d : cnode=%d, npdap == %p, not aligned\n", cpu, cnode, npdap); - BUG(); - } -#endif - - if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) { - /* Not enabled, or no events to monitor */ - return; - } - - if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) { - /* don't multiplex on every timer interrupt */ - return; - } - - /* - * Read registers for last interval and increment counters. - * Hold the per-node synergy_perf_lock so concurrent readers get - * consistent values. - */ - spin_lock_irq(&npdap->synergy_perf_lock); - - nasid = cpuid_to_nasid(cpu); - npdap->synergy_active_intervals++; - npdap->synergy_perf_data->intervals++; - npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals; - - npdap->synergy_perf_data->counts[0] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A); - - npdap->synergy_perf_data->counts[1] += 0xffffffffffUL & - REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B); - - /* skip to next in circular list */ - npdap->synergy_perf_data = npdap->synergy_perf_data->next; - - spin_unlock_irq(&npdap->synergy_perf_lock); - - /* set the counter 0 selection modes for both A and B */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel); - - /* and reset the counter registers to zero */ - REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL); - REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL); -} - -void -synergy_perf_init(void) -{ - printk("synergy_perf_init(), counting is initially disabled\n"); - synergy_perf_initialized++; -} diff -Nru a/arch/ia64/sn/kernel/sn2/Makefile b/arch/ia64/sn/kernel/sn2/Makefile --- a/arch/ia64/sn/kernel/sn2/Makefile Tue Mar 18 07:58:24 2003 +++ b/arch/ia64/sn/kernel/sn2/Makefile Fri May 16 04:18:18 2003 @@ -11,4 +11,5 @@ EXTRA_CFLAGS := -DLITTLE_ENDIAN -obj-y += cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o +obj-y += cache.o io.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o \ + prominfo_proc.o timer.o diff -Nru a/arch/ia64/sn/kernel/sn2/cache.c b/arch/ia64/sn/kernel/sn2/cache.c --- a/arch/ia64/sn/kernel/sn2/cache.c Sat Mar 9 02:24:40 2002 +++ b/arch/ia64/sn/kernel/sn2/cache.c Fri May 16 04:18:19 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. * */ @@ -24,6 +24,5 @@ sn_flush_all_caches(long flush_addr, long bytes) { flush_icache_range(flush_addr, flush_addr+bytes); + mb(); } - - diff -Nru a/arch/ia64/sn/kernel/sn2/io.c b/arch/ia64/sn/kernel/sn2/io.c --- a/arch/ia64/sn/kernel/sn2/io.c Thu Mar 27 07:51:51 2003 +++ b/arch/ia64/sn/kernel/sn2/io.c Fri May 16 04:18:18 2003 @@ -9,13 +9,8 @@ * we wrap the inlines from asm/ia64/sn/sn2/io.h here. */ -#include -#include - #include -#ifdef CONFIG_IA64_GENERIC - unsigned int sn_inb (unsigned long port) { @@ -73,7 +68,7 @@ unsigned long sn_readq (void *addr) { - return __sn_readq (addr) + return __sn_readq (addr); } @@ -94,5 +89,3 @@ asm ("__sn_readw = sn_readw"); asm ("__sn_readl = sn_readl"); asm ("__sn_readq = sn_readq"); - -#endif /* CONFIG_IA64_GENERIC */ diff -Nru a/arch/ia64/sn/kernel/sn2/iomv.c b/arch/ia64/sn/kernel/sn2/iomv.c --- a/arch/ia64/sn/kernel/sn2/iomv.c Thu Mar 27 07:53:37 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,71 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = (0xc000000fcc000000 | ((unsigned long)get_nasid() << 38)); - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -EXPORT_SYMBOL(sn_io_addr); - -/** - * sn_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. - * See PV 871084 for details about the WAR about zero value. - * - */ -void -sn_mmiob (void) -{ - while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) - udelay(1); -} diff -Nru a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c Fri May 16 11:50:50 2003 @@ -0,0 +1,361 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * Module to export the system's Firmware Interface Tables, including + * PROM revision numbers, in /proc + */ +#include +#include +#include +#include +#include +#include + +/* to lookup nasids */ +#include + +MODULE_DESCRIPTION("PROM version reporting for /proc"); +MODULE_AUTHOR("Chad Talbott"); +MODULE_LICENSE("GPL"); + +#undef DEBUG_PROMINFO + +#define TRACE_PROMINFO + +#if defined(DEBUG_PROMINFO) +# define DPRINTK(x...) printk(KERN_DEBUG x) +#else +# define DPRINTK(x...) +#endif + +#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO) +# if defined(__GNUC__) +# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \ + __FILE__, __LINE__, __FUNCTION__) +# else +# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__) +# endif +#else +# define TRACE() +#endif + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +#define FIT_SIGNATURE 0x2020205f5449465ful +/* Standard Intel FIT entry types */ +#define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */ +#define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */ +/* Entries 0x02 through 0x0D reserved by Intel */ +#define FIT_ENTRY_PAL_A_PROC 0x0E /* Processor-specific PAL_A entry */ +#define FIT_ENTRY_PAL_A 0x0F /* PAL_A entry, same as... */ +#define FIT_ENTRY_PAL_A_GEN 0x0F /* ...Generic PAL_A entry */ +#define FIT_ENTRY_UNUSED 0x7F /* Unused (reserved by Intel?) */ +/* OEM-defined entries range from 0x10 to 0x7E. */ +#define FIT_ENTRY_SAL_A 0x10 /* SAL_A entry */ +#define FIT_ENTRY_SAL_B 0x11 /* SAL_B entry */ +#define FIT_ENTRY_SALRUNTIME 0x12 /* SAL runtime entry */ +#define FIT_ENTRY_EFI 0x1F /* EFI entry */ +#define FIT_ENTRY_FPSWA 0x20 /* embedded fpswa entry */ +#define FIT_ENTRY_VMLINUX 0x21 /* embedded vmlinux entry */ + +#define FIT_MAJOR_SHIFT (32 + 8) +#define FIT_MAJOR_MASK ((1 << 8) - 1) +#define FIT_MINOR_SHIFT 32 +#define FIT_MINOR_MASK ((1 << 8) - 1) + +#define FIT_MAJOR(q) \ + ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK) +#define FIT_MINOR(q) \ + ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK) + +#define FIT_TYPE_SHIFT (32 + 16) +#define FIT_TYPE_MASK ((1 << 7) - 1) + +#define FIT_TYPE(q) \ + ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK) + +#define FIT_ENTRY(type, maj, min, size) \ + ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \ + (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \ + (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \ + (size)) + +struct fit_type_map_t { + unsigned char type; + const char *name; +}; + +static const struct fit_type_map_t fit_entry_types[] = { + { FIT_ENTRY_FIT_HEADER, "FIT Header" }, + { FIT_ENTRY_PAL_A_GEN, "Generic PAL_A" }, + { FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A" }, + { FIT_ENTRY_PAL_A, "PAL_A" }, + { FIT_ENTRY_PAL_B, "PAL_B" }, + { FIT_ENTRY_SAL_A, "SAL_A" }, + { FIT_ENTRY_SAL_B, "SAL_B" }, + { FIT_ENTRY_SALRUNTIME, "SAL runtime" }, + { FIT_ENTRY_EFI, "EFI" }, + { FIT_ENTRY_VMLINUX, "Embedded Linux" }, + { FIT_ENTRY_FPSWA, "Embedded FPSWA" }, + { FIT_ENTRY_UNUSED, "Unused" }, + { 0xff, "Error" }, +}; + +static const char * +fit_type_name(unsigned char type) +{ + struct fit_type_map_t const*mapp; + + for (mapp = fit_entry_types; mapp->type != 0xff; mapp++) + if (type == mapp->type) + return mapp->name; + + if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED)) + return "OEM type"; + if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A)) + return "Reserved"; + + return "Unknown type"; +} + +/* These two routines read the FIT table directly from the FLASH PROM + * on a specific node. The PROM can only be accessed using aligned 64 + * bit reads, so we do that and then shift and mask the result to get + * at each field. + */ +static int +dump_fit_entry(char *page, unsigned long *fentry) +{ + unsigned long q1, q2; + unsigned type; + + TRACE(); + + q1 = readq(fentry); + q2 = readq(fentry + 1); + type = FIT_TYPE(q2); + return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n", + type, + fit_type_name(type), + FIT_MAJOR(q2), FIT_MINOR(q2), + q1, + /* mult by sixteen to get size in bytes */ + (unsigned)q2 * 16); +} + +/* We assume that the fit table will be small enough that we can print + * the whole thing into one page. (This is true for our default 16kB + * pages -- each entry is about 60 chars wide when printed.) I read + * somewhere that the maximum size of the FIT is 128 entries, so we're + * OK except for 4kB pages (and no one is going to do that on SN + * anyway). + */ +static int +dump_fit(char *page, unsigned long *fit) +{ + unsigned long qw; + int nentries; + int fentry; + char *p; + + TRACE(); + + DPRINTK("dumping fit from %p\n", (void *)fit); + + qw = readq(fit); + DPRINTK("FIT signature: %016lx (%.8s)\n", qw, (char *)&qw); + if (qw != FIT_SIGNATURE) + printk(KERN_WARNING "Unrecognized FIT signature"); + + qw = readq(fit + 1); + nentries = (unsigned)qw; + DPRINTK("number of fit entries: %u\n", nentries); + /* check that we won't overflow the page -- see comment above */ + BUG_ON(nentries * 60 > PAGE_SIZE); + + p = page; + for (fentry = 0; fentry < nentries; fentry++) + /* each FIT entry is two 64 bit words */ + p += dump_fit_entry(p, fit + 2 * fentry); + + return p - page; +} + +static int +dump_version(char *page, unsigned long *fit) +{ + int nentries; + int fentry; + unsigned long qw; + + TRACE(); + + nentries = (unsigned)readq(fit + 1); + BUG_ON(nentries * 60 > PAGE_SIZE); + + for (fentry = 0; fentry < nentries; fentry++) { + qw = readq(fit + 2 * fentry + 1); + if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A) + return sprintf(page, "%x.%02x\n", + FIT_MAJOR(qw), FIT_MINOR(qw)); + } + return 0; +} + +/* same as in proc_misc.c */ +static int +proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof, + int len) +{ + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int +read_version_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_version(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + return len; +} + +static int +read_fit_entry(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + + MOD_INC_USE_COUNT; + /* data holds the pointer to this node's FIT */ + len = dump_fit(page, (unsigned long *)data); + len = proc_calc_metrics(page, start, off, count, eof, len); + MOD_DEC_USE_COUNT; + + return len; +} + +/* this is a fake FIT that's used on the medusa simulator which + * doesn't usually run a complete PROM. + */ +#ifdef CONFIG_IA64_SGI_SN_SIM +static unsigned long fakefit[] = { + /* this is all we need to satisfy the code below */ + FIT_SIGNATURE, + FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2), + /* dump something arbitrary for + * /proc/sgi_prominfo/nodeX/version */ + 0xbadbeef00fa3ef17ul, + FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100) +}; +#endif + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + +#ifdef CONFIG_IA64_SGI_SN_SIM + if (IS_RUNNING_ON_SIMULATOR()) + return fakefit; +#endif + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + DPRINTK("pointer to fit at %p\n", (void *)fitp); + fit_paddr = readq(fitp); + DPRINTK("fit pointer contains %lx\n", fit_paddr); + /* snag just the node-relative offset */ + fit_paddr &= ~0ul >> (63-35); + /* the pointer to the FIT is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + fit_paddr += 0x700000000; + fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr); + DPRINTK("fit at %p\n", (void *)fit_vaddr); + return fit_vaddr; +} + +/* module entry points */ +int __init prominfo_init(void); +void __exit prominfo_exit(void); + +module_init(prominfo_init); +module_exit(prominfo_exit); + +static struct proc_dir_entry **proc_entries; +static struct proc_dir_entry *sgi_prominfo_entry; + +#define NODE_NAME_LEN 11 + +int __init +prominfo_init(void) +{ + struct proc_dir_entry **entp; + cnodeid_t cnodeid; + nasid_t nasid; + char name[NODE_NAME_LEN]; + + TRACE(); + + DPRINTK("running on cpu %d\n", smp_processor_id()); + DPRINTK("numnodes %d\n", numnodes); + + proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *), + GFP_KERNEL); + + sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + sprintf(name, "node%d", cnodeid); + *entp = proc_mkdir(name, sgi_prominfo_entry); + nasid = cnodeid_to_nasid(cnodeid); + create_proc_read_entry( + "fit", 0, *entp, read_fit_entry, + lookup_fit(nasid)); + create_proc_read_entry( + "version", 0, *entp, read_version_entry, + lookup_fit(nasid)); + } + + return 0; +} + +void __exit +prominfo_exit(void) +{ + struct proc_dir_entry **entp; + unsigned cnodeid; + char name[NODE_NAME_LEN]; + + TRACE(); + + for (cnodeid = 0, entp = proc_entries; + cnodeid < numnodes; + cnodeid++, entp++) { + remove_proc_entry("fit", *entp); + remove_proc_entry("version", *entp); + sprintf(name, "node%d", cnodeid); + remove_proc_entry(name, sgi_prominfo_entry); + } + remove_proc_entry("sgi_prominfo", NULL); + kfree(proc_entries); +} diff -Nru a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c --- a/arch/ia64/sn/kernel/sn2/sn2_smp.c Tue Feb 25 02:41:52 2003 +++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c Fri May 16 04:18:18 2003 @@ -1,7 +1,7 @@ /* * SN2 Platform specific SMP Support * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -79,284 +79,6 @@ return ws; } -#ifdef PTCG_WAR -/* - * The following structure is used to pass params thru smp_call_function - * to other cpus for flushing TLB ranges. - */ -typedef struct { - unsigned long start; - unsigned long end; - unsigned long nbits; - unsigned int rid; - atomic_t unfinished_count; - char fill[96]; -} ptc_params_t; - -#define NUMPTC 512 - -static ptc_params_t ptcParamArray[NUMPTC] __attribute__((__aligned__(128))); - -/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */ -static ptc_params_t *ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128))); -static volatile ptc_params_t *ptcParamsEmpty __cacheline_aligned; - -/*REFERENCED*/ -static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED; - -static int ptcInit = 0; -#ifdef PTCDEBUG -static int ptcParamsAllBusy = 0; /* debugging/statistics */ -static int ptcCountBacklog = 0; -static int ptcBacklog[NUMPTC+1]; -static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128))); -#endif - -/* - * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference, - * so that we get a clean compile with the ia64 patch without the - * actual SN1 specific code in arch/ia64/kernel/smp.c. - */ -extern void smp_send_flush_tlb (void) __attribute((weak)); - - -/** - * sn1_ptc_l_range - purge local translation cache - * @start: start of virtual address range - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Purges the range specified from the local processor's translation cache - * (as opposed to the translation registers). Note that more than the specified - * range *may* be cleared from the cache by some processors. - * - * This is probably not good enough, but I don't want to try to make it better - * until I get some statistics on a running system. At a minimum, we should only - * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's - * own FSB. Also, we only have to serialize per FSB, not globally. - * - * More likely, we will have to do some work to reduce the frequency of calls to - * this routine. - */ -static inline void -sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits) -{ - do { - __asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory"); - start += (1UL << nbits); - } while (start < end); - ia64_srlz_d(); -} - -/** - * sn1_received_flush_tlb - cpu tlb flush routine - * - * Flushes the TLB of a given processor. - */ -void -sn1_received_flush_tlb(void) -{ - unsigned long start, end, nbits; - unsigned int rid, saved_rid; - int cpu = smp_processor_id(); - int result; - ptc_params_t *ptcParams; - - ptcParams = ptcParamsNextByCpu[cpu*16]; - if (ptcParams == ptcParamsEmpty) - return; - - do { - start = ptcParams->start; - saved_rid = (unsigned int) ia64_get_rr(start); - end = ptcParams->end; - nbits = ptcParams->nbits; - rid = ptcParams->rid; - - if (saved_rid != rid) { - ia64_set_rr(start, (unsigned long)rid); - ia64_srlz_d(); - } - - sn1_ptc_l_range(start, end, nbits); - - if (saved_rid != rid) - ia64_set_rr(start, (unsigned long)saved_rid); - - ia64_srlz_i(); - - result = atomic_dec(&ptcParams->unfinished_count); -#ifdef PTCDEBUG - { - int i = ptcParams-&ptcParamArray[0]; - ptcParamsResults[cpu][i] = (char) result; - ptcParamsCounts[cpu][i]++; - } -#endif /* PTCDEBUG */ - - if (++ptcParams == &ptcParamArray[NUMPTC]) - ptcParams = &ptcParamArray[0]; - - } while (ptcParams != ptcParamsEmpty); - - ptcParamsNextByCpu[cpu*16] = ptcParams; -} - -/** - * sn1_global_tlb_purge - flush a translation cache range on all processors - * @start: start of virtual address range to flush - * @end: end of virtual address range - * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc)) - * - * Flushes the translation cache of all processors from @start to @end. - */ -void -sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) -{ - ptc_params_t *params; - ptc_params_t *next; - unsigned long irqflags; -#ifdef PTCDEBUG - ptc_params_t *nextnext; - int backlog = 0; -#endif - - if (smp_num_cpus == 1) { - sn1_ptc_l_range(start, end, nbits); - return; - } - - if (in_interrupt()) { - /* - * If at interrupt level and cannot get spinlock, - * then do something useful by flushing own tlbflush queue - * so as to avoid a possible deadlock. - */ - while (!spin_trylock(&ptcParamsLock)) { - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - udelay(10); /* take it easier on the bus */ - } - } else { - spin_lock(&ptcParamsLock); - } - - if (!ptcInit) { - int cpu; - ptcInit = 1; - memset(ptcParamArray, 0, sizeof(ptcParamArray)); - ptcParamsEmpty = &ptcParamArray[0]; - for (cpu=0; cpu= &ptcParamArray[0]) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - - if (backlog) { - /* check the end of the array */ - ptr = &ptcParamArray[NUMPTC]; - while (--ptr > params) { - if (atomic_read(&ptr->unfinished_count) == 0) - break; - ++backlog; - } - } - ptcBacklog[backlog]++; - } -#endif /* PTCDEBUG */ - - /* wait for the next entry to clear...should be rare */ - if (atomic_read(&next->unfinished_count) > 0) { -#ifdef PTCDEBUG - ptcParamsAllBusy++; - - if (atomic_read(&nextnext->unfinished_count) == 0) { - if (atomic_read(&next->unfinished_count) > 0) { - panic("\nnonzero next zero nextnext %lx %lx\n", - (long)next, (long)nextnext); - } - } -#endif - - /* it could be this cpu that is behind */ - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* now we know it's not this cpu, so just wait */ - while (atomic_read(&next->unfinished_count) > 0) { - barrier(); - } - } - - params->start = start; - params->end = end; - params->nbits = nbits; - params->rid = (unsigned int) ia64_get_rr(start); - atomic_set(¶ms->unfinished_count, smp_num_cpus); - - /* The atomic_set above can hit memory *after* the update - * to ptcParamsEmpty below, which opens a timing window - * that other cpus can squeeze into! - */ - mb(); - - /* everything is ready to process: - * -- global lock is held - * -- new entry + 1 is free - * -- new entry is set up - * so now: - * -- update the global next pointer - * -- unlock the global lock - * -- send IPI to notify other cpus - * -- process the data ourselves - */ - ptcParamsEmpty = next; - spin_unlock(&ptcParamsLock); - smp_send_flush_tlb(); - - local_irq_save(irqflags); - sn1_received_flush_tlb(); - local_irq_restore(irqflags); - - /* - * Since IPIs are polled event (for now), we need to wait til the - * TLB flush has started. - * wait for the flush to complete - */ - while (atomic_read(¶ms->unfinished_count) > 0) - barrier(); -} - -#endif /* PTCG_WAR */ /** @@ -372,18 +94,10 @@ void sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits) { - int cnode, mycnode, nasid; + int cnode, mycnode, nasid, flushed=0; volatile unsigned long *ptc0, *ptc1; unsigned long flags=0, data0, data1; - /* - * Special case 1 cpu & 1 node. Use local purges. - */ -#ifdef PTCG_WAR - sn1_global_tlb_purge(start, end, nbits); - return; -#endif /* PTCG_WAR */ - data0 = (1UL<>8)<pio_write_status_addr; - mycnode = local_nodeid; + mycnode = numa_node_id(); for (cnode = 0; cnode < numnodes; cnode++) { if (is_headless_node(cnode) || cnode == mycnode) @@ -482,16 +189,10 @@ void sn_send_IPI_phys(long physid, int vector, int delivery_mode) { - long nasid, slice; - long val; + long nasid, slice, val; + unsigned long flags=0; volatile long *p; -#ifdef BUS_INT_WAR - if (vector != ap_wakeup_vector && delivery_mode == IA64_IPI_DM_INT) { - return; - } -#endif - nasid = cpu_physical_id_to_nasid(physid); slice = cpu_physical_id_to_slice(physid); @@ -503,12 +204,15 @@ (0x000feeUL< +#include #ifdef CONFIG_PROC_FS #include @@ -43,7 +44,7 @@ return sprintf(page, "%d\n", sn_local_partid()); } -struct proc_dir_entry * sgi_proc_dir = NULL; +static struct proc_dir_entry * sgi_proc_dir; void register_sn_partition_id(void) { @@ -135,11 +136,60 @@ entry->write_proc = sn_force_interrupt_write_proc; } } + +extern int sn_linkstats_get(char *); +extern int sn_linkstats_reset(unsigned long); + +static int +sn_linkstats_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) { + + return sn_linkstats_get(page); +} + +static int +sn_linkstats_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char s[64]; + unsigned long msecs; + int e = count; + + if (copy_from_user(s, buffer, count < sizeof(s) ? count : sizeof(s))) + e = -EFAULT; + else { + if (sscanf(s, "%lu", &msecs) != 1 || msecs < 5) + /* at least 5 milliseconds between updates */ + e = -EINVAL; + else + sn_linkstats_reset(msecs); + } + + return e; +} + +void +register_sn_linkstats(void) { + struct proc_dir_entry *entry; + + if (!sgi_proc_dir) { + sgi_proc_dir = proc_mkdir("sgi_sn", 0); + } + entry = create_proc_entry("linkstats", 0444, sgi_proc_dir); + if (entry) { + entry->nlink = 1; + entry->data = 0; + entry->read_proc = sn_linkstats_read_proc; + entry->write_proc = sn_linkstats_write_proc; + } +} + void register_sn_procfs(void) { register_sn_partition_id(); register_sn_serial_numbers(); register_sn_force_interrupt(); + register_sn_linkstats(); } #endif /* CONFIG_PROC_FS */ diff -Nru a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/sn/kernel/sn2/timer.c Mon May 19 23:50:15 2003 @@ -0,0 +1,76 @@ +/* + * linux/arch/ia64/sn/kernel/sn2/timer.c + * + * Copyright (C) 2003 Silicon Graphics, Inc. + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger : updated for new timer-interpolation infrastructure + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +extern unsigned long sn_rtc_cycles_per_second; +static volatile unsigned long last_wall_rtc; + +static unsigned long rtc_offset; /* updated only when xtime write-lock is held! */ +static long rtc_nsecs_per_cycle; +static long rtc_per_timer_tick; + +static unsigned long +getoffset(void) +{ + return rtc_offset + (GET_RTC_COUNTER() - last_wall_rtc)*rtc_nsecs_per_cycle; +} + + +static void +update(long delta_nsec) +{ + unsigned long rtc_counter = GET_RTC_COUNTER(); + unsigned long offset = rtc_offset + (rtc_counter - last_wall_rtc)*rtc_nsecs_per_cycle; + + /* Be careful about signed/unsigned comparisons here: */ + if (delta_nsec < 0 || (unsigned long) delta_nsec < offset) + rtc_offset = offset - delta_nsec; + else + rtc_offset = 0; + last_wall_rtc = rtc_counter; +} + + +static void +reset(void) +{ + rtc_offset = 0; + last_wall_rtc = GET_RTC_COUNTER(); +} + + +static struct time_interpolator sn2_interpolator = { + .get_offset = getoffset, + .update = update, + .reset = reset +}; + +void __init +sn_timer_init(void) +{ + sn2_interpolator.frequency = sn_rtc_cycles_per_second; + sn2_interpolator.drift = -1; /* unknown */ + register_time_interpolator(&sn2_interpolator); + + rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ; + rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second; + + last_wall_rtc = GET_RTC_COUNTER(); +} diff -Nru a/arch/ia64/sn/kernel/sn_asm.S b/arch/ia64/sn/kernel/sn_asm.S --- a/arch/ia64/sn/kernel/sn_asm.S Wed Dec 4 07:11:51 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#ifdef CONFIG_IA64_SGI_AUTOTEST - -// Testing only. -// Routine will cause MCAs -// zzzmca(n) -// n=0 MCA via duplicate TLB dropin -// n=1 MCA via read of garbage address -// n=2 MCA via lfetch read of garbage address -// - -#define ITIR(key, ps) ((key<<8) | (ps<<2)) -#define TLB_PAGESIZE 28 // Use 256MB pages for now. - - .global zzzmca - .proc zzzmca -zzzmca: - alloc loc4 = ar.pfs,2,8,1,0;; - cmp.ne p6,p0=r32,r0;; - movl r2=0x2dead - movl r3=0x3dead - movl r15=0x15dead - movl r16=0x16dead - movl r31=0x31dead - movl loc0=0x34beef - movl loc1=0x35beef - movl loc2=0x36beef - movl loc3=0x37beef - movl out0=0x42beef - - movl r20=0x32feed;; - mov ar32=r20 - movl r20=0x36feed;; - mov ar36=r20 - movl r20=0x65feed;; - mov ar65=r20 - movl r20=0x66feed;; - mov ar66=r20 - -(p6) br.cond.sptk 1f - - rsm 0x2000;; - srlz.d; - mov r11 = 5 - mov r3 = ITIR(0,TLB_PAGESIZE);; - mov cr.itir = r3 - mov r10 = 0;; - itr.d dtr[r11] = r10;; - mov r11 = 6 - - itr.d dtr[r11] = r10;; - br 9f - -1: - cmp.eq p6,p7=1,r32 -#ifdef CONFIG_IA64_SGI_SN1 - movl r8=0xe00000fe00000048;; -#else - movl r8=0xe0007fb000000048;; -#endif - (p6) ld8 r9=[r8] - (p7) lfetch.fault.nt2 [r8] - ;; - mf - ;; - mf.a - ;; - srlz.d - -9: mov ar.pfs=loc4 - br.ret.sptk rp - - .endp zzzmca - -#endif diff -Nru a/arch/ia64/sn/kernel/sn_ksyms.c b/arch/ia64/sn/kernel/sn_ksyms.c --- a/arch/ia64/sn/kernel/sn_ksyms.c Tue Dec 3 10:07:31 2002 +++ b/arch/ia64/sn/kernel/sn_ksyms.c Fri May 23 03:37:31 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -16,36 +16,16 @@ #include #include -#include #include -#include -extern devfs_handle_t base_io_scsi_ctlr_vhdl[]; +#include +extern vertex_hdl_t base_io_scsi_ctlr_vhdl[]; #include extern cnodeid_t master_node_get(devfs_handle_t vhdl); #include EXPORT_SYMBOL(base_io_scsi_ctlr_vhdl); EXPORT_SYMBOL(master_node_get); - -/* - * symbols referenced by the PCIBA module - */ -#include -#include -#include -#include - -devfs_handle_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn); -EXPORT_SYMBOL(devfn_to_vertex); -EXPORT_SYMBOL(hwgraph_vertex_unref); -EXPORT_SYMBOL(pciio_config_get); -EXPORT_SYMBOL(pciio_info_slot_get); -EXPORT_SYMBOL(hwgraph_edge_add); -EXPORT_SYMBOL(pciio_info_master_get); -EXPORT_SYMBOL(pciio_info_get); - #ifdef CONFIG_IA64_SGI_SN_DEBUG EXPORT_SYMBOL(__pa_debug); EXPORT_SYMBOL(__va_debug); @@ -55,29 +35,26 @@ EXPORT_SYMBOL(sn_send_IPI_phys); /* symbols referenced by partitioning modules */ -#include +#include +EXPORT_SYMBOL(bte_copy); EXPORT_SYMBOL(bte_unaligned_copy); #include EXPORT_SYMBOL(ia64_sal); +EXPORT_SYMBOL(physical_node_map); -#ifdef CONFIG_IA64_SGI_SN2 #include EXPORT_SYMBOL(sal_lock); EXPORT_SYMBOL(sn_partid); EXPORT_SYMBOL(sn_local_partid); EXPORT_SYMBOL(sn_system_serial_number_string); EXPORT_SYMBOL(sn_partition_serial_number); -#endif + +EXPORT_SYMBOL(sn_mmiob); /* added by tduffy 04.08.01 to fix depmod issues */ #include -#ifdef BUS_INT_WAR -extern void sn_add_polled_interrupt(int, int); -extern void sn_delete_polled_interrupt(int); -EXPORT_SYMBOL(sn_add_polled_interrupt); -EXPORT_SYMBOL(sn_delete_polled_interrupt); -#endif - extern nasid_t master_nasid; EXPORT_SYMBOL(master_nasid); + +EXPORT_SYMBOL(sn_flush_all_caches); diff -Nru a/arch/ia64/sn/kernel/sv.c b/arch/ia64/sn/kernel/sv.c --- a/arch/ia64/sn/kernel/sv.c Mon Mar 31 14:29:49 2003 +++ b/arch/ia64/sn/kernel/sv.c Fri May 16 04:18:17 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff -Nru a/arch/ia64/tools/Makefile b/arch/ia64/tools/Makefile --- a/arch/ia64/tools/Makefile Fri Jan 17 19:31:11 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,51 +0,0 @@ -CFLAGS = -g -O2 -Wall $(CPPFLAGS) - -TARGET = include/asm-ia64/offsets.h - -src = $(obj) - -clean-files := print_offsets.s print_offsets offsets.h - -$(TARGET): $(obj)/offsets.h - @if ! cmp -s $(obj)/offsets.h ${TARGET}; then \ - echo -e "*** Updating ${TARGET}..."; \ - cp $(obj)/offsets.h ${TARGET}; \ - else \ - echo "*** ${TARGET} is up to date"; \ - fi - -# -# If we're cross-compiling, we use the cross-compiler to translate -# print_offsets.c into an assembly file and then awk to translate this -# file into offsets.h. This avoids having to use a simulator to -# generate this file. This is based on an idea suggested by Asit -# Mallick. If we're running natively, we can of course just build -# print_offsets and run it. --davidm -# - -ifeq ($(CROSS_COMPILE),) - -$(obj)/offsets.h: $(obj)/print_offsets - $(obj)/print_offsets > $(obj)/offsets.h - -comma := , - -$(obj)/print_offsets: $(src)/print_offsets.c FORCE - [ -r $(TARGET) ] || echo "#define IA64_TASK_SIZE 0" > $(TARGET) - $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \ - $(src)/print_offsets.c -o $@ - -FORCE: - -else - -$(obj)/offsets.h: $(obj)/print_offsets.s - $(AWK) -f $(src)/print_offsets.awk $^ > $@ - -$(obj)/print_offsets.s: $(src)/print_offsets.c - [ -r $(TARGET) ] || echo "#define IA64_TASK_SIZE 0" > $(TARGET) - $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -S $^ -o $@ - -endif - -.PHONY: all modules modules_install diff -Nru a/arch/ia64/tools/print_offsets.awk b/arch/ia64/tools/print_offsets.awk --- a/arch/ia64/tools/print_offsets.awk Tue Sep 17 23:22:09 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,72 +0,0 @@ -BEGIN { - print "#ifndef _ASM_IA64_OFFSETS_H" - print "#define _ASM_IA64_OFFSETS_H" - print "/*" - print " * DO NOT MODIFY" - print " *" - print " * This file was generated by arch/ia64/tools/print_offsets.awk." - print " *" - print " */" - print "" - print "#define CLONE_IDLETASK_BIT 12" - print "#define CLONE_SETTLS_BIT 19" -} - -# look for .tab: -# stringz "name" -# data value -# sequence - -/.*[.]size/ { - inside_table = 0 -} - -/\/\/ end/ { - inside_table = 0 -} - -/.*[.]rodata/ { - inside_table = 0 -} - -{ - if (inside_table) { - if ($1 == "//") getline; - name=$2 - getline - getline - if ($1 == "//") getline; - value=$2 - len = length(name) - name = substr(name, 2, len - 2) - len -= 2 - if (len == 0) - print "" - else { - len += 8 - if (len >= 40) { - space=" " - } else { - space="" - while (len < 40) { - len += 8 - space = space"\t" - } - } - printf("#define %s%s%lu\t/* 0x%lx */\n", name, space, value, value) - } - } -} - -/tab:/ { - inside_table = 1 -} - -/tab\#:/ { - inside_table = 1 -} - -END { - print "" - print "#endif /* _ASM_IA64_OFFSETS_H */" -} diff -Nru a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c --- a/arch/ia64/tools/print_offsets.c Sat May 10 02:28:47 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,220 +0,0 @@ -/* - * Utility to generate asm-ia64/offsets.h. - * - * Copyright (C) 1999-2003 Hewlett-Packard Co - * David Mosberger-Tang - * - * Note that this file has dual use: when building the kernel - * natively, the file is translated into a binary and executed. When - * building the kernel in a cross-development environment, this file - * gets translated into an assembly file which, in turn, is processed - * by awk to generate offsets.h. So if you make any changes to this - * file, be sure to verify that the awk procedure still works (see - * print_offsets.awk). - */ -#include - -#include - -#include -#include -#include -#include - -#include "../kernel/sigframe.h" - -#ifdef offsetof -# undef offsetof -#endif - -/* - * We _can't_ include the host's standard header file, as those are in - * potential conflict with the what the Linux kernel declares for the - * target system. - */ -extern int printf (const char *, ...); - -#define offsetof(type,field) ((char *) &((type *) 0)->field - (char *) 0) - -struct - { - const char name[256]; - unsigned long value; - } -tab[] = - { - { "IA64_TASK_SIZE", sizeof (struct task_struct) }, - { "IA64_THREAD_INFO_SIZE", sizeof (struct thread_info) }, - { "IA64_PT_REGS_SIZE", sizeof (struct pt_regs) }, - { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, - { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, - { "IA64_CPU_SIZE", sizeof (struct cpuinfo_ia64) }, - { "SIGFRAME_SIZE", sizeof (struct sigframe) }, - { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, - { "", 0 }, /* spacer */ - { "IA64_TASK_CLEAR_CHILD_TID_OFFSET",offsetof (struct task_struct, clear_child_tid) }, - { "IA64_TASK_GROUP_LEADER_OFFSET", offsetof (struct task_struct, group_leader) }, - { "IA64_TASK_PID_OFFSET", offsetof (struct task_struct, pid) }, - { "IA64_TASK_REAL_PARENT_OFFSET", offsetof (struct task_struct, real_parent) }, - { "IA64_TASK_TGID_OFFSET", offsetof (struct task_struct, tgid) }, - { "IA64_TASK_THREAD_KSP_OFFSET", offsetof (struct task_struct, thread.ksp) }, - { "IA64_TASK_THREAD_ON_USTACK_OFFSET", offsetof (struct task_struct, thread.on_ustack) }, - { "IA64_PT_REGS_CR_IPSR_OFFSET", offsetof (struct pt_regs, cr_ipsr) }, - { "IA64_PT_REGS_CR_IIP_OFFSET", offsetof (struct pt_regs, cr_iip) }, - { "IA64_PT_REGS_CR_IFS_OFFSET", offsetof (struct pt_regs, cr_ifs) }, - { "IA64_PT_REGS_AR_UNAT_OFFSET", offsetof (struct pt_regs, ar_unat) }, - { "IA64_PT_REGS_AR_PFS_OFFSET", offsetof (struct pt_regs, ar_pfs) }, - { "IA64_PT_REGS_AR_RSC_OFFSET", offsetof (struct pt_regs, ar_rsc) }, - { "IA64_PT_REGS_AR_RNAT_OFFSET", offsetof (struct pt_regs, ar_rnat) }, - { "IA64_PT_REGS_AR_BSPSTORE_OFFSET",offsetof (struct pt_regs, ar_bspstore) }, - { "IA64_PT_REGS_PR_OFFSET", offsetof (struct pt_regs, pr) }, - { "IA64_PT_REGS_B6_OFFSET", offsetof (struct pt_regs, b6) }, - { "IA64_PT_REGS_LOADRS_OFFSET", offsetof (struct pt_regs, loadrs) }, - { "IA64_PT_REGS_R1_OFFSET", offsetof (struct pt_regs, r1) }, - { "IA64_PT_REGS_R2_OFFSET", offsetof (struct pt_regs, r2) }, - { "IA64_PT_REGS_R3_OFFSET", offsetof (struct pt_regs, r3) }, - { "IA64_PT_REGS_R12_OFFSET", offsetof (struct pt_regs, r12) }, - { "IA64_PT_REGS_R13_OFFSET", offsetof (struct pt_regs, r13) }, - { "IA64_PT_REGS_R14_OFFSET", offsetof (struct pt_regs, r14) }, - { "IA64_PT_REGS_R15_OFFSET", offsetof (struct pt_regs, r15) }, - { "IA64_PT_REGS_R8_OFFSET", offsetof (struct pt_regs, r8) }, - { "IA64_PT_REGS_R9_OFFSET", offsetof (struct pt_regs, r9) }, - { "IA64_PT_REGS_R10_OFFSET", offsetof (struct pt_regs, r10) }, - { "IA64_PT_REGS_R11_OFFSET", offsetof (struct pt_regs, r11) }, - { "IA64_PT_REGS_R16_OFFSET", offsetof (struct pt_regs, r16) }, - { "IA64_PT_REGS_R17_OFFSET", offsetof (struct pt_regs, r17) }, - { "IA64_PT_REGS_R18_OFFSET", offsetof (struct pt_regs, r18) }, - { "IA64_PT_REGS_R19_OFFSET", offsetof (struct pt_regs, r19) }, - { "IA64_PT_REGS_R20_OFFSET", offsetof (struct pt_regs, r20) }, - { "IA64_PT_REGS_R21_OFFSET", offsetof (struct pt_regs, r21) }, - { "IA64_PT_REGS_R22_OFFSET", offsetof (struct pt_regs, r22) }, - { "IA64_PT_REGS_R23_OFFSET", offsetof (struct pt_regs, r23) }, - { "IA64_PT_REGS_R24_OFFSET", offsetof (struct pt_regs, r24) }, - { "IA64_PT_REGS_R25_OFFSET", offsetof (struct pt_regs, r25) }, - { "IA64_PT_REGS_R26_OFFSET", offsetof (struct pt_regs, r26) }, - { "IA64_PT_REGS_R27_OFFSET", offsetof (struct pt_regs, r27) }, - { "IA64_PT_REGS_R28_OFFSET", offsetof (struct pt_regs, r28) }, - { "IA64_PT_REGS_R29_OFFSET", offsetof (struct pt_regs, r29) }, - { "IA64_PT_REGS_R30_OFFSET", offsetof (struct pt_regs, r30) }, - { "IA64_PT_REGS_R31_OFFSET", offsetof (struct pt_regs, r31) }, - { "IA64_PT_REGS_AR_CCV_OFFSET", offsetof (struct pt_regs, ar_ccv) }, - { "IA64_PT_REGS_AR_FPSR_OFFSET", offsetof (struct pt_regs, ar_fpsr) }, - { "IA64_PT_REGS_B0_OFFSET", offsetof (struct pt_regs, b0) }, - { "IA64_PT_REGS_B7_OFFSET", offsetof (struct pt_regs, b7) }, - { "IA64_PT_REGS_F6_OFFSET", offsetof (struct pt_regs, f6) }, - { "IA64_PT_REGS_F7_OFFSET", offsetof (struct pt_regs, f7) }, - { "IA64_PT_REGS_F8_OFFSET", offsetof (struct pt_regs, f8) }, - { "IA64_PT_REGS_F9_OFFSET", offsetof (struct pt_regs, f9) }, - { "IA64_SWITCH_STACK_CALLER_UNAT_OFFSET", offsetof (struct switch_stack, caller_unat) }, - { "IA64_SWITCH_STACK_AR_FPSR_OFFSET", offsetof (struct switch_stack, ar_fpsr) }, - { "IA64_SWITCH_STACK_F2_OFFSET", offsetof (struct switch_stack, f2) }, - { "IA64_SWITCH_STACK_F3_OFFSET", offsetof (struct switch_stack, f3) }, - { "IA64_SWITCH_STACK_F4_OFFSET", offsetof (struct switch_stack, f4) }, - { "IA64_SWITCH_STACK_F5_OFFSET", offsetof (struct switch_stack, f5) }, - { "IA64_SWITCH_STACK_F10_OFFSET", offsetof (struct switch_stack, f10) }, - { "IA64_SWITCH_STACK_F11_OFFSET", offsetof (struct switch_stack, f11) }, - { "IA64_SWITCH_STACK_F12_OFFSET", offsetof (struct switch_stack, f12) }, - { "IA64_SWITCH_STACK_F13_OFFSET", offsetof (struct switch_stack, f13) }, - { "IA64_SWITCH_STACK_F14_OFFSET", offsetof (struct switch_stack, f14) }, - { "IA64_SWITCH_STACK_F15_OFFSET", offsetof (struct switch_stack, f15) }, - { "IA64_SWITCH_STACK_F16_OFFSET", offsetof (struct switch_stack, f16) }, - { "IA64_SWITCH_STACK_F17_OFFSET", offsetof (struct switch_stack, f17) }, - { "IA64_SWITCH_STACK_F18_OFFSET", offsetof (struct switch_stack, f18) }, - { "IA64_SWITCH_STACK_F19_OFFSET", offsetof (struct switch_stack, f19) }, - { "IA64_SWITCH_STACK_F20_OFFSET", offsetof (struct switch_stack, f20) }, - { "IA64_SWITCH_STACK_F21_OFFSET", offsetof (struct switch_stack, f21) }, - { "IA64_SWITCH_STACK_F22_OFFSET", offsetof (struct switch_stack, f22) }, - { "IA64_SWITCH_STACK_F23_OFFSET", offsetof (struct switch_stack, f23) }, - { "IA64_SWITCH_STACK_F24_OFFSET", offsetof (struct switch_stack, f24) }, - { "IA64_SWITCH_STACK_F25_OFFSET", offsetof (struct switch_stack, f25) }, - { "IA64_SWITCH_STACK_F26_OFFSET", offsetof (struct switch_stack, f26) }, - { "IA64_SWITCH_STACK_F27_OFFSET", offsetof (struct switch_stack, f27) }, - { "IA64_SWITCH_STACK_F28_OFFSET", offsetof (struct switch_stack, f28) }, - { "IA64_SWITCH_STACK_F29_OFFSET", offsetof (struct switch_stack, f29) }, - { "IA64_SWITCH_STACK_F30_OFFSET", offsetof (struct switch_stack, f30) }, - { "IA64_SWITCH_STACK_F31_OFFSET", offsetof (struct switch_stack, f31) }, - { "IA64_SWITCH_STACK_R4_OFFSET", offsetof (struct switch_stack, r4) }, - { "IA64_SWITCH_STACK_R5_OFFSET", offsetof (struct switch_stack, r5) }, - { "IA64_SWITCH_STACK_R6_OFFSET", offsetof (struct switch_stack, r6) }, - { "IA64_SWITCH_STACK_R7_OFFSET", offsetof (struct switch_stack, r7) }, - { "IA64_SWITCH_STACK_B0_OFFSET", offsetof (struct switch_stack, b0) }, - { "IA64_SWITCH_STACK_B1_OFFSET", offsetof (struct switch_stack, b1) }, - { "IA64_SWITCH_STACK_B2_OFFSET", offsetof (struct switch_stack, b2) }, - { "IA64_SWITCH_STACK_B3_OFFSET", offsetof (struct switch_stack, b3) }, - { "IA64_SWITCH_STACK_B4_OFFSET", offsetof (struct switch_stack, b4) }, - { "IA64_SWITCH_STACK_B5_OFFSET", offsetof (struct switch_stack, b5) }, - { "IA64_SWITCH_STACK_AR_PFS_OFFSET", offsetof (struct switch_stack, ar_pfs) }, - { "IA64_SWITCH_STACK_AR_LC_OFFSET", offsetof (struct switch_stack, ar_lc) }, - { "IA64_SWITCH_STACK_AR_UNAT_OFFSET", offsetof (struct switch_stack, ar_unat) }, - { "IA64_SWITCH_STACK_AR_RNAT_OFFSET", offsetof (struct switch_stack, ar_rnat) }, - { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET", offsetof (struct switch_stack, ar_bspstore) }, - { "IA64_SWITCH_STACK_PR_OFFSET", offsetof (struct switch_stack, pr) }, - { "IA64_SIGCONTEXT_IP_OFFSET", offsetof (struct sigcontext, sc_ip) }, - { "IA64_SIGCONTEXT_AR_BSP_OFFSET", offsetof (struct sigcontext, sc_ar_bsp) }, - { "IA64_SIGCONTEXT_AR_FPSR_OFFSET", offsetof (struct sigcontext, sc_ar_fpsr) }, - { "IA64_SIGCONTEXT_AR_RNAT_OFFSET", offsetof (struct sigcontext, sc_ar_rnat) }, - { "IA64_SIGCONTEXT_AR_UNAT_OFFSET", offsetof (struct sigcontext, sc_ar_unat) }, - { "IA64_SIGCONTEXT_B0_OFFSET", offsetof (struct sigcontext, sc_br[0]) }, - { "IA64_SIGCONTEXT_CFM_OFFSET", offsetof (struct sigcontext, sc_cfm) }, - { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, - { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, - { "IA64_SIGCONTEXT_PR_OFFSET", offsetof (struct sigcontext, sc_pr) }, - { "IA64_SIGCONTEXT_R12_OFFSET", offsetof (struct sigcontext, sc_gr[12]) }, - { "IA64_SIGCONTEXT_RBS_BASE_OFFSET",offsetof (struct sigcontext, sc_rbs_base) }, - { "IA64_SIGCONTEXT_LOADRS_OFFSET", offsetof (struct sigcontext, sc_loadrs) }, - { "IA64_SIGFRAME_ARG0_OFFSET", offsetof (struct sigframe, arg0) }, - { "IA64_SIGFRAME_ARG1_OFFSET", offsetof (struct sigframe, arg1) }, - { "IA64_SIGFRAME_ARG2_OFFSET", offsetof (struct sigframe, arg2) }, - { "IA64_SIGFRAME_HANDLER_OFFSET", offsetof (struct sigframe, handler) }, - { "IA64_SIGFRAME_SIGCONTEXT_OFFSET", offsetof (struct sigframe, sc) }, - /* for assembly files which can't include sched.h: */ - { "IA64_CLONE_VFORK", CLONE_VFORK }, - { "IA64_CLONE_VM", CLONE_VM }, - /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ - { "IA64_CPUINFO_ITM_DELTA_OFFSET", offsetof (struct cpuinfo_ia64, itm_delta) }, - { "IA64_CPUINFO_ITM_NEXT_OFFSET", offsetof (struct cpuinfo_ia64, itm_next) }, - { "IA64_CPUINFO_NSEC_PER_CYC_OFFSET", offsetof (struct cpuinfo_ia64, nsec_per_cyc) }, - { "IA64_TIMESPEC_TV_NSEC_OFFSET", offsetof (struct timespec, tv_nsec) }, - -}; - -static const char *tabs = "\t\t\t\t\t\t\t\t\t\t"; - -int -main (int argc, char **argv) -{ - const char *space; - int i, num_tabs; - size_t len; - - printf ("#ifndef _ASM_IA64_OFFSETS_H\n"); - printf ("#define _ASM_IA64_OFFSETS_H\n\n"); - - printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by " - "arch/ia64/tools/print_offsets.\n *\n */\n\n"); - - for (i = 0; i < (int) (sizeof (tab) / sizeof (tab[0])); ++i) - { - if (tab[i].name[0] == '\0') - printf ("\n"); - else - { - len = strlen (tab[i].name); - - num_tabs = (40 - len) / 8; - if (num_tabs <= 0) - space = " "; - else - space = strchr(tabs, '\0') - (40 - len) / 8; - - printf ("#define %s%s%lu\t/* 0x%lx */\n", - tab[i].name, space, tab[i].value, tab[i].value); - } - } - - printf ("\n#define CLONE_IDLETASK_BIT %ld\n", ia64_fls (CLONE_IDLETASK)); - printf ("\n#define CLONE_SETTLS_BIT %ld\n", ia64_fls (CLONE_SETTLS)); - - printf ("\n#endif /* _ASM_IA64_OFFSETS_H */\n"); - return 0; -} diff -Nru a/arch/ia64/vmlinux.lds.S b/arch/ia64/vmlinux.lds.S --- a/arch/ia64/vmlinux.lds.S Wed Jun 11 17:40:05 2003 +++ b/arch/ia64/vmlinux.lds.S Mon Jun 16 17:03:24 2003 @@ -3,8 +3,9 @@ #include #include #include +#include -#define LOAD_OFFSET PAGE_OFFSET +#define LOAD_OFFSET KERNEL_START + KERNEL_TR_PAGE_SIZE #include OUTPUT_FORMAT("elf64-ia64-little") @@ -23,22 +24,22 @@ } v = PAGE_OFFSET; /* this symbol is here to make debugging easier... */ - phys_start = _start - PAGE_OFFSET; + phys_start = _start - LOAD_OFFSET; . = KERNEL_START; _text = .; _stext = .; - .text : AT(ADDR(.text) - PAGE_OFFSET) + .text : AT(ADDR(.text) - LOAD_OFFSET) { *(.text.ivt) *(.text) } - .text2 : AT(ADDR(.text2) - PAGE_OFFSET) + .text2 : AT(ADDR(.text2) - LOAD_OFFSET) { *(.text2) } #ifdef CONFIG_SMP - .text.lock : AT(ADDR(.text.lock) - PAGE_OFFSET) + .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } #endif _etext = .; @@ -47,17 +48,24 @@ /* Exception table */ . = ALIGN(16); - __ex_table : AT(ADDR(__ex_table) - PAGE_OFFSET) + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { __start___ex_table = .; *(__ex_table) __stop___ex_table = .; } - __mckinley_e9_bundles : AT(ADDR(__mckinley_e9_bundles) - PAGE_OFFSET) + .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) + { + __start___vtop_patchlist = .; + *(.data.patch.vtop) + __end____vtop_patchlist = .; + } + + .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET) { __start___mckinley_e9_bundles = .; - *(__mckinley_e9_bundles) + *(.data.patch.mckinley_e9) __end___mckinley_e9_bundles = .; } @@ -67,7 +75,7 @@ #if defined(CONFIG_IA64_GENERIC) /* Machine Vector */ . = ALIGN(16); - .machvec : AT(ADDR(.machvec) - PAGE_OFFSET) + .machvec : AT(ADDR(.machvec) - LOAD_OFFSET) { machvec_start = .; *(.machvec) @@ -77,9 +85,9 @@ /* Unwind info & table: */ . = ALIGN(8); - .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) + .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - LOAD_OFFSET) { *(.IA_64.unwind_info*) } - .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) + .IA_64.unwind : AT(ADDR(.IA_64.unwind) - LOAD_OFFSET) { ia64_unw_start = .; *(.IA_64.unwind*) @@ -88,24 +96,24 @@ RODATA - .opd : AT(ADDR(.opd) - PAGE_OFFSET) + .opd : AT(ADDR(.opd) - LOAD_OFFSET) { *(.opd) } /* Initialization code and data: */ . = ALIGN(PAGE_SIZE); __init_begin = .; - .init.text : AT(ADDR(.init.text) - PAGE_OFFSET) + .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; *(.init.text) _einittext = .; } - .init.data : AT(ADDR(.init.data) - PAGE_OFFSET) + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } - .init.ramfs : AT(ADDR(.init.ramfs) - PAGE_OFFSET) + .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) @@ -113,19 +121,19 @@ } . = ALIGN(16); - .init.setup : AT(ADDR(.init.setup) - PAGE_OFFSET) + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { __setup_start = .; *(.init.setup) __setup_end = .; } - __param : AT(ADDR(__param) - PAGE_OFFSET) + __param : AT(ADDR(__param) - LOAD_OFFSET) { __start___param = .; *(__param) __stop___param = .; } - .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET) + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { __initcall_start = .; *(.initcall1.init) @@ -138,7 +146,7 @@ __initcall_end = .; } __con_initcall_start = .; - .con_initcall.init : AT(ADDR(.con_initcall.init) - PAGE_OFFSET) + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { *(.con_initcall.init) } __con_initcall_end = .; __security_initcall_start = .; @@ -149,24 +157,24 @@ __init_end = .; /* The initial task and kernel stack */ - .data.init_task : AT(ADDR(.data.init_task) - PAGE_OFFSET) + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { *(.data.init_task) } - .data.page_aligned : AT(ADDR(.data.page_aligned) - PAGE_OFFSET) + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { *(__special_page_section) __start_gate_section = .; - *(.text.gate) + *(.data.gate) __stop_gate_section = .; } + . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */ - . = ALIGN(SMP_CACHE_BYTES); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - PAGE_OFFSET) + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { *(.data.cacheline_aligned) } /* Per-cpu data: */ . = ALIGN(PERCPU_PAGE_SIZE); __phys_per_cpu_start = .; - .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - PAGE_OFFSET) + .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET) { __per_cpu_start = .; *(.data.percpu) @@ -174,24 +182,24 @@ } . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */ - .data : AT(ADDR(.data) - PAGE_OFFSET) + .data : AT(ADDR(.data) - LOAD_OFFSET) { *(.data) *(.gnu.linkonce.d*) CONSTRUCTORS } . = ALIGN(16); __gp = . + 0x200000; /* gp must be 16-byte aligned for exc. table */ - .got : AT(ADDR(.got) - PAGE_OFFSET) + .got : AT(ADDR(.got) - LOAD_OFFSET) { *(.got.plt) *(.got) } /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ - .sdata : AT(ADDR(.sdata) - PAGE_OFFSET) + .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) { *(.sdata) } _edata = .; _bss = .; - .sbss : AT(ADDR(.sbss) - PAGE_OFFSET) + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { *(.sbss) *(.scommon) } - .bss : AT(ADDR(.bss) - PAGE_OFFSET) + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss) *(COMMON) } _end = .; diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig --- a/arch/m68k/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/m68k/Kconfig Thu Jun 19 10:23:30 2003 @@ -376,81 +376,7 @@ endchoice -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config ZORRO bool "Amiga Zorro (AutoConfig) bus support" @@ -647,6 +573,8 @@ endmenu +source "drivers/base/Kconfig" + source "drivers/mtd/Kconfig" source "drivers/block/Kconfig" @@ -680,417 +608,7 @@ module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CD-ROM)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT for - SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config ST_EXTRA_DEVS - int "Maximum number of SCSI tapes that can be loaded as modules" - depends on CHR_DEV_ST - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional tapes that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config A3000_SCSI - tristate "A3000 WD33C93A support" - depends on AMIGA && SCSI - help - If you have an Amiga 3000 and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. This driver is - also available as a module ( = code which can be inserted in and - removed from the running kernel whenever you want). The module is - called wd33c93. If you want to compile it as a module, say M here - and read . - -config A4000T_SCSI - bool "A4000T SCSI support (EXPERIMENTAL)" - depends on AMIGA && EXPERIMENTAL - help - Support for the NCR53C710 SCSI controller on the Amiga 4000T. - -config A2091_SCSI - tristate "A2091 WD33C93A support" - depends on ZORRO && SCSI - help - If you have a Commodore A2091 SCSI controller, say Y. Otherwise, - say N. This driver is also available as a module ( = code which can - be inserted in and removed from the running kernel whenever you - want). The module is called wd33c93. If you want to compile it as - a module, say M here and read . - -config GVP11_SCSI - tristate "GVP Series II WD33C93A support" - depends on ZORRO && SCSI - ---help--- - If you have a Great Valley Products Series II SCSI controller, - answer Y. Also say Y if you have a later model of GVP SCSI - controller (such as the GVP A4008 or a Combo board). Otherwise, - answer N. This driver does NOT work for the T-Rex series of - accelerators from TekMagic and GVP-M. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). The module will be called gvp11. If you want to compile it - as a module, say M here and read . - -config CYBERSTORM_SCSI - tristate "CyberStorm SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with an original (MkI) Phase5 Cyberstorm - accelerator board and the optional Cyberstorm SCSI controller, - answer Y. Otherwise, say N. - -config CYBERSTORMII_SCSI - tristate "CyberStorm Mk II SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board - and the optional Cyberstorm SCSI controller, say Y. Otherwise, - answer N. - -config BLZ2060_SCSI - tristate "Blizzard 2060 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga with a Phase5 Blizzard 2060 accelerator board - and want to use the onboard SCSI controller, say Y. Otherwise, - answer N. - -config BLZ1230_SCSI - tristate "Blizzard 1230IV/1260 SCSI support" - depends on ZORRO && SCSI - help - If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard - 1260 accelerator, and the optional SCSI module, say Y. Otherwise, - say N. - -config FASTLANE_SCSI - tristate "Fastlane SCSI support" - depends on ZORRO && SCSI - help - If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use - one in the near future, say Y to this question. Otherwise, say N. - -config A4091_SCSI - bool "A4091 SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller - (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade - plan at the time the Amiga business was sold to DKB. - -config WARPENGINE_SCSI - bool "WarpEngine SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - Support for MacroSystem Development's WarpEngine Amiga SCSI-2 - controller. Info at - . - -config BLZ603EPLUS_SCSI - bool "Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL - help - If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ - accelerator, say Y. Otherwise, say N. - -config OKTAGON_SCSI - tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL && SCSI - help - If you have the BSC Oktagon SCSI disk controller for the Amiga, say - Y to this question. If you're in doubt about whether you have one, - see the picture at - . - -# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI -# bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI -config ATARI_SCSI - tristate "Atari native SCSI support" - depends on ATARI && SCSI - ---help--- - If you have an Atari with built-in NCR5380 SCSI controller (TT, - Falcon, ...) say Y to get it supported. Of course also, if you have - a compatible SCSI controller (e.g. for Medusa). This driver is also - available as a module ( = code which can be inserted in and removed - from the running kernel whenever you want). The module is called - atari_scsi. If you want to compile it as a module, say M here and - read . This driver supports both - styles of NCR integration into the system: the TT style (separate - DMA), and the Falcon style (via ST-DMA, replacing ACSI). It does - NOT support other schemes, like in the Hades (without DMA). - -config ATARI_SCSI_TOSHIBA_DELAY - bool "Long delays for Toshiba CD-ROMs" - depends on ATARI_SCSI - help - This option increases the delay after a SCSI arbitration to - accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to - use a Toshiba CD-ROM drive; otherwise, the option is not needed and - would impact performance a bit, so say N. - -config ATARI_SCSI_RESET_BOOT - bool "Reset SCSI-devices at boottime" - depends on ATARI_SCSI - help - Reset the devices on your Atari whenever it boots. This makes the - boot process fractionally longer but may assist recovery from errors - that leave the devices with SCSI operations partway completed. - -config TT_DMA_EMUL - bool "Hades SCSI DMA emulator" - depends on ATARI_SCSI && HADES - help - This option enables code which emulates the TT SCSI DMA chip on the - Hades. This increases the SCSI transfer rates at least ten times - compared to PIO transfers. - -config MAC_SCSI - bool "Macintosh NCR5380 SCSI" - depends on MAC - help - This is the NCR 5380 SCSI controller included on most of the 68030 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - -config SCSI_MAC_ESP - tristate "Macintosh NCR53c9[46] SCSI" - depends on MAC && SCSI - help - This is the NCR 53c9x SCSI controller found on most of the 68040 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called mac_esp. If you want to compile it as - a module, say M here and read . - -# dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI -config MVME147_SCSI - bool "WD33C93 SCSI driver for MVME147" - depends on MVME147 - help - Support for the on-board SCSI controller on the Motorola MVME147 - single-board computer. - -config MVME16x_SCSI - bool "NCR53C710 SCSI driver for MVME16x" - depends on MVME16x - help - The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config BVME6000_SCSI - bool "NCR53C710 SCSI driver for BVME6000" - depends on BVME6000 - help - The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config SUN3_SCSI - tristate "Sun3 NCR5380 SCSI" - depends on SUN3 && SCSI - help - This option will enable support for the OBIO (onboard io) NCR5380 - SCSI controller found in the Sun 3/50 and 3/60, as well as for - "Sun3" type VME scsi controllers also based on the NCR5380. - General Linux information on the Sun 3 series (now discontinued) - is at . - -config SUN3X_ESP - bool "Sun3x ESP SCSI" - depends on SUN3X - help - The ESP was an on-board SCSI controller used on Sun 3/80 - machines. Say Y here to compile in support for it. - -endmenu +source "drivers/scsi/Kconfig" endmenu diff -Nru a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig --- a/arch/m68knommu/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/m68knommu/Kconfig Thu Jun 19 10:23:30 2003 @@ -501,16 +501,7 @@ config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. - -config BINFMT_ZFLAT - bool " Enable ZFLAT support" - depends on BINFMT_FLAT - help - Supoprt FLAT format compressed binaries +source "fs/Kconfig.binfmt" endmenu @@ -523,6 +514,8 @@ endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/mips/Kconfig b/arch/mips/Kconfig --- a/arch/mips/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/mips/Kconfig Thu Jun 19 10:23:30 2003 @@ -702,82 +702,7 @@ bool "ARC console support" depends on ARC32 -config BINFMT_AOUT - bool - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - bool - default y - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" source "drivers/pci/Kconfig" @@ -818,6 +743,8 @@ if ISA source "drivers/pnp/Kconfig" endif + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/mips64/Kconfig b/arch/mips64/Kconfig --- a/arch/mips64/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/mips64/Kconfig Thu Jun 19 10:23:30 2003 @@ -335,34 +335,7 @@ bool "ARC console support" depends on ARC32 -config BINFMT_ELF - tristate "Kernel support for 64-bit ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. +source "fs/Kconfig.binfmt" config MIPS32_COMPAT bool "Kernel support for Linux/MIPS 32-bit binary compatibility" @@ -378,40 +351,17 @@ config BINFMT_ELF32 bool - depends on MIPS32_COMPAT + depends on BINFMT_ELF && MIPS32_COMPAT default y help This allows you to run 32-bit Linux/ELF binaries on your Ultra. Everybody wants this; say Y. -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. - endmenu source "drivers/pci/Kconfig" + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/parisc/Kconfig b/arch/parisc/Kconfig --- a/arch/parisc/Kconfig Sun May 11 22:49:49 2003 +++ b/arch/parisc/Kconfig Thu Jun 19 10:23:30 2003 @@ -166,68 +166,11 @@ depends on PROC_FS default y -config BINFMT_SOM - tristate "Kernel support for SOM binaries" - depends on HPUX - help - SOM is a binary executable format inherited from HP/UX. Say Y here - to be able to load and execute SOM binaries directly. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu + +source "drivers/base/Kconfig" # source "drivers/mtd/Kconfig" diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/ppc/Kconfig Thu Jun 19 10:23:30 2003 @@ -808,42 +808,11 @@ "-g" option to preserve debugging information. It is mainly used for examining kernel data structures on the live kernel. -config BINFMT_ELF - bool - default y - help - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. - config KERNEL_ELF bool default y -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" source "drivers/pci/Kconfig" @@ -1193,6 +1162,8 @@ bool "Pinned Kernel TLBs (860 ONLY)" depends on ADVANCED_OPTIONS && 8xx endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig --- a/arch/ppc64/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/ppc64/Kconfig Thu Jun 19 10:23:30 2003 @@ -191,37 +191,7 @@ "-g" option to preserve debugging information. It is mainly used for examining kernel data structures on the live kernel. -config BINFMT_ELF - bool "Kernel support for 64-bit ELF binaries" - help - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" source "drivers/pci/Kconfig" @@ -270,6 +240,8 @@ most cases you will need to specify the root device here. endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig --- a/arch/s390/Kconfig Sun Apr 20 12:56:51 2003 +++ b/arch/s390/Kconfig Thu Jun 19 10:23:30 2003 @@ -192,78 +192,8 @@ config KCORE_ELF bool default y - ---help--- - If you enabled support for /proc file system then the file - /proc/kcore will contain the kernel core image. This can be used - in gdb: - - $ cd /usr/src/linux ; gdb vmlinux /proc/kcore - - You have two choices here: ELF and A.OUT. Selecting ELF will make - /proc/kcore appear in ELF core format as defined by the Executable - and Linking Format specification. Selecting A.OUT will choose the - old "a.out" format which may be necessary for some old versions - of binutils or on some architectures. - - This is especially useful if you have compiled the kernel with the - "-g" option to preserve debugging information. It is mainly used - for examining kernel data structures on the live kernel so if you - don't understand what this means or are not a kernel hacker, just - leave it at its default value ELF. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. + +source "fs/Kconfig.binfmt" config PROCESS_DEBUG bool "Show crashed user process info" @@ -298,6 +228,8 @@ config PCMCIA bool default n + +source "drivers/base/Kconfig" menu "SCSI support" diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig --- a/arch/sh/Kconfig Sat Jun 14 17:43:31 2003 +++ b/arch/sh/Kconfig Thu Jun 19 10:23:30 2003 @@ -763,64 +763,11 @@ endchoice -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_FLAT - tristate "Kernel support for FLAT binaries" - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig --- a/arch/sparc/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/sparc/Kconfig Thu Jun 19 10:23:30 2003 @@ -277,81 +277,7 @@ don't understand what this means or are not a kernel hacker, just leave it at its default value ELF. -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - ---help--- - A.out (Assembler.OUTput) is a set of formats for libraries and - executables used in the earliest versions of UNIX. Linux used the - a.out formats QMAGIC and ZMAGIC until they were replaced with the - ELF format. - - As more and more programs are converted to ELF, the use for a.out - will gradually diminish. If you disable this option it will reduce - your kernel by one page. This is not much and by itself does not - warrant removing support. However its removal is a good idea if you - wish to ensure that absolutely none of your programs will use this - older executable format. If you don't know what to answer at this - point then answer Y. If someone told you "You need a kernel with - QMAGIC support" then you'll have to say Y here. You may answer M to - compile a.out support as a module and later load the module when you - want to use a program or library in a.out format. The module will be - called binfmt_aout. Saying M or N here is dangerous though, - because some crucial programs on your system might still be in A.OUT - format. - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config SUNOS_EMUL bool "SunOS binary emulation" @@ -393,6 +319,8 @@ endmenu +source "drivers/base/Kconfig" + source "drivers/video/Kconfig" source "drivers/mtd/Kconfig" @@ -576,232 +504,7 @@ module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CDrom)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives can not be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage - and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives - as well. Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called osst. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SCSI - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers. - - This support is also available as a module called esp ( = code - which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -config SCSI_QLOGICPTI - tristate "PTI Qlogic,ISP Driver" - depends on SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - This support is also available as a module called qlogicpti ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -endmenu +source "drivers/scsi/Kconfig" endmenu diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c --- a/arch/sparc/kernel/time.c Sat Jun 14 16:16:07 2003 +++ b/arch/sparc/kernel/time.c Tue Jun 17 15:46:44 2003 @@ -408,9 +408,9 @@ mon = MSTK_REG_MONTH(mregs); year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; mregs->creg &= ~MSTK_CREG_READ; spin_unlock_irq(&mostek_lock); #ifdef CONFIG_SUN4 @@ -441,9 +441,9 @@ intersil_start(iregs); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec); } #endif diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig --- a/arch/sparc64/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/sparc64/Kconfig Thu Jun 19 10:23:30 2003 @@ -415,59 +415,7 @@ If you want to run SunOS binaries (see SunOS binary emulation below) or other a.out binaries, say Y. If unsure, say N. -config BINFMT_ELF - tristate "Kernel support for 64-bit ELF binaries" - ---help--- - ELF (Executable and Linkable Format) is a format for libraries and - executables used across different architectures and operating - systems. Saying Y here will enable your kernel to run ELF binaries - and enlarge it by about 13 KB. ELF support under Linux has now all - but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) - because it is portable (this does *not* mean that you will be able - to run executables from different architectures or operating systems - however) and makes building run-time libraries very easy. Many new - executables are distributed solely in ELF format. You definitely - want to say Y here. - - Information about ELF is contained in the ELF HOWTO available from - . - - If you find that after upgrading from Linux kernel 1.2 and saying Y - here, you still can't run any ELF binaries (they just crash), then - you'll have to install the newest ELF runtime libraries, including - ld.so (check the file for location and - latest version). - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called binfmt_elf. Saying M or N here is dangerous because - some crucial programs on your system might be in ELF format. - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. It's also useful if you often run DOS executables under - the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from - ). Once you have - registered such a binary class with the kernel, you can start one of - those programs simply by typing in its name at a shell prompt; Linux - will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config SUNOS_EMUL bool "SunOS binary emulation" @@ -573,6 +521,8 @@ endmenu +source "drivers/base/Kconfig" + source "drivers/video/Kconfig" source "drivers/serial/Kconfig" @@ -748,642 +698,7 @@ module if your root file system (the one containing the directory /) is located on a SCSI device. -comment "SCSI support type (disk, tape, CDrom)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use a SCSI hard disk or the SCSI or parallel port - version of the IOMEGA ZIP drive under Linux, say Y and read the - SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sd_mod. If you want to compile it as a - module, say M here and read and - . Do not compile this driver as a - module if your root file system (the one containing the directory /) - is located on a SCSI disk. In this case, do not compile the driver - for your SCSI host adapter (below) as a module either. - -config SD_EXTRA_DEVS - int "Maximum number of SCSI disks that can be loaded as modules" - depends on BLK_DEV_SD - default "40" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional disks that can be loaded after the - first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called st. If you want to compile it as a - module, say M here and read and - . - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives can not be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage - and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives - as well. Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called osst. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a SCSI CD-ROM under Linux, say Y and read the - SCSI-HOWTO and the CD-ROM-HOWTO at - . Also make sure to say Y - or M to "ISO 9660 CD-ROM file system support" later. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called sr_mod. If you want to compile it as a - module, say M here and read and - . - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config SR_EXTRA_DEVS - int "Maximum number of CDROM devices that can be loaded as modules" - depends on BLK_DEV_SR - default "2" - ---help--- - This controls the amount of additional space allocated in tables for - drivers that are loaded as modules after the kernel is booted. In - the event that the SCSI core itself was loaded as a module, this - value is the number of additional CD-ROMs that can be loaded after - the first host driver is loaded. - - Admittedly this isn't pretty, but there are tons of race conditions - involved with resizing the internal arrays on the fly. Someday this - flag will go away, and everything will work automatically. - - If you don't understand what's going on, go with the default. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called sg. - If unsure, say N. - -comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs" - depends on SCSI - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - If you have a SCSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, and only one LUN is detected, you - can say Y here to force the SCSI driver to probe for multiple LUNs. - A SCSI device with multiple LUNs acts logically like multiple SCSI - devices. The vast majority of SCSI devices have only one LUN, and - so most people can say N here and should in fact do so, because it - is safer. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo "scsi log token [level]" > /proc/scsi/scsi - - at boot time after the /proc file system has been mounted. - - There are a number of things that can be used for 'token' (you can - find them in the source: ), and this - allows you to select the types of information you want, and the - level allows you to select the level of verbosity. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - - -menu "SCSI low-level drivers" - depends on SCSI!=n - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SCSI - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers. - - This support is also available as a module called esp ( = code - which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - -config SCSI_QLOGICPTI - tristate "PTI Qlogic, ISP Driver" - depends on SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - This support is also available as a module called qlogicpti ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - - -choice - prompt "Adaptec AIC7xxx support" - optional - depends on SCSI && PCI - -source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" - -config SCSI_AIC7XXX_OLD - tristate "Old driver" - ---help--- - WARNING This driver is an older aic7xxx driver and is no longer - under active development. Adaptec, Inc. is writing a new driver to - take the place of this one, and it is recommended that whenever - possible, people should use the new Adaptec written driver instead - of this one. This driver will eventually be phased out entirely. - - This is support for the various aic7xxx based Adaptec SCSI - controllers. These include the 274x EISA cards; 284x VLB cards; - 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and - motherboard based SCSI controllers from Adaptec. It does not support - the AAA-13x RAID controllers from Adaptec, nor will it likely ever - support them. It does not support the 2920 cards from Adaptec that - use the Future Domain SCSI controller chip. For those cards, you - need the "Future Domain 16xx SCSI support" driver. - - In general, if the controller is based on an Adaptec SCSI controller - chip from the aic777x series or the aic78xx series, this driver - should work. The only exception is the 7810 which is specifically - not supported (that's the RAID controller chip on the AAA-13x - cards). - - Note that the AHA2920 SCSI host adapter is *not* supported by this - driver; choose "Future Domain 16xx SCSI support" instead if you have - one of those. - - Information on the configuration options for this controller can be - found by checking the help file for each of the available - configuration options. You should read - at a minimum before - contacting the maintainer with any questions. The SCSI-HOWTO, - available from , can also - be of great help. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The module - will be called aic7xxx_old. - -config AIC7XXX_OLD_TCQ_ON_BY_DEFAULT - bool "Enable Tagged Command Queueing (TCQ) by default" - depends on SCSI_AIC7XXX_OLD - ---help--- - This option causes the aic7xxx driver to attempt to use Tagged - Command Queueing (TCQ) on all devices that claim to support it. - - TCQ is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. Because the device is - intelligent, it can optimize its operations (like head positioning) - based on its own request queue. Not all devices implement this - correctly. - - If you say Y here, you can still turn off TCQ on troublesome devices - with the use of the tag_info boot parameter. See the file - for more information on that and - other aic7xxx setup commands. If this option is turned off, you may - still enable TCQ on known good devices by use of the tag_info boot - parameter. - - If you are unsure about your devices then it is safest to say N - here. - - However, TCQ can increase performance on some hard drives by as much - as 50% or more, so it is recommended that if you say N here, you - should at least read the file so - you will know how to enable this option manually should your drives - prove to be safe in regards to TCQ. - - Conversely, certain drives are known to lock up or cause bus resets - when TCQ is enabled on them. If you have a Western Digital - Enterprise SCSI drive for instance, then don't even bother to enable - TCQ on it as the drive will become unreliable, and it will actually - reduce performance. - -config AIC7XXX_OLD_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC7XXX_OLD - default "8" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - Reasonable figures are in the range of 8 to 24 commands per device, - but depending on hardware could be increased or decreased from that - figure. If the number is too high for any particular device, the - driver will automatically compensate usually after only 10 minutes - of uptime. It will not hinder performance if some of your devices - eventually have their command depth reduced, but is a waste of - memory if all of your devices end up reducing this number down to a - more reasonable figure. - - NOTE: Certain very broken drives are known to lock up when given - more commands than they like to deal with. Quantum Fireball drives - are the most common in this category. For the Quantum Fireball - drives it is suggested to use no more than 8 commands per device. - - Default: 8 - -config AIC7XXX_OLD_PROC_STATS - bool "Collect statistics to report in /proc" - depends on SCSI_AIC7XXX_OLD - ---help--- - This option tells the driver to keep track of how many commands have - been sent to each particular device and report that information to - the user via the /proc/scsi/aic7xxx/n file, where n is the number of - the aic7xxx controller you want the information on. This adds a - small amount of overhead to each and every SCSI command the aic7xxx - driver handles, so if you aren't really interested in this - information, it is best to leave it disabled. This will only work if - you also say Y to "/proc file system support", below. - - If unsure, say N. - -endchoice - -config SCSI_SYM53C8XX_2 - tristate "SYM53C8XX Version 2 SCSI support" - depends on PCI && SCSI - ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers. - - If your system has problems using this new major version of the - SYM53C8XX driver, you may switch back to driver version 1. - - Please read for more - information. - -config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - int "DMA addressing mode" - depends on SCSI_SYM53C8XX_2 - default "1" - ---help--- - This option only applies to PCI-SCSI chip that are PCI DAC capable - (875A, 895A, 896, 1010-33, 1010-66, 1000). - - When set to 0, only PCI 32 bit DMA addressing (SAC) will be performed. - When set to 1, 40 bit DMA addressing (with upper 24 bits of address - set to zero) is supported. The addressable range is here 1 TB. - When set to 2, full 64 bits of address for DMA are supported, but only - 16 segments of 4 GB can be addressed. The addressable range is so - limited to 64 GB. - - The safest value is 0 (32 bit DMA addressing) that is guessed to still - fit most of real machines. - - The preferred value 1 (40 bit DMA addressing) should make happy - properly engineered PCI DAC capable host bridges. You may configure - this option for Intel platforms with more than 4 GB of memory. - - The still experimental value 2 (64 bit DMA addressing with 16 x 4GB - segments limitation) can be used on systems that require PCI address - bits past bit 39 to be set for the addressing of memory using PCI - DAC cycles. - -config SCSI_SYM53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on SCSI_SYM53C8XX_2 - default "16" - help - This is the default value of the command queue depth the driver will - announce to the generic SCSI layer for devices that support tagged - command queueing. This value can be changed from the boot command line. - This is a soft limit that cannot exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. - -config SCSI_SYM53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_SYM53C8XX_2 - default "64" - help - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The driver supports up to 256 queued commands per device. - This value is used as a compiled-in hard limit. - -config SCSI_SYM53C8XX_IOMAPPED - bool "use normal IO" - depends on SCSI_SYM53C8XX_2 - help - If you say Y here, the driver will preferently use normal IO rather than - memory mapped IO. - -config SCSI_NCR53C8XX - tristate "NCR53C8XX SCSI support" - depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI - ---help--- - This is the BSD ncr driver adapted to Linux for the NCR53C8XX family - of PCI-SCSI controllers. This driver supports parity checking, - tagged command queuing and fast synchronous data transfers up to 80 - MB/s with wide FAST-40 LVD devices and controllers. - - Recent versions of the 53C8XX chips are better supported by the - option "SYM53C8XX SCSI support", below. - - Note: there is yet another driver for the 53c8xx family of - controllers ("NCR53c7,8xx SCSI support" above). If you want to use - them both, you need to say M to both and build them as modules, but - only one may be active at a time. If you have a 53c8xx board, you - probably do not want to use the "NCR53c7,8xx SCSI support". - - Please read for more - information. - -config SCSI_SYM53C8XX - tristate "SYM53C8XX SCSI support" - depends on PCI && SCSI_SYM53C8XX_2!=y && SCSI - ---help--- - This driver supports all the features of recent 53C8XX chips (used - in PCI SCSI controllers), notably the hardware phase mismatch - feature of the SYM53C896. - - Older versions of the 53C8XX chips are not supported by this - driver. If your system uses either a 810 rev. < 16, a 815, or a 825 - rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX - driver ("NCR53C8XX SCSI support" above) or configure both the - NCR53C8XX and this SYM53C8XX drivers either as module or linked to - the kernel image. - - When both drivers are linked into the kernel, the SYM53C8XX driver - is called first at initialization and you can use the 'excl=ioaddr' - driver boot option to exclude attachment of adapters by the - SYM53C8XX driver. For example, entering - 'sym53c8xx=excl:0xb400,excl=0xc000' at the lilo prompt prevents - adapters at io address 0xb400 and 0xc000 from being attached by the - SYM53C8XX driver, thus allowing the NCR53C8XX driver to attach them. - The 'excl' option is also supported by the NCR53C8XX driver. - - Please read for more - information. - -config SCSI_NCR53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "8" - ---help--- - "Tagged command queuing" is a feature of SCSI-2 which improves - performance: the host adapter can send several SCSI commands to a - device's queue even if previous commands haven't finished yet. - Because the device is intelligent, it can optimize its operations - (like head positioning) based on its own request queue. Some SCSI - devices don't implement this properly; if you want to disable this - feature, enter 0 or 1 here (it doesn't matter which). - - The default value is 8 and should be supported by most hard disks. - This value can be overridden from the boot command line using the - 'tags' option as follows (example): - 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to - 4, set queue depth to 16 for target 2 and target 3 on controller 0 - and set queue depth to 10 for target 0 / lun 2 on controller 1. - - The normal answer therefore is to go with the default 8 and to use - a boot command line option for devices that need to use a different - command queue depth. - - There is no safe option other than using good SCSI devices. - -config SCSI_NCR53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "32" - ---help--- - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. - Modern hard disks are able to support 64 tags and even more, but - do not seem to be faster when more than 32 tags are being used. - - So, the normal answer here is to go with the default value 32 unless - you are using very large hard disks with large cache (>= 1 MB) that - are able to take advantage of more than 32 tagged commands. - - There is no safe option and the default answer is recommended. - -config SCSI_NCR53C8XX_SYNC - int "synchronous transfers frequency in MHz" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - default "10" - ---help--- - The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers - are respectively the maximum data transfer rates in mega-transfers - per second for each class. For example, a FAST-20 Wide 16 device is - able to transfer data at 20 million 16 bit packets per second for a - total rate of 40 MB/s. - - You may specify 0 if you want to only use asynchronous data - transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. - Note that 80 should normally be ok since the driver decreases the - value automatically according to the controller's capabilities. - - Your answer to this question is ignored for controllers with NVRAM, - since the driver will get this information from the user set-up. It - also can be overridden using a boot setup option, as follows - (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate - for FAST-20 synchronous data transfer (20 mega-transfers per - second). - - The normal answer therefore is not to go with the default but to - select the maximum value 80 allowing the driver to use the maximum - value supported by each controller. If this causes problems with - your SCSI devices, you should come back and decrease the value. - - There is no safe option other than using good cabling, right - terminations and SCSI conformant devices. - -config SCSI_NCR53C8XX_PROFILE - bool "enable profiling" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) - help - This option allows you to enable profiling information gathering. - These statistics are not very accurate due to the low frequency - of the kernel clock (100 Hz on i386) and have performance impact - on systems that use very fast devices. - - The normal answer therefore is N. - -config SCSI_NCR53C8XX_PQS_PDS - bool "include support for the NCR PQS/PDS SCSI card" - depends on (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && SCSI_SYM53C8XX - help - Say Y here if you have a special SCSI adapter produced by NCR - corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need - this if you do not have one of these adapters. However, since this - device is detected as a specific PCI device, this option is quite - safe. - - The common answer here is N, but answering Y is safe. - -config SCSI_NCR53C8XX_NO_DISCONNECT - bool "not allow targets to disconnect" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 - help - This option is only provided for safety if you suspect some SCSI - device of yours to not support properly the target-disconnect - feature. In that case, you would say Y here. In general however, to - not allow targets to disconnect is not reasonable if there is more - than 1 device on a SCSI bus. The normal answer therefore is N. - -config SCSI_NCR53C8XX_SYMBIOS_COMPAT - bool "assume boards are SYMBIOS compatible (EXPERIMENTAL)" - depends on PCI && SCSI_SYM53C8XX_2!=y && (SCSI_NCR53C8XX || SCSI_SYM53C8XX) && EXPERIMENTAL - ---help--- - This option allows you to enable some features depending on GPIO - wiring. These General Purpose Input/Output pins can be used for - vendor specific features or implementation of the standard SYMBIOS - features. Genuine SYMBIOS controllers use GPIO0 in output for - controller LED and GPIO3 bit as a flag indicating - singled-ended/differential interface. The Tekram DC-390U/F boards - uses a different GPIO wiring. - - Your answer to this question is ignored if all your controllers have - NVRAM, since the driver is able to detect the board type from the - NVRAM format. - - If all the controllers in your system are genuine SYMBIOS boards or - use BIOS and drivers from SYMBIOS, you would want to say Y here, - otherwise N. N is the safe answer. - -config SCSI_QLOGIC_ISP - tristate "Qlogic ISP SCSI support" - depends on PCI && SCSI - ---help--- - This driver works for all QLogic PCI SCSI host adapters (IQ-PCI, - IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter - card is supported by the "AM53/79C974 PCI SCSI" driver.) - - If you say Y here, make sure to choose "BIOS" at the question "PCI - access mode". - - Please read the file . You - should also read the SCSI-HOWTO, available from - . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called qlogicisp. If you want to compile it as - a module, say M here and read . - -config SCSI_QLOGIC_FC - tristate "Qlogic ISP FC SCSI support" - depends on PCI && SCSI - help - This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called qlogicfc. If you want to compile it as - a module, say M here and read . - -config SCSI_QLOGIC_FC_FIRMWARE - bool - depends on SCSI_QLOGIC_FC - default y - -endmenu +source "drivers/scsi/Kconfig" endmenu diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Sun Jun 15 07:49:09 2003 +++ b/arch/sparc64/defconfig Thu Jun 19 18:35:17 2003 @@ -90,6 +90,11 @@ CONFIG_WATCHDOG_RIO=m # +# Generic Driver Options +# +CONFIG_FW_LOADER=m + +# # Graphics support # CONFIG_FB=y @@ -266,39 +271,72 @@ CONFIG_SCSI=y # -# SCSI support type (disk, tape, CDrom) +# SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=m CONFIG_CHR_DEV_OSST=m CONFIG_BLK_DEV_SR=m CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=m # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_REPORT_LUNS=y CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers # -CONFIG_SCSI_SUNESP=y -CONFIG_SCSI_QLOGICPTI=m +CONFIG_BLK_DEV_3W_XXXX_RAID=m +CONFIG_SCSI_ACARD=m +CONFIG_SCSI_AACRAID=m # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set +CONFIG_SCSI_AIC79XX=m +CONFIG_AIC79XX_CMDS_PER_DEVICE=32 +CONFIG_AIC79XX_RESET_DELAY_MS=15000 +# CONFIG_AIC79XX_BUILD_FIRMWARE is not set +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set +# CONFIG_AIC79XX_DEBUG_ENABLE is not set +CONFIG_AIC79XX_DEBUG_MASK=0 +# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +CONFIG_SCSI_DMX3191D=m +# CONFIG_SCSI_EATA is not set +CONFIG_SCSI_EATA_PIO=m +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_INITIO is not set +CONFIG_SCSI_INIA100=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_IMM=m +# CONFIG_SCSI_IZIP_EPP16 is not set +# CONFIG_SCSI_IZIP_SLOW_CTR is not set CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 # CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set CONFIG_SCSI_QLOGIC_ISP=m CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLOGICPTI=m +CONFIG_SCSI_DC395x=m +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +CONFIG_SCSI_DEBUG=m +CONFIG_SCSI_SUNESP=y # # Fibre Channel support @@ -966,17 +1004,19 @@ # # Miscellaneous filesystems # -# CONFIG_ADFS_FS is not set +CONFIG_ADFS_FS=m +# CONFIG_ADFS_FS_RW is not set CONFIG_AFFS_FS=m -# CONFIG_HFS_FS is not set +CONFIG_HFS_FS=m CONFIG_BEFS_FS=m # CONFIG_BEFS_DEBUG is not set CONFIG_BFS_FS=m CONFIG_EFS_FS=m -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set +CONFIG_CRAMFS=m +CONFIG_VXFS_FS=m CONFIG_HPFS_FS=m -# CONFIG_QNX4FS_FS is not set +CONFIG_QNX4FS_FS=m +# CONFIG_QNX4FS_RW is not set CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_UFS_FS_WRITE=y @@ -997,12 +1037,22 @@ CONFIG_SUNRPC=m CONFIG_SUNRPC_GSS=m CONFIG_RPCSEC_GSS_KRB5=m -# CONFIG_SMB_FS is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set CONFIG_CIFS=m -# CONFIG_NCP_FS is not set +CONFIG_NCP_FS=m +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set CONFIG_CODA_FS=m # CONFIG_INTERMEZZO_FS is not set -# CONFIG_AFS_FS is not set +CONFIG_AFS_FS=m +CONFIG_RXRPC=m # # Partition Types @@ -1010,6 +1060,7 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y CONFIG_SUN_PARTITION=y +CONFIG_SMB_NLS=y CONFIG_NLS=y # @@ -1210,6 +1261,7 @@ # # USB Network adaptors # +CONFIG_USB_AX8817X=m CONFIG_USB_CATC=m CONFIG_USB_KAWETH=m CONFIG_USB_PEGASUS=m diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c --- a/arch/sparc64/kernel/time.c Sat Jun 14 16:15:59 2003 +++ b/arch/sparc64/kernel/time.c Tue Jun 17 14:51:27 2003 @@ -703,9 +703,9 @@ } xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; if (mregs) { tmp = mostek_read(mregs + MOSTEK_CREG); @@ -743,9 +743,9 @@ (unsigned int) (long) &unix_tod); prom_feval(obp_gettod); xtime.tv_sec = unix_tod; - wall_to_monotonic.tv_sec = -xtime.tv_sec + INITIAL_JIFFIES / HZ; + wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = 0; + wall_to_monotonic.tv_nsec = -xtime.tv_nsec; return; } diff -Nru a/arch/um/Kconfig b/arch/um/Kconfig --- a/arch/um/Kconfig Sat Mar 8 14:50:37 2003 +++ b/arch/um/Kconfig Thu Jun 19 10:23:30 2003 @@ -62,14 +62,7 @@ config NET bool "Networking support" -config BINFMT_AOUT - tristate "Kernel support for a.out binaries" - -config BINFMT_ELF - tristate "Kernel support for ELF binaries" - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" +source "fs/Kconfig.binfmt" config HOSTFS tristate "Host filesystem" @@ -177,6 +170,8 @@ endmenu source "init/Kconfig" + +source "drivers/base/Kconfig" source "arch/um/Kconfig_char" diff -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig --- a/arch/v850/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/v850/Kconfig Thu Jun 19 10:23:30 2003 @@ -243,20 +243,13 @@ config KCORE_ELF default y -config BINFMT_FLAT - tristate "Kernel support for flat binaries" - help - Support uClinux FLAT format binaries. - -config BINFMT_ZFLAT - bool " Enable ZFLAT support" - depends on BINFMT_FLAT - help - Support FLAT format compressed binaries +source "fs/Kconfig.binfmt" endmenu ############################################################################# + +source "drivers/base/Kconfig" source drivers/mtd/Kconfig diff -Nru a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S --- a/arch/v850/vmlinux.lds.S Tue May 27 00:09:43 2003 +++ b/arch/v850/vmlinux.lds.S Mon Jun 16 22:23:12 2003 @@ -95,7 +95,10 @@ *(.initcall6.init) \ *(.initcall7.init) \ . = ALIGN (4) ; \ - ___initcall_end = . ; + ___initcall_end = . ; \ + ___con_initcall_start = .; \ + *(.con_initcall.init) \ + ___con_initcall_end = .; /* Contents of `init' section for a kernel that's loaded into RAM. */ #define RAMK_INIT_CONTENTS \ @@ -232,5 +235,15 @@ # include "rte_ma1_cb-rom.ld" # else # include "rte_ma1_cb.ld" +# endif +#endif + +#ifdef CONFIG_RTE_CB_NB85E +# ifdef CONFIG_ROM_KERNEL +# include "rte_nb85e_cb-rom.ld" +# elif defined(CONFIG_RTE_CB_MULTI) +# include "rte_nb85e_cb-multi.ld" +# else +# include "rte_nb85e_cb.ld" # endif #endif diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Wed Jun 11 18:15:04 2003 +++ b/arch/x86_64/Kconfig Thu Jun 19 10:23:30 2003 @@ -375,31 +375,7 @@ depends on PROC_FS default y -config BINFMT_ELF - bool - default y - -config BINFMT_MISC - tristate "Kernel support for MISC binaries" - ---help--- - If you say Y here, it will be possible to plug wrapper-driven binary - formats into the kernel. You will like this especially when you use - programs that need an interpreter to run like Java, Python or - Emacs-Lisp. Once you have registered such a binary class with the kernel, - you can start one of those programs simply by typing in its name at a shell - prompt; Linux will automatically feed it to the correct interpreter. - - You can do other nice things, too. Read the file - to learn how to use this - feature, and for information about how - to include Java support. - - You must say Y to "/proc file system support" (CONFIG_PROC_FS) to - use this part of the kernel. - - You may say M here for module support and later load the module when - you have use for it; the module is called binfmt_misc. If you - don't know what to answer at this point, say Y. +source "fs/Kconfig.binfmt" config IA32_EMULATION bool "IA32 Emulation" @@ -420,6 +396,8 @@ default y endmenu + +source "drivers/base/Kconfig" source "drivers/mtd/Kconfig" diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig --- a/drivers/acpi/Kconfig Tue Mar 25 13:32:08 2003 +++ b/drivers/acpi/Kconfig Fri Jun 13 14:52:18 2003 @@ -49,12 +49,12 @@ Full ACPI support (CONFIG_ACPI) is preferred. Use this option only if you wish to limit ACPI's role to processor enumeration. - There is no command-line option to disable this, but the kernel - will fall back to the MPS table if the MADT is not present. + In this configuration, ACPI defaults to off. It must be enabled + on the command-line with the "acpismp=force" option. config ACPI_BOOT bool - depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY || X86 && ACPI + depends on IA64 && (!IA64_HP_SIM || IA64_SGI_SN) || X86 && ACPI && !ACPI_HT_ONLY default y config ACPI_SLEEP @@ -135,6 +135,31 @@ bool "NUMA support" if NUMA && (IA64 && !IA64_HP_SIM || X86 && ACPI && !ACPI_HT_ONLY && !X86_64) default y if IA64 && IA64_SGI_SN +config ACPI_ASUS + tristate "ASUS/Medion Laptop Extras" + depends on X86 && ACPI && !ACPI_HT_ONLY + ---help--- + This driver provides support for extra features of ACPI-compatible + ASUS laptops. As some of Medion laptops are made by ASUS, it may also + support some Medion laptops (such as 9675 for example). It makes all + the extra buttons generate standard ACPI events that go through + /proc/acpi/events, and (on some models) adds support for changing the + display brightness and output, switching the LCD backlight on and off, + and most importantly, allows you to blink those fancy LEDs intended + for reporting mail and wireless status. + + All settings are changed via /proc/acpi/asus directory entries. Owner + and group for these entries can be set with asus_uid and asus_gid + parameters. + + More information and a userspace daemon for handling the extra buttons + at . + + If you have an ACPI-compatible ASUS laptop, say Y or M here. This + driver is still under development, so if your laptop is unsupported or + something works not quite as expected, please use the mailing list + available on the above page (acpi4asus-user@lists.sourceforge.net) + config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on X86 && ACPI && !ACPI_HT_ONLY diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile --- a/drivers/acpi/Makefile Thu Feb 13 09:52:30 2003 +++ b/drivers/acpi/Makefile Fri Jun 13 11:50:34 2003 @@ -44,5 +44,6 @@ obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o +obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_BUS) += scan.o diff -Nru a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/acpi/asus_acpi.c Fri Jun 13 11:50:34 2003 @@ -0,0 +1,951 @@ +/* + * asus_acpi.c - Asus Laptop ACPI Extras + * + * + * Copyright (C) 2002, 2003 Julien Lerouge, Karol Kozimor + * + * 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 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The development page for this driver is located at + * http://sourceforge.net/projects/acpi4asus/ + * + * Credits: + * Johann Wiesner - Small compile fixes + * John Belmonte - ACPI code for Toshiba laptop was a good starting point. + * + * TODO + * add Fn key status + * Add mode selection on module loading (parameter) -> still necessary ? + * Complete display switching -- may require dirty hacks? + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ASUS_ACPI_VERSION "0.24a" + +#define PROC_ASUS "asus" //the directory +#define PROC_MLED "mled" +#define PROC_WLED "wled" +#define PROC_INFOS "info" +#define PROC_LCD "lcd" +#define PROC_BRN "brn" +#define PROC_DISP "disp" + +#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver" +#define ACPI_HOTK_CLASS "hotkey" +#define ACPI_HOTK_DEVICE_NAME "Hotkey" +#define ACPI_HOTK_HID "ATK0100" + +/* + * Some events we use, same for all Asus + */ +#define BR_UP 0x10 +#define BR_DOWN 0x20 + +/* + * Flags for hotk status + */ +#define MLED_ON 0x01 //is MLED ON ? +#define WLED_ON 0x02 + +MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); +MODULE_DESCRIPTION(ACPI_HOTK_NAME); +MODULE_LICENSE("GPL"); + + +static uid_t asus_uid = 0; +static gid_t asus_gid = 0; +MODULE_PARM(asus_uid, "i"); +MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n"); +MODULE_PARM(asus_gid, "i"); +MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n"); + + +/* For each model, all features implemented */ +struct model_data { + char *name; //name of the laptop + char *mt_mled; //method to handle mled + char *mled_status; //node to handle mled reading + char *mt_wled; //method to handle wled + char *wled_status; //node to handle wled reading + char *mt_lcd_switch; //method to turn LCD ON/OFF + char *lcd_status; //node to read LCD panel state + char *brightness_up; //method to set brightness up + char *brightness_down; //guess what ? + char *brightness_set; //method to set absolute brightness + char *brightness_get; //method to get absolute brightness + char *brightness_status;//node to get brightness + char *display_set; //method to set video output + char *display_get; //method to get video output +}; + +/* + * This is the main structure, we can use it to store anything interesting + * about the hotk device + */ +struct asus_hotk { + struct acpi_device *device; //the device we are in + acpi_handle handle; //the handle of the hotk device + char status; //status of the hotk, for LEDs, ... + struct model_data *methods; //methods available on the laptop + u8 brightness; //brighness level + enum { + L2X = 0, //L200D -> TODO check Q11 (Fn+F8) + // Calling this method simply hang the + // computer, ISMI method hangs the laptop. + L3X, //L3C + L3D, //L3400D + M2X, //M2400E + S1X, //S1300A -> TODO special keys do not work ? + D1X, //D1 + L1X, //L1400B + A1X, //A1340D, A1300F + J1X, //S200 (J1) + //TODO A1370D does not seems to have a ATK device + // L8400 model doesn't have ATK + END_MODEL, + } model; //Models currently supported + u16 event_count[128]; //count for each event TODO make this better +}; + +/* Here we go */ +#define L3X_PREFIX "\\_SB.PCI0.PX40.ECD0." +#define S1X_PREFIX "\\_SB.PCI0.PX40." +#define L1X_PREFIX S1X_PREFIX +#define A1X_PREFIX "\\_SB.PCI0.ISA.EC0." +#define J1X_PREFIX A1X_PREFIX + +static struct model_data model_conf[END_MODEL] = { + /* + * name| mled |mled read| wled |wled read| lcd sw |lcd read | + * br up|br down | br set | br read | br status|set disp | get disp + * + * br set and read shall be in hotk device ! + * same for set disp + * + * TODO I have seen a SWBX and AIBX method on some models, like L1400B, + * it seems to be a kind of switch, but what for ? + * + */ + {"L2X", "MLED", "\\SGP6", "WLED", "\\RCP3", "\\Q10", "\\SGP0", + "\\Q0E", "\\Q0F", NULL, NULL, NULL, "SDSP", "\\INFB"}, + + {"L3X", "MLED", NULL, "WLED", NULL, L3X_PREFIX "_Q10", "\\GL32", + L3X_PREFIX "_Q0F", L3X_PREFIX "_Q0E", "SPLV", "GPLV", "\\BLVL", "SDSP", + "\\_SB.PCI0.PCI1.VGAC.NMAP"}, + + {"L3D", "MLED", "\\MALD", "WLED", NULL, "\\Q10", "\\BKLG", + "\\Q0E", "\\Q0F", "SPLV", "GPLV", "\\BLVL", "SDSP", "\\INFB"}, + + {"M2X", "MLED", NULL, "WLED", NULL, "\\Q10", "\\GP06", + "\\Q0E","\\Q0F", "SPLV", "GPLV", NULL, "SDSP", "\\INFB"}, + + {"S1X", "MLED", "\\EMLE", "WLED", NULL, S1X_PREFIX "Q10", "\\PNOF", + S1X_PREFIX "Q0F", S1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, + + {"D1X", "MLED", NULL, NULL, NULL, "\\Q0D", "\\GP11", + "\\Q0C", "\\Q0B", NULL, NULL, "\\BLVL", "SDSP","\\INFB"}, + + {"L1X", "MLED", NULL, "WLED", NULL, L1X_PREFIX "Q10", "\\PNOF", + L1X_PREFIX "Q0F", L1X_PREFIX "Q0E", "SPLV", "GPLV", "\\BRIT", NULL, NULL}, + + {"A1X", "MLED", "\\MAIL", NULL, NULL, A1X_PREFIX "_Q10", "\\BKLI", + A1X_PREFIX "_Q0E", A1X_PREFIX "_Q0F", NULL, NULL, NULL, NULL, NULL}, + + {"J1X", "MLED", "\\MAIL", NULL, NULL, J1X_PREFIX "_Q10", "\\BKLI", + J1X_PREFIX "_Q0B", J1X_PREFIX "_Q0A", NULL, NULL, NULL, NULL, NULL} +}; + +/* procdir we use */ +static struct proc_dir_entry *asus_proc_dir = NULL; + +/* + * This header is made available to allow proper configuration given model, + * revision number , ... this info cannot go in struct asus_hotk because it is + * available before the hotk + */ +static struct acpi_table_header *asus_info = NULL; + +/* + * The hotkey driver declaration + */ +static int asus_hotk_add(struct acpi_device *device); +static int asus_hotk_remove(struct acpi_device *device, int type); +static struct acpi_driver asus_hotk_driver = { + .name = ACPI_HOTK_NAME, + .class = ACPI_HOTK_CLASS, + .ids = ACPI_HOTK_HID, + .ops = { + .add = asus_hotk_add, + .remove = asus_hotk_remove, + }, +}; + +/* + * This function evaluates an ACPI method, given an int as parameter, the + * method is searched within the scope of the handle, can be NULL. The output + * of the method is written is output, which can also be NULL + * + * returns 1 if write is successful, 0 else. + */ +static int write_acpi_int(acpi_handle handle, const char *method, int val, + struct acpi_buffer *output) +{ + struct acpi_object_list params; //list of input parameters (an int here) + union acpi_object in_obj; //the only param we use + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = val; + + status = acpi_evaluate_object(handle, (char *) method, ¶ms, output); + return (status == AE_OK); +} + + +static int read_acpi_int(acpi_handle handle, const char *method, int *val) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, (char*) method, NULL, &output); + *val = out_obj.integer.value; + return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER); +} + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static int +proc_read_info(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + char buf[16]; //enough for all info + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + + len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n"); + len += + sprintf(page + len, "Model reference : %s\n", + hotk->methods->name); + if (asus_info) { + snprintf(buf, 5, "%s", asus_info->signature); + len += sprintf(page + len, "ACPI signature : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->length); + len += sprintf(page + len, "Table length : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->revision); + len += sprintf(page + len, "ACPI minor version : %s\n", buf); + snprintf(buf, 16, "%d", asus_info->checksum); + len += sprintf(page + len, "Checksum : %s\n", buf); + snprintf(buf, 7, "%s", asus_info->oem_id); + len += sprintf(page + len, "OEM identification : %s\n", buf); + snprintf(buf, 9, "%s", asus_info->oem_table_id); + len += sprintf(page + len, "OEM table id : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->oem_revision); + len += sprintf(page + len, "OEM rev number : 0x%s\n", buf); + snprintf(buf, 5, "%s", asus_info->asl_compiler_id); + len += sprintf(page + len, "ASL comp vendor ID : %s\n", buf); + snprintf(buf, 16, "%x", asus_info->asl_compiler_revision); + len += sprintf(page + len, "ASL comp rev number: 0x%s\n", buf); + } + + return len; +} + + +/* + * proc file handlers + */ +static int +proc_read_mled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + int led_status = 0; + /* + * We use the easy way, we don't care of off and count, so we don't set eof + * to 1 + */ + if (hotk->methods->mled_status) { + if (read_acpi_int(NULL, hotk->methods->mled_status, + &led_status)) + len = sprintf(page, "%d\n", led_status); + else + printk(KERN_NOTICE "Asus ACPI: Error reading MLED " + "status\n"); + } else { + len = sprintf(page, "%d\n", (hotk->status & MLED_ON) ? 1 : 0); + } + + return len; +} + + +static int +proc_write_mled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int led_out = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + led_out = ~value & 1; + + hotk->status = + (value) ? (hotk->status | MLED_ON) : (hotk->status & ~MLED_ON); + + /* We don't have to check mt_mled exists if we are here :) */ + if (!write_acpi_int(hotk->handle, hotk->methods->mt_mled, led_out, + NULL)) + printk(KERN_NOTICE "Asus ACPI: MLED write failed\n"); + + + + return count; +} + +/* + * We write our info in page, we begin at offset off and cannot write more + * than count bytes. We set eof to 1 if we handle those 2 values. We return the + * number of bytes written in page + */ +static int +proc_read_wled(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int len = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + int led_status; + + if (hotk->methods->wled_status) { + if (read_acpi_int(NULL, hotk->methods->mled_status, + &led_status)) + len = sprintf(page, "%d\n", led_status); + else + printk(KERN_NOTICE "Asus ACPI: Error reading WLED " + "status\n"); + } else { + len = sprintf(page, "%d\n", (hotk->status & WLED_ON) ? 1 : 0); + } + + return len; +} + +static int +proc_write_wled(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int led_out = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + led_out = value & 1; + + hotk->status = + (value) ? (hotk->status | WLED_ON) : (hotk->status & ~WLED_ON); + + /* We don't have to check if mt_wled exists if we are here :) */ + if (!write_acpi_int(hotk->handle, hotk->methods->mt_wled, led_out, + NULL)) + printk(KERN_NOTICE "Asus ACPI: WLED write failed\n"); + + + return count; +} + + +static int get_lcd_state(struct asus_hotk *hotk) +{ + int lcd = 0; + + /* We don't have to check anything, if we are here */ + if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) + printk(KERN_NOTICE "Asus ACPI: Error reading LCD status\n"); + + if (hotk->model == L2X) + lcd = ~lcd; + + return (lcd & 1); +} + + +static int +proc_read_lcd(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + return sprintf(page, "%d\n", get_lcd_state((struct asus_hotk *) data)); +} + + +static int +proc_write_lcd(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + int lcd = 0; + acpi_status status = 0; + int lcd_status = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%i", &value) == 1) + lcd = value & 1; + + lcd_status = get_lcd_state(hotk); + + if (lcd_status != lcd) { + /* switch */ + status = + acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Asus ACPI: Error switching LCD\n"); + } + + return count; +} + + +/* + * Change the brightness level + */ +static void set_brightness(int value, struct asus_hotk *hotk) +{ + acpi_status status = 0; + + /* ATKD laptop */ + if(hotk->methods->brightness_set) { + if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set, + value, NULL)) + printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n"); + return; + } + + /* HOTK laptop if we are here, act as appropriate */ + value -= hotk->brightness; + while (value != 0) { + status = acpi_evaluate_object(NULL, (value > 0) ? + hotk->methods->brightness_up : + hotk->methods->brightness_down, + NULL, NULL); + (value > 0) ? value-- : value++; + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Asus ACPI: Error changing brightness\n"); + } + return; +} + +static int read_brightness(struct asus_hotk *hotk) +{ + int value; + + if(hotk->methods->brightness_get) { /* ATKD laptop */ + if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, + &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n"); + } else if (hotk->methods->brightness_status) { /* For D1 for example */ + if (!read_acpi_int(NULL, hotk->methods->brightness_status, + &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading brightness\n"); + } else /* HOTK laptop */ + value = hotk->brightness; + return value; +} + +static int +proc_read_brn(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + struct asus_hotk *hotk = (struct asus_hotk *) data; + return sprintf(page, "%d\n", read_brightness(hotk)); +} + +static int +proc_write_brn(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%d", &value) == 1) { + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + /* 0 <= value <= 15 */ + set_brightness(value, hotk); + } else { + printk(KERN_NOTICE "Asus ACPI: Error reading user input\n"); + } + + return count; +} + +static void set_display(int value, struct asus_hotk *hotk) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(hotk->handle, hotk->methods->display_set, + value, NULL)) + printk(KERN_NOTICE "Asus ACPI: Error setting display\n"); + return; +} + +/* + * Now, *this* one could be more user-friendly, but so far, no-one has + * complained. The significance of bits is the same as in proc_write_disp() + */ + +static int +proc_read_disp(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + int value = 0; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value)) + printk(KERN_NOTICE "Asus ACPI: Error reading display status\n"); + return sprintf(page, "%d\n", value); +} + +/* + * Preliminary support for display switching. As of now: 0x01 should activate + * the LCD output, 0x02 should do for CRT, and 0x04 for TV-Out. Any combination + * (bitwise) of these will suffice. I never actually tested 3 displays hooked up + * simultaneously, so be warned. + */ + +static int +proc_write_disp(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int value; + struct asus_hotk *hotk = (struct asus_hotk *) data; + + /* scan expression. Multiple expressions may be delimited with ; */ + if (sscanf(buffer, "%d", &value) == 1) + set_display(value, hotk); + else { + printk(KERN_NOTICE "Asus ACPI: Error reading user input\n"); + } + + return count; +} + +static int asus_hotk_add_fs(struct acpi_device *device) +{ + struct proc_dir_entry *proc; + struct asus_hotk *hotk = acpi_driver_data(device); + mode_t mode; + + /* + * If parameter uid or gid is not changed, keep the default setting for + * our proc entries (-rw-rw-rw-) else, it means we care about security, + * and then set to -rw-rw---- + */ + + if ((asus_uid == 0) && (asus_gid == 0)){ + mode = S_IFREG | S_IRUGO | S_IWUGO; + }else{ + mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; + } + + acpi_device_dir(device) = asus_proc_dir; + if (!acpi_device_dir(device)) + return(-ENODEV); + + proc = create_proc_entry(PROC_INFOS, mode, acpi_device_dir(device)); + if (proc) { + proc->read_proc = proc_read_info; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_INFOS + " fs entry\n"); + } + + if (hotk->methods->mt_wled) { + proc = create_proc_entry(PROC_WLED, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_wled; + proc->read_proc = proc_read_wled; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_WLED + " fs entry\n"); + } + } + + if (hotk->methods->mt_mled) { + proc = create_proc_entry(PROC_MLED, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_mled; + proc->read_proc = proc_read_mled; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_MLED + " fs entry\n"); + } + } + + /* + * We need both read node and write method as LCD switch is also accessible + * from keyboard + */ + if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) { + proc = create_proc_entry(PROC_LCD, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_lcd; + proc->read_proc = proc_read_lcd; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_LCD + " fs entry\n"); + } + } + + if ((hotk->methods->brightness_up && hotk->methods->brightness_down) || + (hotk->methods->brightness_get && hotk->methods->brightness_get)) { + proc = create_proc_entry(PROC_BRN, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_brn; + proc->read_proc = proc_read_brn; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_BRN + " fs entry\n"); + } + } + + if (hotk->methods->display_set) { + proc = create_proc_entry(PROC_DISP, mode, acpi_device_dir(device)); + if (proc) { + proc->write_proc = proc_write_disp; + proc->read_proc = proc_read_disp; + proc->data = acpi_driver_data(device); + proc->owner = THIS_MODULE; + proc->uid = asus_uid; + proc->gid = asus_gid;; + } else { + printk(KERN_NOTICE " Unable to create " PROC_DISP + " fs entry\n"); + } + } + + return (AE_OK); +} + + +static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) +{ + /* TODO Find a better way to handle events count. Here, in data, we receive + * the hotk, so we can make anything !! + */ + struct asus_hotk *hotk = (struct asus_hotk *) data; + + if (!hotk) + return; + + if ((event & ~((u32) BR_UP)) < 16) { + hotk->brightness = (event & ~((u32) BR_UP)); + } else if ((event & ~((u32) BR_DOWN)) < 16 ) { + hotk->brightness = (event & ~((u32) BR_DOWN)); + } + + acpi_bus_generate_event(hotk->device, event, + hotk->event_count[event % 128]++); + + return; +} + +/* + * This function is used to initialize the hotk with right values. In this + * method, we can make all the detection we want, and modify the hotk struct + */ +static int asus_hotk_get_info(struct asus_hotk *hotk) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *model = NULL; + + /* + * We have to write 0 on init this far for all ASUS models + */ + if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { + printk(KERN_NOTICE " Hotkey initialization failed\n"); + return -ENODEV; + } + + /* + * Here, we also use asus_info to make decision. For example, on INIT + * method, S1X and L1X models both reports to be L84F, but they don't + * have the same methods (L1X has WLED, S1X don't) + */ + model = (union acpi_object *) buffer.pointer; + if (model->type == ACPI_TYPE_STRING) { + printk(KERN_NOTICE " %s model detected, ", model->string.pointer); + } + + hotk->model = END_MODEL; + if (strncmp(model->string.pointer, "L3D", 3) == 0) + hotk->model = L3D; + /* + * L2B has same settings that L3X, except for GL32, but as + * there is no node to get the LCD status, and as GL32 is never + * used anywhere else, I assume it's safe, even if lcd get is + * broken for this model (TODO fix it ?) + */ + else if (strncmp(model->string.pointer, "L3", 2) == 0 || + strncmp(model->string.pointer, "L2B", 3) == 0) + hotk->model = L3X; + else if (strncmp(model->string.pointer, "M2", 2) == 0) + hotk->model = M2X; + else if (strncmp(model->string.pointer, "L2", 2) == 0) + hotk->model = L2X; + else if (strncmp(model->string.pointer, "L8", 2) == 0) + /* S1300A reports L84F, but L1400B too */ + if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) + hotk->model = L1X; + else + hotk->model = S1X; + else if (strncmp(model->string.pointer, "D1", 2) == 0) + hotk->model = D1X; + else if (strncmp(model->string.pointer, "A1", 2) == 0) + hotk->model = A1X; + else if (strncmp(model->string.pointer, "J1", 2) == 0) + hotk->model = J1X; + + + if (hotk->model == END_MODEL) { + /* By default use the same values, as I don't know others */ + printk("unsupported, trying default values, contact the " + "developers\n"); + hotk->model = L2X; + } else { + printk("supported\n"); + } + + hotk->methods = &model_conf[hotk->model]; + + acpi_os_free(model); + + return AE_OK; +} + + + +static int asus_hotk_check(struct asus_hotk *hotk) +{ + int result = 0; + + if (!hotk) + return(-EINVAL); + + result = acpi_bus_get_status(hotk->device); + if (result) + return(result); + + if (hotk->device->status.present) { + result = asus_hotk_get_info(hotk); + } else { + printk(KERN_NOTICE " Hotkey device not present, aborting\n"); + return(-EINVAL); + } + + return(result); +} + + + +static int asus_hotk_add(struct acpi_device *device) +{ + struct asus_hotk *hotk = NULL; + acpi_status status = AE_OK; + int result; + + if (!device) + return(-EINVAL); + + hotk = + (struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL); + if (!hotk) + return(-ENOMEM); + memset(hotk, 0, sizeof(struct asus_hotk)); + + hotk->handle = device->handle; + sprintf(acpi_device_name(device), "%s", ACPI_HOTK_DEVICE_NAME); + sprintf(acpi_device_class(device), "%s", ACPI_HOTK_CLASS); + acpi_driver_data(device) = hotk; + hotk->device = device; + + + result = asus_hotk_check(hotk); + if (result) + goto end; + + result = asus_hotk_add_fs(device); + if (result) + goto end; + + /* + * We install the handler, it will receive the hotk in parameter, so, we + * could add other data to the hotk struct + */ + status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify, hotk); + if (ACPI_FAILURE(status)) { + printk(KERN_NOTICE + " Error installing notify handler\n"); + } else { + printk(KERN_DEBUG + " Notify Handler installed successfully\n"); + } + + /* For HOTK laptops: init the hotk->brightness value */ + if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) && + (hotk->methods->brightness_up && hotk->methods->brightness_down)) { + status = acpi_evaluate_object(NULL, hotk->methods->brightness_down, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE " Error changing brightness\n"); + status = acpi_evaluate_object(NULL, hotk->methods->brightness_up, + NULL, NULL); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE " Error changing brightness\n"); + } + + end: + if (result) { + kfree(hotk); + } + + return(result); +} + + + + +static int asus_hotk_remove(struct acpi_device *device, int type) +{ + acpi_status status = 0; + struct asus_hotk *hotk = NULL; + + if (!device || !acpi_driver_data(device)) + return(-EINVAL); + + hotk = (struct asus_hotk *) acpi_driver_data(device); + + status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, + asus_hotk_notify); + if (ACPI_FAILURE(status)) + printk(KERN_NOTICE "Error removing notify handler\n"); + + kfree(hotk); + + return(0); +} + + + + +static int __init asus_acpi_init(void) +{ + int result = 0; + acpi_status status = 0; + struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; + + printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", + ASUS_ACPI_VERSION); + /* + * Here is the code to know the model we are running on. We need to + * know this before calling the acpi_bus_register_driver function, in + * case the HID for the laptop we are running on is different from + * ACPI_HOTK_HID, which I have never seen yet :) + * + * This information is then available in the global var asus_info + */ + status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt); + if (ACPI_FAILURE(status)) { + printk(KERN_NOTICE " Couldn't get the DSDT table header\n"); + } else { + asus_info = (struct acpi_table_header *) dsdt.pointer; + } + + asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); + if (!asus_proc_dir) + return(-ENODEV); + asus_proc_dir->owner = THIS_MODULE; + + result = acpi_bus_register_driver(&asus_hotk_driver); + if (result < 0) { + printk(KERN_NOTICE " Error registering " ACPI_HOTK_NAME " \n"); + remove_proc_entry(PROC_ASUS, acpi_root_dir); + return(-ENODEV); + } + + return(0); +} + + + +static void __exit asus_acpi_exit(void) +{ + acpi_bus_unregister_driver(&asus_hotk_driver); + remove_proc_entry(PROC_ASUS, acpi_root_dir); + + acpi_os_free(asus_info); + + return; +} + +module_init(asus_acpi_init); +module_exit(asus_acpi_exit); diff -Nru a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c --- a/drivers/acpi/dispatcher/dsmthdat.c Fri Apr 18 16:27:54 2003 +++ b/drivers/acpi/dispatcher/dsmthdat.c Thu Jun 19 17:41:29 2003 @@ -306,7 +306,6 @@ { acpi_status status; struct acpi_namespace_node *node; - union acpi_operand_object *new_desc = object; ACPI_FUNCTION_TRACE ("ds_method_data_set_value"); @@ -325,28 +324,16 @@ } /* - * If the object has just been created and is not attached to anything, - * (the reference count is 1), then we can just store it directly into - * the arg/local. Otherwise, we must copy it. + * Increment ref count so object can't be deleted while installed. + * NOTE: We do not copy the object in order to preserve the call by + * reference semantics of ACPI Control Method invocation. + * (See ACPI specification 2.0_c) */ - if (object->common.reference_count > 1) { - status = acpi_ut_copy_iobject_to_iobject (object, &new_desc, walk_state); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object Copied %p, new %p\n", - object, new_desc)); - } - else { - /* Increment ref count so object can't be deleted while installed */ - - acpi_ut_add_reference (new_desc); - } + acpi_ut_add_reference (object); /* Install the object */ - node->object = new_desc; + node->object = object; return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c --- a/drivers/acpi/events/evgpe.c Thu Apr 24 11:22:45 2003 +++ b/drivers/acpi/events/evgpe.c Thu Jun 19 17:41:29 2003 @@ -186,11 +186,13 @@ } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, - "GPE block at %8.8X%8.8X - Values: Enable %02X Status %02X\n", + "GPE pair: Status %8.8X%8.8X = %02X, Enable %8.8X%8.8X = %02X\n", + ACPI_HIDWORD (gpe_register_info->status_address.address), + ACPI_LODWORD (gpe_register_info->status_address.address), + gpe_register_info->status, ACPI_HIDWORD (gpe_register_info->enable_address.address), ACPI_LODWORD (gpe_register_info->enable_address.address), - gpe_register_info->enable, - gpe_register_info->status)); + gpe_register_info->enable)); /* First check if there is anything active at all in this register */ diff -Nru a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c --- a/drivers/acpi/events/evgpeblk.c Fri May 23 16:01:51 2003 +++ b/drivers/acpi/events/evgpeblk.c Thu Jun 19 17:41:29 2003 @@ -76,9 +76,14 @@ /* No need for spin lock since we are not changing any list elements */ + /* Walk the GPE interrupt levels */ + gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; while (gpe_xrupt_block) { gpe_block = gpe_xrupt_block->gpe_block_list_head; + + /* Walk the GPE blocks on this interrupt level */ + while (gpe_block) { if ((&gpe_block->event_info[0] <= gpe_event_info) && (&gpe_block->event_info[((acpi_size) gpe_block->register_count) * 8] > gpe_event_info)) { @@ -155,7 +160,7 @@ * * PARAMETERS: Callback from walk_namespace * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * control method under the _GPE portion of the namespace. @@ -164,10 +169,10 @@ * * The name of each GPE control method is of the form: * "_Lnn" or "_Enn" - * Where: - * L - means that the GPE is level triggered - * E - means that the GPE is edge triggered - * nn - is the GPE number [in HEX] + * Where: + * L - means that the GPE is level triggered + * E - means that the GPE is edge triggered + * nn - is the GPE number [in HEX] * ******************************************************************************/ @@ -196,7 +201,8 @@ name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd character of the method name + * Edge/Level determination is based on the 2nd character + * of the method name */ switch (name[1]) { case 'L': @@ -249,15 +255,14 @@ gpe_event_info->flags = type; gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; - /* - * Enable the GPE (SCIs should be disabled at this point) - */ + /* Enable the GPE (SCIs should be disabled at this point) */ + status = acpi_hw_enable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); return_ACPI_STATUS (AE_OK); @@ -867,8 +872,8 @@ } /* - * GPE0 and GPE1 do not have to be contiguous in the GPE number space, - * But, GPE0 always starts at zero. + * GPE0 and GPE1 do not have to be contiguous in the GPE number + * space. However, GPE0 always starts at GPE number zero. */ gpe_number_max = acpi_gbl_FADT->gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c --- a/drivers/acpi/executer/exoparg1.c Tue Feb 18 15:32:32 2003 +++ b/drivers/acpi/executer/exoparg1.c Thu Jun 19 17:41:29 2003 @@ -222,7 +222,7 @@ union acpi_operand_object *return_desc2 = NULL; u32 temp32; u32 i; - u32 j; + u32 power_of_ten; acpi_integer digit; @@ -291,61 +291,70 @@ case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ /* - * The 64-bit ACPI integer can hold 16 4-bit BCD integers + * The 64-bit ACPI integer can hold 16 4-bit BCD characters + * (if table is 32-bit, integer can hold 8 BCD characters) + * Convert each 4-bit BCD value */ + power_of_ten = 1; return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Get one BCD digit */ + digit = operand[0]->integer.value; - digit = (acpi_integer) ((operand[0]->integer.value >> (i * 4)) & 0xF); + /* Convert each BCD digit (each is one nybble wide) */ + + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + /* Get the least significant 4-bit BCD digit */ + + temp32 = ((u32) digit) & 0xF; /* Check the range of the digit */ - if (digit > 9) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD digit too large: %d\n", - (u32) digit)); + if (temp32 > 9) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "BCD digit too large (not decimal): 0x%X\n", + temp32)); + status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } - if (digit > 0) { - /* Sum into the result with the appropriate power of 10 */ + /* Sum the digit into the result with the current power of 10 */ - for (j = 0; j < i; j++) { - digit *= 10; - } + return_desc->integer.value += (((acpi_integer) temp32) * power_of_ten); - return_desc->integer.value += digit; - } + /* Shift to next BCD digit */ + + digit >>= 4; + + /* Next power of 10 */ + + power_of_ten *= 10; } break; case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ - if (operand[0]->integer.value > ACPI_MAX_BCD_VALUE) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "BCD overflow: %8.8X%8.8X\n", - ACPI_HIDWORD(operand[0]->integer.value), - ACPI_LODWORD(operand[0]->integer.value))); - status = AE_AML_NUMERIC_OVERFLOW; - goto cleanup; - } - return_desc->integer.value = 0; - for (i = 0; i < ACPI_MAX_BCD_DIGITS; i++) { - /* Divide by nth factor of 10 */ + digit = operand[0]->integer.value; - temp32 = 0; - digit = operand[0]->integer.value; - for (j = 0; j < i; j++) { - (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32); - } + /* Each BCD digit is one nybble wide */ - /* Create the BCD digit from the remainder above */ + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + (void) acpi_ut_short_divide (&digit, 10, &digit, &temp32); - if (digit > 0) { - return_desc->integer.value += ((acpi_integer) temp32 << (i * 4)); - } + /* Insert the BCD digit that resides in the remainder from above */ + + return_desc->integer.value |= (((acpi_integer) temp32) << (i * 4)); + } + + /* Overflow if there is any data left in Digit */ + + if (digit > 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Integer too large to convert to BCD: %8.8X%8.8X\n", + ACPI_HIDWORD(operand[0]->integer.value), + ACPI_LODWORD(operand[0]->integer.value))); + status = AE_AML_NUMERIC_OVERFLOW; + goto cleanup; } break; diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c --- a/drivers/acpi/executer/exstore.c Tue Feb 18 15:32:33 2003 +++ b/drivers/acpi/executer/exstore.c Thu Jun 19 17:41:29 2003 @@ -190,8 +190,8 @@ case ACPI_TYPE_INTEGER: ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%8.8X%8.8X\n", - ACPI_HIWORD (source_desc->integer.value), - ACPI_LOWORD (source_desc->integer.value))); + ACPI_HIDWORD (source_desc->integer.value), + ACPI_LODWORD (source_desc->integer.value))); break; diff -Nru a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c --- a/drivers/acpi/executer/exsystem.c Tue Feb 18 15:32:33 2003 +++ b/drivers/acpi/executer/exsystem.c Thu Jun 19 17:41:29 2003 @@ -134,7 +134,7 @@ acpi_ex_exit_interpreter (); - acpi_os_stall (how_long); + acpi_os_sleep (0, (how_long / 1000) + 1); /* And now we must get the interpreter again */ @@ -142,7 +142,7 @@ } else { - acpi_os_sleep (0, (how_long / 1000) + 1); + acpi_os_stall (how_long); } return (status); diff -Nru a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c --- a/drivers/acpi/executer/exutils.c Tue Feb 18 15:32:33 2003 +++ b/drivers/acpi/executer/exutils.c Thu Jun 19 17:41:29 2003 @@ -289,7 +289,10 @@ /* * acpi_integer is unsigned, so we don't worry about a '-' */ - current_value = value; + if ((current_value = value) == 0) { + return_VALUE (1); + } + num_digits = 0; while (current_value) { diff -Nru a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c --- a/drivers/acpi/hardware/hwregs.c Thu Apr 24 11:22:45 2003 +++ b/drivers/acpi/hardware/hwregs.c Thu Jun 19 17:41:29 2003 @@ -56,7 +56,7 @@ * * FUNCTION: acpi_hw_clear_acpi_status * - * PARAMETERS: none + * PARAMETERS: Flags - Lock the hardware or not * * RETURN: none * @@ -65,7 +65,8 @@ ******************************************************************************/ acpi_status -acpi_hw_clear_acpi_status (void) +acpi_hw_clear_acpi_status ( + u32 flags) { acpi_status status; @@ -77,10 +78,11 @@ ACPI_BITMASK_ALL_FIXED_STATUS, (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); - - status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + if (flags & ACPI_MTX_LOCK) { + status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } } status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, @@ -104,7 +106,9 @@ status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); unlock_and_exit: - (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + if (flags & ACPI_MTX_LOCK) { + (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); + } return_ACPI_STATUS (status); } @@ -237,8 +241,9 @@ * * FUNCTION: acpi_get_register * - * PARAMETERS: register_id - Index of ACPI Register to access - * use_lock - Lock the hardware + * PARAMETERS: register_id - ID of ACPI bit_register to access + * return_value - Value that was read from the register + * Flags - Lock the hardware or not * * RETURN: Value is read from specified Register. Value returned is * normalized to bit0 (is shifted all the way right) @@ -290,7 +295,8 @@ *return_value = register_value; - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %X\n", register_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %8.8X register %X\n", + register_value, bit_reg_info->parent_register)); } return_ACPI_STATUS (status); @@ -443,7 +449,8 @@ ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); - ACPI_DEBUG_PRINT ((ACPI_DB_IO, "ACPI Register Write actual %X\n", register_value)); + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n", + value, register_value, bit_reg_info->parent_register)); return_ACPI_STATUS (status); } @@ -751,10 +758,15 @@ default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); - status = AE_BAD_PARAMETER; - break; + return (AE_BAD_PARAMETER); } + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, + ACPI_HIDWORD (reg->address), + ACPI_LODWORD (reg->address), + acpi_ut_get_region_name (reg->address_space_id))); + return (status); } @@ -832,9 +844,14 @@ default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported address space: %X\n", reg->address_space_id)); - status = AE_BAD_PARAMETER; - break; + return (AE_BAD_PARAMETER); } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, + ACPI_HIDWORD (reg->address), + ACPI_LODWORD (reg->address), + acpi_ut_get_region_name (reg->address_space_id))); return (status); } diff -Nru a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c --- a/drivers/acpi/hardware/hwsleep.c Fri Apr 18 16:27:55 2003 +++ b/drivers/acpi/hardware/hwsleep.c Thu Jun 19 17:41:29 2003 @@ -231,7 +231,7 @@ return_ACPI_STATUS (status); } - status = acpi_hw_clear_acpi_status(); + status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } @@ -355,7 +355,7 @@ ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios"); acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK); - acpi_hw_clear_acpi_status(); + acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK); acpi_hw_disable_non_wakeup_gpes(); diff -Nru a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c --- a/drivers/acpi/tables/tbconvrt.c Mon May 12 10:44:47 2003 +++ b/drivers/acpi/tables/tbconvrt.c Thu Jun 19 17:41:29 2003 @@ -287,10 +287,14 @@ (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + - ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + } } @@ -379,11 +383,15 @@ ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id; - acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, - (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), - (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + - ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); - acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + /* PM1B is optional; leave null if not present */ + + if (local_fadt->xpm1b_evt_blk.address) { + acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, + (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), + (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address + + ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); + acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id; + } } diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c --- a/drivers/acpi/utilities/utmisc.c Mon May 12 10:44:47 2003 +++ b/drivers/acpi/utilities/utmisc.c Thu Jun 19 17:41:29 2003 @@ -203,10 +203,12 @@ if (revision <= 1) { acpi_gbl_integer_bit_width = 32; + acpi_gbl_integer_nybble_width = 8; acpi_gbl_integer_byte_width = 4; } else { acpi_gbl_integer_bit_width = 64; + acpi_gbl_integer_nybble_width = 16; acpi_gbl_integer_byte_width = 8; } } diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c --- a/drivers/atm/he.c Wed Jun 4 17:57:06 2003 +++ b/drivers/atm/he.c Wed Jun 18 18:08:15 2003 @@ -2710,12 +2710,13 @@ remove_wait_queue(&he_vcc->tx_waitq, &wait); set_current_state(TASK_RUNNING); + spin_lock_irqsave(&he_dev->global_lock, flags); + if (timeout == 0) { hprintk("close tx timeout cid 0x%x\n", cid); goto close_tx_incomplete; } - spin_lock_irqsave(&he_dev->global_lock, flags); while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); udelay(250); diff -Nru a/drivers/base/Kconfig b/drivers/base/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/Kconfig Thu Jun 19 10:06:56 2003 @@ -0,0 +1,10 @@ +menu "Generic Driver Options" + +config FW_LOADER + tristate "Hotplug firmware loading support" + ---help--- + This option is provided for the case where no in-kernel-tree modules + require hotplug firmware loading support, but a module built outside + the kernel tree does. + +endmenu diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile --- a/drivers/base/Makefile Sun May 25 02:45:07 2003 +++ b/drivers/base/Makefile Fri Jun 13 13:45:56 2003 @@ -3,4 +3,5 @@ obj-y := core.o sys.o interface.o power.o bus.o \ driver.o class.o platform.o \ cpu.o firmware.o init.o map.o +obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o memblk.o diff -Nru a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/base/firmware_class.c Tue Jun 17 02:10:01 2003 @@ -0,0 +1,505 @@ +/* + * firmware_class.c - Multi purpose firmware loading support + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Please see Documentation/firmware_class/ for more information. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "base.h" + +MODULE_AUTHOR("Manuel Estrada Sainz "); +MODULE_DESCRIPTION("Multi purpose firmware loading support"); +MODULE_LICENSE("GPL"); + +static int loading_timeout = 10; /* In seconds */ + +struct firmware_priv { + char fw_id[FIRMWARE_NAME_MAX]; + struct completion completion; + struct bin_attribute attr_data; + struct firmware *fw; + int loading; + int abort; + int alloc_size; + struct timer_list timeout; +}; + +static ssize_t +firmware_timeout_show(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", loading_timeout); +} + +/** + * firmware_timeout_store: + * Description: + * Sets the number of seconds to wait for the firmware. Once + * this expires an error will be return to the driver and no + * firmware will be provided. + * + * Note: zero means 'wait for ever' + * + **/ +static ssize_t +firmware_timeout_store(struct class *class, const char *buf, size_t count) +{ + loading_timeout = simple_strtol(buf, NULL, 10); + return count; +} + +static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); + +static void fw_class_dev_release(struct class_device *class_dev); +int firmware_class_hotplug(struct class_device *dev, char **envp, + int num_envp, char *buffer, int buffer_size); + +static struct class firmware_class = { + .name = "firmware", + .hotplug = firmware_class_hotplug, + .release = fw_class_dev_release, +}; + +int +firmware_class_hotplug(struct class_device *class_dev, char **envp, + int num_envp, char *buffer, int buffer_size) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int i = 0; + char *scratch = buffer; + + if (buffer_size < (FIRMWARE_NAME_MAX + 10)) + return -ENOMEM; + if (num_envp < 1) + return -ENOMEM; + + envp[i++] = scratch; + scratch += sprintf(scratch, "FIRMWARE=%s", fw_priv->fw_id) + 1; + return 0; +} + +static ssize_t +firmware_loading_show(struct class_device *class_dev, char *buf) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + return sprintf(buf, "%d\n", fw_priv->loading); +} + +/** + * firmware_loading_store: - loading control file + * Description: + * The relevant values are: + * + * 1: Start a load, discarding any previous partial load. + * 0: Conclude the load and handle the data to the driver code. + * -1: Conclude the load with an error and discard any written data. + **/ +static ssize_t +firmware_loading_store(struct class_device *class_dev, + const char *buf, size_t count) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + int prev_loading = fw_priv->loading; + + fw_priv->loading = simple_strtol(buf, NULL, 10); + + switch (fw_priv->loading) { + case -1: + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); + break; + case 1: + kfree(fw_priv->fw->data); + fw_priv->fw->data = NULL; + fw_priv->fw->size = 0; + fw_priv->alloc_size = 0; + break; + case 0: + if (prev_loading == 1) + complete(&fw_priv->completion); + break; + } + + return count; +} + +static CLASS_DEVICE_ATTR(loading, 0644, + firmware_loading_show, firmware_loading_store); + +static ssize_t +firmware_data_read(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + + if (offset > fw->size) + return 0; + if (offset + count > fw->size) + count = fw->size - offset; + + memcpy(buffer, fw->data + offset, count); + return count; +} +static int +fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) +{ + u8 *new_data; + + if (min_size <= fw_priv->alloc_size) + return 0; + + new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE); + if (!new_data) { + printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); + /* Make sure that we don't keep incomplete data */ + fw_priv->abort = 1; + return -ENOMEM; + } + fw_priv->alloc_size += PAGE_SIZE; + if (fw_priv->fw->data) { + memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); + vfree(fw_priv->fw->data); + } + fw_priv->fw->data = new_data; + BUG_ON(min_size > fw_priv->alloc_size); + return 0; +} + +/** + * firmware_data_write: + * + * Description: + * + * Data written to the 'data' attribute will be later handled to + * the driver as a firmware image. + **/ +static ssize_t +firmware_data_write(struct kobject *kobj, + char *buffer, loff_t offset, size_t count) +{ + struct class_device *class_dev = to_class_dev(kobj); + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + struct firmware *fw = fw_priv->fw; + int retval; + + retval = fw_realloc_buffer(fw_priv, offset + count); + if (retval) + return retval; + + memcpy(fw->data + offset, buffer, count); + + fw->size = max_t(size_t, offset + count, fw->size); + + return count; +} +static struct bin_attribute firmware_attr_data_tmpl = { + .attr = {.name = "data", .mode = 0644}, + .size = 0, + .read = firmware_data_read, + .write = firmware_data_write, +}; + +static void +fw_class_dev_release(struct class_device *class_dev) +{ + kfree(class_dev); +} + +static void +firmware_class_timeout(u_long data) +{ + struct firmware_priv *fw_priv = (struct firmware_priv *) data; + fw_priv->abort = 1; + wmb(); + complete(&fw_priv->completion); +} + +static inline void +fw_setup_class_device_id(struct class_device *class_dev, struct device *dev) +{ + /* XXX warning we should watch out for name collisions */ + strncpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE); + class_dev->class_id[BUS_ID_SIZE - 1] = '\0'; +} +static int +fw_setup_class_device(struct class_device **class_dev_p, + const char *fw_name, struct device *device) +{ + int retval = 0; + struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), + GFP_KERNEL); + struct class_device *class_dev = kmalloc(sizeof (struct class_device), + GFP_KERNEL); + + if (!fw_priv || !class_dev) { + retval = -ENOMEM; + goto error_kfree; + } + memset(fw_priv, 0, sizeof (*fw_priv)); + memset(class_dev, 0, sizeof (*class_dev)); + + init_completion(&fw_priv->completion); + memcpy(&fw_priv->attr_data, &firmware_attr_data_tmpl, + sizeof (firmware_attr_data_tmpl)); + + strncpy(&fw_priv->fw_id[0], fw_name, FIRMWARE_NAME_MAX); + fw_priv->fw_id[FIRMWARE_NAME_MAX - 1] = '\0'; + + fw_setup_class_device_id(class_dev, device); + class_dev->dev = device; + + fw_priv->timeout.function = firmware_class_timeout; + fw_priv->timeout.data = (u_long) fw_priv; + init_timer(&fw_priv->timeout); + + class_dev->class = &firmware_class; + class_set_devdata(class_dev, fw_priv); + retval = class_device_register(class_dev); + if (retval) { + printk(KERN_ERR "%s: class_device_register failed\n", + __FUNCTION__); + goto error_kfree; + } + + retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data); + if (retval) { + printk(KERN_ERR "%s: sysfs_create_bin_file failed\n", + __FUNCTION__); + goto error_unreg_class_dev; + } + + retval = class_device_create_file(class_dev, + &class_device_attr_loading); + if (retval) { + printk(KERN_ERR "%s: class_device_create_file failed\n", + __FUNCTION__); + goto error_remove_data; + } + + fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL); + if (!fw_priv->fw) { + printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", + __FUNCTION__); + retval = -ENOMEM; + goto error_remove_loading; + } + memset(fw_priv->fw, 0, sizeof (*fw_priv->fw)); + + goto out; + +error_remove_loading: + class_device_remove_file(class_dev, &class_device_attr_loading); +error_remove_data: + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); +error_unreg_class_dev: + class_device_unregister(class_dev); +error_kfree: + kfree(fw_priv); + kfree(class_dev); + *class_dev_p = NULL; +out: + *class_dev_p = class_dev; + return retval; +} +static void +fw_remove_class_device(struct class_device *class_dev) +{ + struct firmware_priv *fw_priv = class_get_devdata(class_dev); + + class_device_remove_file(class_dev, &class_device_attr_loading); + sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data); + class_device_unregister(class_dev); +} + +/** + * request_firmware: - request firmware to hotplug and wait for it + * Description: + * @firmware will be used to return a firmware image by the name + * of @name for device @device. + * + * Should be called from user context where sleeping is allowed. + * + * @name will be use as $FIRMWARE in the hotplug environment and + * should be distinctive enough not to be confused with any other + * firmware image for this or any other device. + **/ +int +request_firmware(const struct firmware **firmware, const char *name, + struct device *device) +{ + struct class_device *class_dev; + struct firmware_priv *fw_priv; + int retval; + + if (!firmware) + return -EINVAL; + + *firmware = NULL; + + retval = fw_setup_class_device(&class_dev, name, device); + if (retval) + goto out; + + fw_priv = class_get_devdata(class_dev); + + if (loading_timeout) { + fw_priv->timeout.expires = jiffies + loading_timeout * HZ; + add_timer(&fw_priv->timeout); + } + + wait_for_completion(&fw_priv->completion); + + del_timer(&fw_priv->timeout); + fw_remove_class_device(class_dev); + + if (fw_priv->fw->size && !fw_priv->abort) { + *firmware = fw_priv->fw; + } else { + retval = -ENOENT; + vfree(fw_priv->fw->data); + kfree(fw_priv->fw); + } + kfree(fw_priv); +out: + return retval; +} + +/** + * release_firmware: - release the resource associated with a firmware image + **/ +void +release_firmware(const struct firmware *fw) +{ + if (fw) { + vfree(fw->data); + kfree(fw); + } +} + +/** + * register_firmware: - provide a firmware image for later usage + * + * Description: + * Make sure that @data will be available by requesting firmware @name. + * + * Note: This will not be possible until some kind of persistence + * is available. + **/ +void +register_firmware(const char *name, const u8 *data, size_t size) +{ + /* This is meaningless without firmware caching, so until we + * decide if firmware caching is reasonable just leave it as a + * noop */ +} + +/* Async support */ +struct firmware_work { + struct work_struct work; + struct module *module; + const char *name; + struct device *device; + void *context; + void (*cont)(const struct firmware *fw, void *context); +}; + +static void +request_firmware_work_func(void *arg) +{ + struct firmware_work *fw_work = arg; + const struct firmware *fw; + if (!arg) + return; + request_firmware(&fw, fw_work->name, fw_work->device); + fw_work->cont(fw, fw_work->context); + release_firmware(fw); + module_put(fw_work->module); + kfree(fw_work); +} + +/** + * request_firmware_nowait: + * + * Description: + * Asynchronous variant of request_firmware() for contexts where + * it is not possible to sleep. + * + * @cont will be called asynchronously when the firmware request is over. + * + * @context will be passed over to @cont. + * + * @fw may be %NULL if firmware request fails. + * + **/ +int +request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)) +{ + struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), + GFP_ATOMIC); + if (!fw_work) + return -ENOMEM; + if (!try_module_get(module)) { + kfree(fw_work); + return -EFAULT; + } + + *fw_work = (struct firmware_work) { + .module = module, + .name = name, + .device = device, + .context = context, + .cont = cont, + }; + INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work); + + schedule_work(&fw_work->work); + return 0; +} + +static int __init +firmware_class_init(void) +{ + int error; + error = class_register(&firmware_class); + if (error) { + printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__); + } + error = class_create_file(&firmware_class, &class_attr_timeout); + if (error) { + printk(KERN_ERR "%s: class_create_file failed\n", + __FUNCTION__); + class_unregister(&firmware_class); + } + return error; + +} +static void __exit +firmware_class_exit(void) +{ + class_remove_file(&firmware_class, &class_attr_timeout); + class_unregister(&firmware_class); +} + +module_init(firmware_class_init); +module_exit(firmware_class_exit); + +EXPORT_SYMBOL(release_firmware); +EXPORT_SYMBOL(request_firmware); +EXPORT_SYMBOL(request_firmware_nowait); +EXPORT_SYMBOL(register_firmware); +EXPORT_SYMBOL(firmware_class); diff -Nru a/drivers/base/sys.c b/drivers/base/sys.c --- a/drivers/base/sys.c Wed Jun 11 15:42:05 2003 +++ b/drivers/base/sys.c Tue Jun 17 16:04:30 2003 @@ -74,6 +74,8 @@ sysfs_remove_file(&s->kobj,&a->attr); } +EXPORT_SYMBOL(sysdev_create_file); +EXPORT_SYMBOL(sysdev_remove_file); /* * declare system_subsys @@ -171,6 +173,9 @@ /* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; + /* But make sure we point to the right type for sysfs translation */ + sysdev->kobj.ktype = &ktype_sysdev; + /* set the kobject name */ snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d", cls->kset.kobj.name,sysdev->id); @@ -218,9 +223,6 @@ if (drv->remove) drv->remove(sysdev); } - - list_del_init(&sysdev->entry); - up_write(&system_subsys.rwsem); kobject_unregister(&sysdev->kobj); diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c --- a/drivers/block/cciss_scsi.c Mon May 12 07:33:45 2003 +++ b/drivers/block/cciss_scsi.c Mon Jun 2 17:42:21 2003 @@ -698,7 +698,7 @@ { struct Scsi_Host *sh; - sh = scsi_register(&cciss_driver_template, sizeof(struct ctlr_info *)); + sh = scsi_host_alloc(&cciss_driver_template, sizeof(struct ctlr_info *)); if (sh == NULL) return 0; @@ -1357,7 +1357,7 @@ if (sa->registered) { spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); scsi_remove_host(sa->scsi_host); - scsi_unregister(sa->scsi_host); + scsi_host_put(sa->scsi_host); spin_lock_irqsave(CCISS_LOCK(ctlr), flags); } diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Thu Jun 5 06:22:28 2003 +++ b/drivers/block/ll_rw_blk.c Mon Jun 2 18:32:46 2003 @@ -49,8 +49,6 @@ static int queue_nr_requests; unsigned long blk_max_low_pfn, blk_max_pfn; -int blk_nohighio = 0; - static wait_queue_head_t congestion_wqh[2]; /* @@ -2334,7 +2332,6 @@ EXPORT_SYMBOL(blk_queue_segment_boundary); EXPORT_SYMBOL(blk_queue_dma_alignment); EXPORT_SYMBOL(blk_rq_map_sg); -EXPORT_SYMBOL(blk_nohighio); EXPORT_SYMBOL(blk_dump_rq_flags); EXPORT_SYMBOL(submit_bio); EXPORT_SYMBOL(blk_phys_contig_segment); diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c --- a/drivers/char/moxa.c Wed Jun 11 12:32:40 2003 +++ b/drivers/char/moxa.c Tue Jun 17 20:34:45 2003 @@ -339,7 +339,6 @@ { int i, n, numBoards; struct moxa_str *ch; - int ret1, ret2; printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); moxaDriver = alloc_tty_driver(MAX_PORTS + 1); @@ -615,7 +614,7 @@ } ch->asyncflags |= ASYNC_CLOSING; - ch->cflag = *tty->termios->c_cflag; + ch->cflag = tty->termios->c_cflag; if (ch->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ diff -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c --- a/drivers/i2c/busses/i2c-ali15x3.c Tue May 6 07:26:13 2003 +++ b/drivers/i2c/busses/i2c-ali15x3.c Tue Jun 17 15:37:34 2003 @@ -177,17 +177,18 @@ if(force_addr) { dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n", ali15x3_smba); - if (PCIBIOS_SUCCESSFUL != - pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba)) - return -ENODEV; - if (PCIBIOS_SUCCESSFUL != - pci_read_config_word(ALI15X3_dev, SMBBA, &a)) - return -ENODEV; + if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, + SMBBA, + ali15x3_smba)) + goto error; + if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev, + SMBBA, &a)) + goto error; if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { /* make sure it works */ dev_err(&ALI15X3_dev->dev, "force address failed - not supported?\n"); - return -ENODEV; + goto error; } } /* check if whole device is enabled */ @@ -219,6 +220,9 @@ dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); return 0; +error: + release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); + return -ENODEV; } /* Internally used pause function */ diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c --- a/drivers/i2c/busses/i2c-i801.c Tue May 6 07:16:02 2003 +++ b/drivers/i2c/busses/i2c-i801.c Sun Jun 8 08:38:26 2003 @@ -27,6 +27,7 @@ 82801BA 2443 82801CA/CAM 2483 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported) + 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported) This driver supports several versions of Intel's I/O Controller Hubs (ICH). For SMBus support, they are similar to the PIIX4 and are part @@ -121,7 +122,8 @@ return -ENODEV; I801_dev = dev; - if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) + if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) || + (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3)) isich4 = 1; else isich4 = 0; @@ -584,6 +586,12 @@ .device = PCI_DEVICE_ID_INTEL_82801DB_3, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_82801EB_3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { 0, } }; diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig Fri Jun 6 00:32:42 2003 +++ b/drivers/i2c/chips/Kconfig Sat May 31 20:47:19 2003 @@ -62,6 +62,20 @@ in the lm_sensors package, which you can download at http://www.lm-sensors.nu +config SENSORS_LM78 + tristate " National Semiconductors LM78 and compatibles" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for National Semiconductor LM78, + LM78-J and LM79. This can also be built as a module which can be + inserted and removed while the kernel is running. + + The module will be called lm78. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + config SENSORS_VIA686A tristate " VIA686A" depends on I2C && EXPERIMENTAL diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile Fri Jun 6 00:31:31 2003 +++ b/drivers/i2c/chips/Makefile Mon Jun 16 04:31:33 2003 @@ -5,6 +5,7 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_LM75) += lm75.o +obj-$(CONFIG_SENSORS_LM78) += lm78.o obj-$(CONFIG_SENSORS_LM85) += lm85.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83781D) += w83781d.o diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c Sun May 25 17:00:00 2003 +++ b/drivers/i2c/chips/adm1021.c Sun Jun 15 03:28:02 2003 @@ -88,8 +88,8 @@ these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ /* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) +#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) /* Initial values */ @@ -172,8 +172,18 @@ show(remote_temp_max); show(remote_temp_hyst); show(remote_temp_input); -show(alarms); -show(die_code); + +#define show2(value) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + \ + adm1021_update_client(client); \ + return sprintf(buf, "%d\n", data->value); \ +} +show2(alarms); +show2(die_code); #define set(value, reg) \ static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/chips/lm78.c Sun Jun 8 14:37:59 2003 @@ -0,0 +1,895 @@ +/* + lm78.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998, 1999 Frodo Looijaard + + 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 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x2f, I2C_CLIENT_END }; +static unsigned int normal_isa[] = { 0x0290, I2C_CLIENT_ISA_END }; +static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_3(lm78, lm78j, lm79); + +/* Many LM78 constants specified below */ + +/* Length of ISA address segment */ +#define LM78_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define LM78_ADDR_REG_OFFSET 5 +#define LM78_DATA_REG_OFFSET 6 + +/* The LM78 registers */ +#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define LM78_REG_IN(nr) (0x20 + (nr)) + +#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) +#define LM78_REG_FAN(nr) (0x28 + (nr)) + +#define LM78_REG_TEMP 0x27 +#define LM78_REG_TEMP_OVER 0x39 +#define LM78_REG_TEMP_HYST 0x3a + +#define LM78_REG_ALARM1 0x41 +#define LM78_REG_ALARM2 0x42 + +#define LM78_REG_VID_FANDIV 0x47 + +#define LM78_REG_CONFIG 0x40 +#define LM78_REG_CHIPID 0x49 +#define LM78_REG_I2C_ADDR 0x48 + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. */ + +/* IN: mV, (0V to 4.08V) + REG: 16mV/bit */ +static inline u8 IN_TO_REG(unsigned long val) +{ + unsigned long nval = SENSORS_LIMIT(val, 0, 4080); + return (nval + 8) / 16; +} +#define IN_FROM_REG(val) ((val) * 16) + +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +static inline int FAN_FROM_REG(u8 val, int div) +{ + return val==0 ? -1 : val==255 ? 0 : 1350000/(val*div); +} + +/* TEMP: mC (-128C to +127C) + REG: 1C/bit, two's complement */ +static inline u8 TEMP_TO_REG(int val) +{ + int nval = SENSORS_LIMIT(val, -128000, 127000) ; + return nval<0 ? (nval-500)/1000+0x100 : (nval+500)/1000; +} + +static inline int TEMP_FROM_REG(u8 val) +{ + return (val>=0x80 ? val-0x100 : val) * 1000; +} + +/* VID: mV + REG: (see doc/vid) */ +static inline int VID_FROM_REG(u8 val) +{ + return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; +} + +/* ALARMS: chip-specific bitmask + REG: (same) */ +#define ALARMS_FROM_REG(val) (val) + +/* FAN DIV: 1, 2, 4, or 8 (defaults to 2) + REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */ +static inline u8 DIV_TO_REG(int val) +{ + return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1; +} +#define DIV_FROM_REG(val) (1 << (val)) + +/* Initial limits. To keep them sane, we use the 'standard' translation as + specified in the LM78 sheet. Use the config file to set better limits. */ +#define LM78_INIT_IN_0(vid) ((vid)==3500 ? 2800 : (vid)) +#define LM78_INIT_IN_1(vid) ((vid)==3500 ? 2800 : (vid)) +#define LM78_INIT_IN_2 3300 +#define LM78_INIT_IN_3 (((5000) * 100)/168) +#define LM78_INIT_IN_4 (((12000) * 10)/38) +#define LM78_INIT_IN_5 (((-12000) * -604)/2100) +#define LM78_INIT_IN_6 (((-5000) * -604)/909) + +#define LM78_INIT_IN_PERCENTAGE 10 + +#define LM78_INIT_IN_MIN_0(vid) (LM78_INIT_IN_0(vid) - \ + LM78_INIT_IN_0(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_0(vid) (LM78_INIT_IN_0(vid) + \ + LM78_INIT_IN_0(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_1(vid) (LM78_INIT_IN_1(vid) - \ + LM78_INIT_IN_1(vid) * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_1(vid) (LM78_INIT_IN_1(vid) + \ + LM78_INIT_IN_1(vid) * LM78_INIT_IN_PERCENTAGE / 100) + +#define LM78_INIT_IN_MIN_2 \ + (LM78_INIT_IN_2 - LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_2 \ + (LM78_INIT_IN_2 + LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_3 \ + (LM78_INIT_IN_3 - LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_3 \ + (LM78_INIT_IN_3 + LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_4 \ + (LM78_INIT_IN_4 - LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_4 \ + (LM78_INIT_IN_4 + LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_5 \ + (LM78_INIT_IN_5 - LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_5 \ + (LM78_INIT_IN_5 + LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MIN_6 \ + (LM78_INIT_IN_6 - LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) +#define LM78_INIT_IN_MAX_6 \ + (LM78_INIT_IN_6 + LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100) + +#define LM78_INIT_FAN_MIN_1 3000 +#define LM78_INIT_FAN_MIN_2 3000 +#define LM78_INIT_FAN_MIN_3 3000 + +#define LM78_INIT_TEMP_OVER 60000 +#define LM78_INIT_TEMP_HYST 50000 + +/* There are some complications in a module like this. First off, LM78 chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + LM78 chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the LM78 at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered LM78, we need to keep some data in memory. That + data is pointed to by lm78_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new lm78 client is + allocated. */ +struct lm78_data { + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[7]; /* Register value */ + u8 in_max[7]; /* Register value */ + u8 in_min[7]; /* Register value */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; /* Register value */ + u8 temp_over; /* Register value */ + u8 temp_hyst; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u16 alarms; /* Register encoding, combined */ +}; + + +static int lm78_attach_adapter(struct i2c_adapter *adapter); +static int lm78_detect(struct i2c_adapter *adapter, int address, int kind); +static int lm78_detach_client(struct i2c_client *client); + +static int lm78_read_value(struct i2c_client *client, u8 register); +static int lm78_write_value(struct i2c_client *client, u8 register, u8 value); +static void lm78_update_client(struct i2c_client *client); +static void lm78_init_client(struct i2c_client *client); + + +static struct i2c_driver lm78_driver = { + .owner = THIS_MODULE, + .name = "lm78", + .id = I2C_DRIVERID_LM78, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm78_attach_adapter, + .detach_client = lm78_detach_client, +}; + +/* 7 Voltages */ +static ssize_t show_in(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_min(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])); +} + +static ssize_t show_in_max(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])); +} + +static ssize_t set_in_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_min[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]); + return count; +} + +static ssize_t set_in_max(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->in_max[nr] = IN_TO_REG(val); + lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]); + return count; +} + +#define show_in_offset(offset) \ +static ssize_t \ + show_in##offset (struct device *dev, char *buf) \ +{ \ + return show_in(dev, buf, 0x##offset); \ +} \ +static DEVICE_ATTR(in_input##offset, S_IRUGO, \ + show_in##offset, NULL) \ +static ssize_t \ + show_in##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_in_min(dev, buf, 0x##offset); \ +} \ +static ssize_t \ + show_in##offset##_max (struct device *dev, char *buf) \ +{ \ + return show_in_max(dev, buf, 0x##offset); \ +} \ +static ssize_t set_in##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_min(dev, buf, count, 0x##offset); \ +} \ +static ssize_t set_in##offset##_max (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_in_max(dev, buf, count, 0x##offset); \ +} \ +static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, \ + show_in##offset##_min, set_in##offset##_min) \ +static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, \ + show_in##offset##_max, set_in##offset##_max) + +show_in_offset(0); +show_in_offset(1); +show_in_offset(2); +show_in_offset(3); +show_in_offset(4); +show_in_offset(5); +show_in_offset(6); + +/* Temperature */ +static ssize_t show_temp(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); +} + +static ssize_t show_temp_over(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); +} + +static ssize_t set_temp_over(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_over = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over); + return count; +} + +static ssize_t show_temp_hyst(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); +} + +static ssize_t set_temp_hyst(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + data->temp_hyst = TEMP_TO_REG(val); + lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst); + return count; +} + +static DEVICE_ATTR(temp_input, S_IRUGO, show_temp, NULL) +static DEVICE_ATTR(temp_max, S_IRUGO | S_IWUSR, + show_temp_over, set_temp_over) +static DEVICE_ATTR(temp_min, S_IRUGO | S_IWUSR, + show_temp_hyst, set_temp_hyst) + +/* 3 Fans */ +static ssize_t show_fan(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t show_fan_min(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])) ); +} + +static ssize_t set_fan_min(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +static ssize_t show_fan_div(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) ); +} + +/* Note: we save and restore the fan minimum here, because its value is + determined in part by the fan divisor. This follows the principle of + least suprise; the user doesn't expect the fan minimum to change just + because the divisor changed. */ +static ssize_t set_fan_div(struct device *dev, const char *buf, + size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + unsigned long min = FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr])); + unsigned long val = simple_strtoul(buf, NULL, 10); + int reg = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->fan_div[nr] = DIV_TO_REG(val); + switch (nr) { + case 0: + reg = (reg & 0xcf) | (data->fan_div[nr] << 4); + break; + case 1: + reg = (reg & 0x3f) | (data->fan_div[nr] << 6); + break; + } + lm78_write_value(client, LM78_REG_VID_FANDIV, reg); + data->fan_min[nr] = + FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); + return count; +} + +#define show_fan_offset(offset) \ +static ssize_t show_fan_##offset (struct device *dev, char *buf) \ +{ \ + return show_fan(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t show_fan_##offset##_min (struct device *dev, char *buf) \ +{ \ + return show_fan_min(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t show_fan_##offset##_div (struct device *dev, char *buf) \ +{ \ + return show_fan_div(dev, buf, 0x##offset - 1); \ +} \ +static ssize_t set_fan_##offset##_min (struct device *dev, \ + const char *buf, size_t count) \ +{ \ + return set_fan_min(dev, buf, count, 0x##offset - 1); \ +} \ +static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_fan_##offset, NULL) \ +static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, \ + show_fan_##offset##_min, set_fan_##offset##_min) + +static ssize_t set_fan_1_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 0) ; +} + +static ssize_t set_fan_2_div(struct device *dev, const char *buf, + size_t count) +{ + return set_fan_div(dev, buf, count, 1) ; +} + +show_fan_offset(1); +show_fan_offset(2); +show_fan_offset(3); + +/* Fan 3 divisor is locked in H/W */ +static DEVICE_ATTR(fan_div1, S_IRUGO | S_IWUSR, + show_fan_1_div, set_fan_1_div) +static DEVICE_ATTR(fan_div2, S_IRUGO | S_IWUSR, + show_fan_2_div, set_fan_2_div) +static DEVICE_ATTR(fan_div3, S_IRUGO, show_fan_3_div, NULL) + +/* VID */ +static ssize_t show_vid(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", VID_FROM_REG(data->vid)); +} +static DEVICE_ATTR(vid, S_IRUGO, show_vid, NULL); + +/* Alarms */ +static ssize_t show_alarms(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm78_data *data = i2c_get_clientdata(client); + lm78_update_client(client); + return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); +} +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); + +/* This function is called when: + * lm78_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm78_driver is still present) */ +static int lm78_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_ADAP_CLASS_SMBUS)) + return 0; + return i2c_detect(adapter, &addr_data, lm78_detect); +} + +/* This function is called by i2c_detect */ +int lm78_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i, err; + struct i2c_client *new_client; + struct lm78_data *data; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + + if (!is_isa && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -ENODEV; + goto ERROR0; + } + + /* Reserve the ISA region */ + if (is_isa) + if (!request_region(address, LM78_EXTENT, "lm78")) { + err = -EBUSY; + goto ERROR0; + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + err = -ENODEV; + goto ERROR1; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm78_{read,write}_value. */ + + if (!(new_client = kmalloc((sizeof(struct i2c_client)) + + sizeof(struct lm78_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR1; + } + memset(new_client, 0, sizeof(struct i2c_client) + + sizeof(struct lm78_data)); + + data = (struct lm78_data *) (new_client + 1); + if (is_isa) + init_MUTEX(&data->lock); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm78_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + if (kind < 0) { + if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) { + err = -ENODEV; + goto ERROR2; + } + if (!is_isa && (lm78_read_value( + new_client, LM78_REG_I2C_ADDR) != address)) { + err = -ENODEV; + goto ERROR2; + } + } + + /* Determine the chip type. */ + if (kind <= 0) { + i = lm78_read_value(new_client, LM78_REG_CHIPID); + if (i == 0x00 || i == 0x20) + kind = lm78; + else if (i == 0x40) + kind = lm78j; + else if ((i & 0xfe) == 0xc0) + kind = lm79; + else { + if (kind == 0) + printk(KERN_WARNING "lm78.o: Ignoring 'force' " + "parameter for unknown chip at " + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + err = -ENODEV; + goto ERROR2; + } + } + + if (kind == lm78) { + client_name = "LM78 chip"; + } else if (kind == lm78j) { + client_name = "LM78-J chip"; + } else if (kind == lm79) { + client_name = "LM79 chip"; + } else { + dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?", + kind); + err = -ENODEV; + goto ERROR2; + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR2; + + /* register sysfs hooks */ + device_create_file(&new_client->dev, &dev_attr_in_input0); + device_create_file(&new_client->dev, &dev_attr_in_min0); + device_create_file(&new_client->dev, &dev_attr_in_max0); + device_create_file(&new_client->dev, &dev_attr_in_input1); + device_create_file(&new_client->dev, &dev_attr_in_min1); + device_create_file(&new_client->dev, &dev_attr_in_max1); + device_create_file(&new_client->dev, &dev_attr_in_input2); + device_create_file(&new_client->dev, &dev_attr_in_min2); + device_create_file(&new_client->dev, &dev_attr_in_max2); + device_create_file(&new_client->dev, &dev_attr_in_input3); + device_create_file(&new_client->dev, &dev_attr_in_min3); + device_create_file(&new_client->dev, &dev_attr_in_max3); + device_create_file(&new_client->dev, &dev_attr_in_input4); + device_create_file(&new_client->dev, &dev_attr_in_min4); + device_create_file(&new_client->dev, &dev_attr_in_max4); + device_create_file(&new_client->dev, &dev_attr_in_input5); + device_create_file(&new_client->dev, &dev_attr_in_min5); + device_create_file(&new_client->dev, &dev_attr_in_max5); + device_create_file(&new_client->dev, &dev_attr_in_input6); + device_create_file(&new_client->dev, &dev_attr_in_min6); + device_create_file(&new_client->dev, &dev_attr_in_max6); + device_create_file(&new_client->dev, &dev_attr_temp_input); + device_create_file(&new_client->dev, &dev_attr_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp_max); + device_create_file(&new_client->dev, &dev_attr_fan_input1); + device_create_file(&new_client->dev, &dev_attr_fan_min1); + device_create_file(&new_client->dev, &dev_attr_fan_div1); + device_create_file(&new_client->dev, &dev_attr_fan_input2); + device_create_file(&new_client->dev, &dev_attr_fan_min2); + device_create_file(&new_client->dev, &dev_attr_fan_div2); + device_create_file(&new_client->dev, &dev_attr_fan_input3); + device_create_file(&new_client->dev, &dev_attr_fan_min3); + device_create_file(&new_client->dev, &dev_attr_fan_div3); + device_create_file(&new_client->dev, &dev_attr_alarms); + device_create_file(&new_client->dev, &dev_attr_vid); + + /* Initialize the LM78 chip */ + lm78_init_client(new_client); + return 0; + +ERROR2: + kfree(new_client); +ERROR1: + if (is_isa) + release_region(address, LM78_EXTENT); +ERROR0: + return err; +} + +static int lm78_detach_client(struct i2c_client *client) +{ + int err; + + /* release ISA region first */ + if(i2c_is_isa_client(client)) + release_region(client->addr, LM78_EXTENT); + + /* now it's safe to scrap the rest */ + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; +} + +/* The SMBus locks itself, but ISA access must be locked explicitely! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_read_value(struct i2c_client *client, u8 reg) +{ + int res; + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + res = inb_p(client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return res; + } else + return i2c_smbus_read_byte_data(client, reg); +} + +/* The SMBus locks itself, but ISA access muse be locked explicitely! + We don't want to lock the whole ISA bus, so we lock each client + separately. + We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, + would slow down the LM78 access and should not be necessary. + There are some ugly typecasts here, but the good new is - they should + nowhere else be necessary! */ +static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + if (i2c_is_isa_client(client)) { + struct lm78_data *data = i2c_get_clientdata(client); + down(&data->lock); + outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET); + outb_p(value, client->addr + LM78_DATA_REG_OFFSET); + up(&data->lock); + return 0; + } else + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM78. It should set limits, etc. */ +static void lm78_init_client(struct i2c_client *client) +{ + struct lm78_data *data = i2c_get_clientdata(client); + int vid; + + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + lm78_write_value(client, LM78_REG_CONFIG, 0x80); + + vid = lm78_read_value(client, LM78_REG_VID_FANDIV) & 0x0f; + if (data->type == lm79) + vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & 0x01) << 4; + else + vid |= 0x10; + vid = VID_FROM_REG(vid); + + lm78_write_value(client, LM78_REG_IN_MIN(0), + IN_TO_REG(LM78_INIT_IN_MIN_0(vid))); + lm78_write_value(client, LM78_REG_IN_MAX(0), + IN_TO_REG(LM78_INIT_IN_MAX_0(vid))); + lm78_write_value(client, LM78_REG_IN_MIN(1), + IN_TO_REG(LM78_INIT_IN_MIN_1(vid))); + lm78_write_value(client, LM78_REG_IN_MAX(1), + IN_TO_REG(LM78_INIT_IN_MAX_1(vid))); + lm78_write_value(client, LM78_REG_IN_MIN(2), + IN_TO_REG(LM78_INIT_IN_MIN_2)); + lm78_write_value(client, LM78_REG_IN_MAX(2), + IN_TO_REG(LM78_INIT_IN_MAX_2)); + lm78_write_value(client, LM78_REG_IN_MIN(3), + IN_TO_REG(LM78_INIT_IN_MIN_3)); + lm78_write_value(client, LM78_REG_IN_MAX(3), + IN_TO_REG(LM78_INIT_IN_MAX_3)); + lm78_write_value(client, LM78_REG_IN_MIN(4), + IN_TO_REG(LM78_INIT_IN_MIN_4)); + lm78_write_value(client, LM78_REG_IN_MAX(4), + IN_TO_REG(LM78_INIT_IN_MAX_4)); + lm78_write_value(client, LM78_REG_IN_MIN(5), + IN_TO_REG(LM78_INIT_IN_MIN_5)); + lm78_write_value(client, LM78_REG_IN_MAX(5), + IN_TO_REG(LM78_INIT_IN_MAX_5)); + lm78_write_value(client, LM78_REG_IN_MIN(6), + IN_TO_REG(LM78_INIT_IN_MIN_6)); + lm78_write_value(client, LM78_REG_IN_MAX(6), + IN_TO_REG(LM78_INIT_IN_MAX_6)); + lm78_write_value(client, LM78_REG_FAN_MIN(0), + FAN_TO_REG(LM78_INIT_FAN_MIN_1, 2)); + lm78_write_value(client, LM78_REG_FAN_MIN(1), + FAN_TO_REG(LM78_INIT_FAN_MIN_2, 2)); + lm78_write_value(client, LM78_REG_FAN_MIN(2), + FAN_TO_REG(LM78_INIT_FAN_MIN_3, 2)); + lm78_write_value(client, LM78_REG_TEMP_OVER, + TEMP_TO_REG(LM78_INIT_TEMP_OVER)); + lm78_write_value(client, LM78_REG_TEMP_HYST, + TEMP_TO_REG(LM78_INIT_TEMP_HYST)); + + /* Start monitoring */ + lm78_write_value(client, LM78_REG_CONFIG, + (lm78_read_value(client, LM78_REG_CONFIG) & 0xf7) + | 0x01); + +} + +static void lm78_update_client(struct i2c_client *client) +{ + struct lm78_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + + dev_dbg(&client->dev, "Starting lm78 update\n"); + + for (i = 0; i <= 6; i++) { + data->in[i] = + lm78_read_value(client, LM78_REG_IN(i)); + data->in_min[i] = + lm78_read_value(client, LM78_REG_IN_MIN(i)); + data->in_max[i] = + lm78_read_value(client, LM78_REG_IN_MAX(i)); + } + for (i = 0; i < 3; i++) { + data->fan[i] = + lm78_read_value(client, LM78_REG_FAN(i)); + data->fan_min[i] = + lm78_read_value(client, LM78_REG_FAN_MIN(i)); + } + data->temp = lm78_read_value(client, LM78_REG_TEMP); + data->temp_over = + lm78_read_value(client, LM78_REG_TEMP_OVER); + data->temp_hyst = + lm78_read_value(client, LM78_REG_TEMP_HYST); + i = lm78_read_value(client, LM78_REG_VID_FANDIV); + data->vid = i & 0x0f; + if (data->type == lm79) + data->vid |= + (lm78_read_value(client, LM78_REG_CHIPID) & + 0x01) << 4; + else + data->vid |= 0x10; + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = lm78_read_value(client, LM78_REG_ALARM1) + + (lm78_read_value(client, LM78_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + + data->fan_div[2] = 1; + } + + up(&data->update_lock); +} + +static int __init sm_lm78_init(void) +{ + return i2c_add_driver(&lm78_driver); +} + +static void __exit sm_lm78_exit(void) +{ + i2c_del_driver(&lm78_driver); +} + + + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("LM78, LM78-J and LM79 driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_lm78_init); +module_exit(sm_lm78_exit); diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c --- a/drivers/i2c/chips/lm85.c Fri Jun 6 00:28:48 2003 +++ b/drivers/i2c/chips/lm85.c Thu Jun 12 02:38:16 2003 @@ -148,20 +148,17 @@ #define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from)) #define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)) #define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n])) -/* #define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0)) -*/ -#define INS_FROM_REG(n,val) ( ( (val*4*lm85_scaling[n]) + (192*4/2) ) / (192*4) ) /* FAN speed is measured using 90kHz clock */ #define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) #define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) -/* Temperature is reported in .01 degC increments */ -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+50)/100,-127,127)) -#define TEMPEXT_FROM_REG(val,ext) ((val)*100 + (ext)*25) +/* Temperature is reported in .001 degC increments */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,-127,127)) +#define TEMPEXT_FROM_REG(val,ext) ((val)*1000 + (ext)*250) #define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0)) -#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127)) +#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/250,-127,127)) #define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) #define PWM_FROM_REG(val) (val) @@ -437,10 +434,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->fan_min[nr] = FAN_TO_REG(val); lm85_write_value(client, LM85_REG_FAN_MIN(nr), data->fan_min[nr]); + up(&data->update_lock); return count; } @@ -528,10 +528,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->pwm[nr] = PWM_TO_REG(val); lm85_write_value(client, LM85_REG_PWM(nr), data->pwm[nr]); + up(&data->update_lock); return count; } static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) @@ -590,10 +593,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->in_min[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MIN(nr), data->in_min[nr]); + up(&data->update_lock); return count; } static ssize_t show_in_max(struct device *dev, char *buf, int nr) @@ -609,10 +615,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->in_max[nr] = INS_TO_REG(nr, val); lm85_write_value(client, LM85_REG_IN_MAX(nr), data->in_max[nr]); + up(&data->update_lock); return count; } #define show_in_reg(offset) \ @@ -673,10 +682,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->temp_min[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MIN(nr), data->temp_min[nr]); + up(&data->update_lock); return count; } static ssize_t show_temp_max(struct device *dev, char *buf, int nr) @@ -692,10 +704,13 @@ { struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); + int val; - int val = simple_strtol(buf, NULL, 10); + down(&data->update_lock); + val = simple_strtol(buf, NULL, 10); data->temp_max[nr] = TEMP_TO_REG(val); lm85_write_value(client, LM85_REG_TEMP_MAX(nr), data->temp_max[nr]); + up(&data->update_lock); return count; } #define show_temp_reg(offset) \ diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c Wed Jun 4 18:37:11 2003 +++ b/drivers/i2c/chips/w83781d.c Mon Jun 16 16:36:26 2003 @@ -28,6 +28,7 @@ asb100 "bach" (type_name = as99127f) 0x30 0x0694 yes no w83781d 7 3 0 3 0x10 0x5ca3 yes yes w83627hf 9 3 2 3 0x20 0x5ca3 yes yes(LPC) + w83627thf 9 3 2 3 0x90 0x5ca3 no yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) @@ -299,8 +300,8 @@ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - struct i2c_client *lm75; /* for secondary I2C addresses */ - /* pointer to array of 2 subclients */ + struct i2c_client *lm75[2]; /* for secondary I2C addresses */ + /* array of 2 pointers to subclients */ u8 in[9]; /* Register value - 8 & 9 for 782D only */ u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ @@ -1043,12 +1044,12 @@ const char *client_name; struct w83781d_data *data = i2c_get_clientdata(new_client); - if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), - GFP_KERNEL))) { + data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[0])) { err = -ENOMEM; goto ERROR_SC_0; } - memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); + memset(data->lm75[0], 0x00, sizeof (struct i2c_client)); id = i2c_adapter_id(adapter); @@ -1066,25 +1067,33 @@ w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, (force_subclients[2] & 0x07) | ((force_subclients[3] & 0x07) << 4)); - data->lm75[0].addr = force_subclients[2]; + data->lm75[0]->addr = force_subclients[2]; } else { val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); + data->lm75[0]->addr = 0x48 + (val1 & 0x07); } if (kind != w83783s) { + + data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!(data->lm75[1])) { + err = -ENOMEM; + goto ERROR_SC_1; + } + memset(data->lm75[1], 0x0, sizeof(struct i2c_client)); + if (force_subclients[0] == id && force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; + data->lm75[1]->addr = force_subclients[3]; } else { - data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); + data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07); } - if (data->lm75[0].addr == data->lm75[1].addr) { + if (data->lm75[0]->addr == data->lm75[1]->addr) { dev_err(&new_client->dev, "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); + data->lm75[0]->addr); err = -EBUSY; - goto ERROR_SC_1; + goto ERROR_SC_2; } } @@ -1103,19 +1112,19 @@ for (i = 0; i <= 1; i++) { /* store all data in w83781d */ - i2c_set_clientdata(&data->lm75[i], NULL); - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strlcpy(data->lm75[i].dev.name, client_name, + i2c_set_clientdata(data->lm75[i], NULL); + data->lm75[i]->adapter = adapter; + data->lm75[i]->driver = &w83781d_driver; + data->lm75[i]->flags = 0; + strlcpy(data->lm75[i]->dev.name, client_name, DEVICE_NAME_SIZE); - if ((err = i2c_attach_client(&(data->lm75[i])))) { + if ((err = i2c_attach_client(data->lm75[i]))) { dev_err(&new_client->dev, "Subclient %d " "registration at address 0x%x " - "failed.\n", i, data->lm75[i].addr); + "failed.\n", i, data->lm75[i]->addr); if (i == 1) - goto ERROR_SC_2; - goto ERROR_SC_1; + goto ERROR_SC_3; + goto ERROR_SC_2; } if (kind == w83783s) break; @@ -1124,10 +1133,14 @@ return 0; /* Undo inits in case of errors */ +ERROR_SC_3: + i2c_detach_client(data->lm75[0]); ERROR_SC_2: - i2c_detach_client(&(data->lm75[0])); + if (NULL != data->lm75[1]) + kfree(data->lm75[1]); ERROR_SC_1: - kfree(data->lm75); + if (NULL != data->lm75[0]) + kfree(data->lm75[0]); ERROR_SC_0: return err; } @@ -1273,7 +1286,7 @@ kind = w83782d; else if (val1 == 0x40 && vendid == winbond && !is_isa) kind = w83783s; - else if (val1 == 0x20 && vendid == winbond) + else if ((val1 == 0x20 || val1 == 0x90) && vendid == winbond) kind = w83627hf; else if (val1 == 0x30 && vendid == asus && !is_isa) kind = as99127f; @@ -1297,7 +1310,10 @@ } else if (kind == w83783s) { client_name = "W83783S chip"; } else if (kind == w83627hf) { - client_name = "W83627HF chip"; + if (val1 == 0x90) + client_name = "W83627THF chip"; + else + client_name = "W83627HF chip"; } else if (kind == as99127f) { client_name = "AS99127F chip"; } else if (kind == w83697hf) { @@ -1326,7 +1342,8 @@ kind, new_client))) goto ERROR3; } else { - data->lm75 = NULL; + data->lm75[0] = NULL; + data->lm75[1] = NULL; } device_create_file_in(new_client, 0); @@ -1409,20 +1426,11 @@ static int w83781d_detach_client(struct i2c_client *client) { - struct w83781d_data *data = i2c_get_clientdata(client); int err; - /* release ISA region or I2C subclients first */ - if (i2c_is_isa_client(client)) { + if (i2c_is_isa_client(client)) release_region(client->addr, W83781D_EXTENT); - } else { - i2c_detach_client(&data->lm75[0]); - if (data->type != w83783s) - i2c_detach_client(&data->lm75[1]); - kfree(data->lm75); - } - /* now it's safe to scrap the rest */ if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); @@ -1484,7 +1492,7 @@ res = i2c_smbus_read_byte_data(client, reg & 0xff); } else { /* switch to subclient */ - cl = &data->lm75[bank - 1]; + cl = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ @@ -1555,7 +1563,7 @@ value & 0xff); } else { /* switch to subclient */ - cl = &data->lm75[bank - 1]; + cl = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x52: /* CONFIG */ diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c --- a/drivers/ieee1394/sbp2.c Wed May 28 17:50:03 2003 +++ b/drivers/ieee1394/sbp2.c Mon Jun 2 17:42:21 2003 @@ -707,7 +707,7 @@ return hi; /* Register our host with the SCSI stack. */ - scsi_host = scsi_register (&scsi_driver_template, 0); + scsi_host = scsi_host_alloc(&scsi_driver_template, 0); if (!scsi_host) { SBP2_ERR("failed to register scsi host"); return NULL; @@ -716,7 +716,7 @@ hi = hpsb_create_hostinfo(&sbp2_highlevel, host, sizeof(*hi)); if (!hi) { SBP2_ERR("failed to allocate hostinfo"); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); } hpsb_set_hostinfo_key(&sbp2_highlevel, host, (unsigned long)scsi_host); @@ -732,7 +732,7 @@ * enabled (scsi-host uses classdata member of the device). */ if (scsi_add_host(hi->scsi_host, NULL)) { SBP2_ERR("failed to add scsi host"); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); hpsb_destroy_hostinfo(&sbp2_highlevel, host); } @@ -753,7 +753,7 @@ if (hi) { scsi_remove_host(hi->scsi_host); - scsi_unregister(hi->scsi_host); + scsi_host_put(hi->scsi_host); } } diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c --- a/drivers/input/serio/ambakmi.c Tue May 13 09:30:32 2003 +++ b/drivers/input/serio/ambakmi.c Wed Jun 18 15:44:25 2003 @@ -1,7 +1,7 @@ /* - * linux/drivers/input/serio/amba_kmi.c + * linux/drivers/input/serio/ambakmi.c * - * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2000-2003 Deep Blue Solutions Ltd. * Copyright (C) 2002 Russell King. * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,7 @@ #include #include +#include #include #define KMI_BASE (kmi->base) @@ -28,11 +29,10 @@ struct amba_kmi_port { struct serio io; struct amba_kmi_port *next; - void *base; + unsigned char *base; unsigned int irq; unsigned int divisor; - char name[32]; - char phys[16]; + unsigned int open; struct resource *res; }; @@ -73,7 +73,7 @@ writeb(kmi->divisor, KMICLKDIV); writeb(KMICR_EN, KMICR); - ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->phys, kmi); + ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->io.phys, kmi); if (ret) { printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); writeb(0, KMICR); @@ -94,9 +94,7 @@ free_irq(kmi->irq, kmi); } -static struct amba_kmi_port *list; - -static int __init amba_kmi_init_one(char *type, unsigned long base, int irq, int nr) +static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; @@ -110,58 +108,83 @@ kmi->io.write = amba_kmi_write; kmi->io.open = amba_kmi_open; kmi->io.close = amba_kmi_close; - kmi->io.name = kmi->name; - kmi->io.phys = kmi->phys; + kmi->io.name = dev->dev.name; + kmi->io.phys = dev->dev.bus_id; kmi->io.driver = kmi; - snprintf(kmi->name, sizeof(kmi->name), "AMBA KMI PS/2 %s port", type); - snprintf(kmi->phys, sizeof(kmi->phys), "amba/serio%d", nr); - - kmi->res = request_mem_region(base, KMI_SIZE, kmi->phys); + kmi->res = request_mem_region(dev->res.start, KMI_SIZE, kmi->io.phys); if (!kmi->res) { kfree(kmi); return -EBUSY; } - kmi->base = ioremap(base, KMI_SIZE); + kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { release_resource(kmi->res); kfree(kmi); return -ENOMEM; } - kmi->irq = irq; + kmi->irq = dev->irq; kmi->divisor = 24 / 8 - 1; - kmi->next = list; - list = kmi; + amba_set_drvdata(dev, kmi); serio_register_port(&kmi->io); return 0; } -static int __init amba_kmi_init(void) +static int amba_kmi_remove(struct amba_device *dev) { - amba_kmi_init_one("keyboard", KMI0_BASE, IRQ_KMIINT0, 0); - amba_kmi_init_one("mouse", KMI1_BASE, IRQ_KMIINT1, 1); + struct amba_kmi_port *kmi = amba_get_drvdata(dev); + + amba_set_drvdata(dev, NULL); + + serio_unregister_port(&kmi->io); + iounmap(kmi->base); + release_resource(kmi->res); + kfree(kmi); return 0; } -static void __exit amba_kmi_exit(void) +static int amba_kmi_resume(struct amba_device *dev, u32 level) { - struct amba_kmi_port *kmi, *next; + struct amba_kmi_port *kmi = amba_get_drvdata(dev); - kmi = list; - while (kmi) { - next = kmi->next; + if (level == RESUME_ENABLE) { + /* kick the serio layer to rescan this port */ + serio_rescan(&kmi->io); + } - serio_unregister_port(&kmi->io); - iounmap(kmi->base); - release_resource(kmi->res); - kfree(kmi); + return 0; +} - kmi = next; - } +static struct amba_id amba_kmi_idtable[] = { + { + .id = 0x00041050, + .mask = 0x000fffff, + }, + { 0, 0 } +}; + +static struct amba_driver ambakmi_driver = { + .drv = { + .name = "kmi-pl050", + }, + .id_table = amba_kmi_idtable, + .probe = amba_kmi_probe, + .remove = amba_kmi_remove, + .resume = amba_kmi_resume, +}; + +static int __init amba_kmi_init(void) +{ + return amba_driver_register(&ambakmi_driver); +} + +static void __exit amba_kmi_exit(void) +{ + return amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); diff -Nru a/drivers/isdn/act2000/Makefile b/drivers/isdn/act2000/Makefile --- a/drivers/isdn/act2000/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/act2000/Makefile Fri May 23 11:27:32 2003 @@ -6,4 +6,4 @@ # Multipart objects. -act2000-objs := module.o capi.o act2000_isa.o +act2000-y := module.o capi.o act2000_isa.o diff -Nru a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile --- a/drivers/isdn/capi/Makefile Mon Feb 3 14:19:36 2003 +++ b/drivers/isdn/capi/Makefile Fri May 23 11:27:32 2003 @@ -13,4 +13,3 @@ kernelcapi-y := kcapi.o capiutil.o capilib.o kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o -kernelcapi-objs := $(kernelcapi-y) diff -Nru a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile --- a/drivers/isdn/divert/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/divert/Makefile Fri May 23 11:27:32 2003 @@ -6,4 +6,4 @@ # Multipart objects. -dss1_divert-objs := isdn_divert.o divert_procfs.o divert_init.o +dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o diff -Nru a/drivers/isdn/eicon/Makefile b/drivers/isdn/eicon/Makefile --- a/drivers/isdn/eicon/Makefile Mon Feb 3 14:19:36 2003 +++ b/drivers/isdn/eicon/Makefile Fri May 23 11:27:32 2003 @@ -7,15 +7,13 @@ # Multipart objects. -eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \ - eicon_io.o -divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \ - fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o +eicon-y := eicon_mod.o eicon_isa.o eicon_pci.o \ + eicon_idi.o eicon_io.o +eicon-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ + xlog.o kprintf.o fpga.o fourbri.o lincfg.o \ + linchr.o linsys.o linio.o -# Optional parts of multipart objects. +divas-y := common.o idi.o bri.o pri.o log.o xlog.o \ + kprintf.o fpga.o fourbri.o lincfg.o \ + linchr.o linsys.o linio.o Divas_mod.o -eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \ - xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \ - linsys.o linio.o - -eicon-objs += $(eicon-objs-y) diff -Nru a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c --- a/drivers/isdn/eicon/eicon_isa.c Sun Oct 6 18:00:18 2002 +++ b/drivers/isdn/eicon/eicon_isa.c Fri May 23 11:28:53 2003 @@ -123,7 +123,7 @@ int eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) { int tmp; - int timeout; + unsigned long timeout; eicon_isa_codebuf cbuf; unsigned char *code; eicon_isa_boot *boot; @@ -300,7 +300,7 @@ eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) { eicon_isa_boot *boot; int tmp; - int timeout; + unsigned long timeout; int j; eicon_isa_codebuf cbuf; unsigned char *code; diff -Nru a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c --- a/drivers/isdn/hardware/avm/b1pci.c Thu May 22 19:22:14 2003 +++ b/drivers/isdn/hardware/avm/b1pci.c Fri May 23 11:54:06 2003 @@ -111,7 +111,7 @@ cinfo->capi_ctrl.procinfo = b1pci_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; + cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { @@ -239,6 +239,7 @@ goto err_unmap; } + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "b1pciv4"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1dma_register_appl; @@ -249,7 +250,6 @@ cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff -Nru a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c --- a/drivers/isdn/hardware/avm/b1pcmcia.c Thu May 22 19:22:14 2003 +++ b/drivers/isdn/hardware/avm/b1pcmcia.c Fri May 23 11:54:06 2003 @@ -95,6 +95,7 @@ b1_reset(card->port); b1_getrevision(card); + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "b1pcmcia"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1_register_appl; @@ -105,7 +106,6 @@ cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff -Nru a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c --- a/drivers/isdn/hardware/avm/t1pci.c Thu May 22 19:22:14 2003 +++ b/drivers/isdn/hardware/avm/t1pci.c Fri May 23 11:54:06 2003 @@ -109,6 +109,7 @@ goto err_unmap; } + cinfo->capi_ctrl.owner = THIS_MODULE; cinfo->capi_ctrl.driver_name = "t1pci"; cinfo->capi_ctrl.driverdata = cinfo; cinfo->capi_ctrl.register_appl = b1dma_register_appl; @@ -119,7 +120,6 @@ cinfo->capi_ctrl.procinfo = t1pci_procinfo; cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc; strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; retval = attach_capi_ctr(&cinfo->capi_ctrl); if (retval) { diff -Nru a/drivers/isdn/hardware/eicon/Makefile b/drivers/isdn/hardware/eicon/Makefile --- a/drivers/isdn/hardware/eicon/Makefile Mon Feb 3 14:19:36 2003 +++ b/drivers/isdn/hardware/eicon/Makefile Fri May 23 11:27:32 2003 @@ -1,24 +1,24 @@ # Makefile for the Eicon DIVA ISDN drivers. +# Each configuration option enables a list of files. + +obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o +obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o +obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o +obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o + # Multipart objects. -divas-objs := divasmain.o divasfunc.o di.o io.o istream.o diva.o dlist.o divasproc.o diva_dma.o -divacapi-objs := capimain.o capifunc.o message.o capidtmf.o -divadidd-objs := diva_didd.o diddfunc.o dadapter.o -diva_mnt-objs := divamnt.o mntfunc.o debug.o maintidi.o -diva_idi-objs := divasi.o idifunc.o um_idi.o dqueue.o dlist.o - -# Optional parts of multipart objects. - -divas-objs-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o -divas-objs-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o -divas-objs-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o +divas-y := divasmain.o divasfunc.o di.o io.o istream.o \ + diva.o dlist.o divasproc.o diva_dma.o +divas-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o +divas-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o +divas-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o -divas-objs += $(sort $(divas-objs-y)) +divacapi-y := capimain.o capifunc.o message.o capidtmf.o -# Each configuration option enables a list of files. +divadidd-y := diva_didd.o diddfunc.o dadapter.o + +diva_mnt-y := divamnt.o mntfunc.o debug.o maintidi.o -obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o -obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o -obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o -obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o +diva_idi-y := divasi.o idifunc.o um_idi.o dqueue.o dlist.o diff -Nru a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile --- a/drivers/isdn/hisax/Makefile Mon Feb 3 14:19:36 2003 +++ b/drivers/isdn/hisax/Makefile Fri May 23 11:27:32 2003 @@ -17,47 +17,45 @@ # Multipart objects. -hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \ - st5481_hdlc.o -hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o cert.o +hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ + st5481_b.o st5481_hdlc.o -# Optional parts of multipart objects. -hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o -hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o -hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o +hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ + lmgr.o q931.o callc.o fsm.o cert.o +hisax-$(CONFIG_HISAX_EURO) += l3dss1.o +hisax-$(CONFIG_HISAX_NI1) += l3ni1.o +hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o -hisax-objs-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o -hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o -hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o -hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o isar.o -hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o -hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o -hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o -hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o -hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o -hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o -hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o -hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o -hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o -hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o -hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o -#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o - -hisax-objs += $(hisax-objs-y) +hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o +hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o +hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o +hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o \ + isar.o +hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o +hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o +hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o +hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o +hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o +hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o +hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o +hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o +hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o +hisax-$(CONFIG_HISAX_W6692) += w6692.o +hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o +#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o CERT := $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?) CFLAGS_cert.o := -DCERTIFICATION=$(CERT) diff -Nru a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c --- a/drivers/isdn/hisax/avma1_cs.c Wed May 28 08:01:08 2003 +++ b/drivers/isdn/hisax/avma1_cs.c Wed Jun 4 09:26:28 2003 @@ -153,6 +153,8 @@ /* Initialize the dev_link_t structure */ link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) + return NULL; memset(link, 0, sizeof(struct dev_link_t)); link->release.function = &avma1cs_release; link->release.data = (u_long)link; @@ -186,6 +188,10 @@ /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + kfree(link); + return NULL; + } memset(local, 0, sizeof(local_info_t)); link->priv = local; diff -Nru a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile --- a/drivers/isdn/hysdn/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/hysdn/Makefile Fri May 23 11:27:32 2003 @@ -2,15 +2,10 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_HYSDN) += hysdn.o +obj-$(CONFIG_HYSDN) += hysdn.o # Multipart objects. -hysdn-objs := hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o \ - hysdn_sched.o hysdn_net.o hysdn_init.o - -# Optional parts of multipart objects. - -hysdn-objs-$(CONFIG_HYSDN_CAPI) += hycapi.o - -hysdn-objs += $(hysdn-objs-y) +hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \ + hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o +hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o diff -Nru a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c --- a/drivers/isdn/hysdn/hysdn_proclog.c Mon Sep 2 12:15:36 2002 +++ b/drivers/isdn/hysdn/hysdn_proclog.c Fri May 23 11:28:53 2003 @@ -98,7 +98,8 @@ { struct log_data *ib; struct procdata *pd = card->proclog; - int i, flags; + int i; + unsigned long flags; if (!pd) return; @@ -300,7 +301,8 @@ struct log_data *inf; struct procdata *pd; hysdn_card *card; - int flags, retval = 0; + int retval = 0; + unsigned long flags; lock_kernel(); diff -Nru a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile --- a/drivers/isdn/i4l/Makefile Mon Feb 3 14:19:36 2003 +++ b/drivers/isdn/i4l/Makefile Fri May 23 11:27:32 2003 @@ -2,25 +2,18 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_ISDN) += isdn.o -obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o +obj-$(CONFIG_ISDN) += isdn.o +obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o # Multipart objects. -isdn-objs := isdn_net_lib.o \ - isdn_fsm.o \ - isdn_tty.o isdn_v110.o \ - isdn_common.o \ - -# Optional parts of multipart objects. - -isdn-objs-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o -isdn-objs-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o -isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o -isdn-objs-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o -isdn-objs-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o -isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o -isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o -isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o - -isdn-objs += $(isdn-objs-y) +isdn-y := isdn_net_lib.o isdn_fsm.o isdn_tty.o \ + isdn_v110.o isdn_common.o +isdn-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o +isdn-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o +isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o +isdn-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o +isdn-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o +isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o +isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o +isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o diff -Nru a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c --- a/drivers/isdn/i4l/isdn_bsdcomp.c Wed Oct 16 09:14:51 2002 +++ b/drivers/isdn/i4l/isdn_bsdcomp.c Wed Jun 18 21:40:13 2003 @@ -300,7 +300,6 @@ * Finally release the structure itself. */ kfree (db); - MOD_DEC_USE_COUNT; } } @@ -355,8 +354,6 @@ return NULL; } - MOD_INC_USE_COUNT; - /* * If this is the compression buffer then there is no length data. * For decompression, the length information is needed as well. @@ -907,6 +904,7 @@ *************************************************************/ static struct isdn_ppp_compressor ippp_bsd_compress = { + .owner = THIS_MODULE, .num = CI_BSD_COMPRESS, .alloc = bsd_alloc, .free = bsd_free, diff -Nru a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c --- a/drivers/isdn/i4l/isdn_ppp_ccp.c Tue Feb 25 01:39:03 2003 +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c Wed Jun 18 21:56:55 2003 @@ -259,11 +259,14 @@ { int id; - if (ccp->comp_stat) + if (ccp->comp_stat) { ccp->compressor->free(ccp->comp_stat); - if (ccp->decomp_stat) + module_put(ccp->compressor->owner); + } + if (ccp->decomp_stat) { ccp->decompressor->free(ccp->decomp_stat); - + module_put(ccp->decompressor->owner); + } for (id = 0; id < 256; id++) { if (ccp->reset->rs[id]) ippp_ccp_reset_free_state(ccp, id); @@ -553,13 +556,14 @@ } } -static struct isdn_ppp_compressor *ipc_head = NULL; +static LIST_HEAD(ipc_head); +static spinlock_t ipc_head_lock; int ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, struct isdn_ppp_comp_data *data) { - struct isdn_ppp_compressor *ipc = ipc_head; + struct isdn_ppp_compressor *ipc; int ret; void *stat; int num = data->num; @@ -568,34 +572,48 @@ printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); - for (ipc = ipc_head; ipc; ipc = ipc->next) { - if (ipc->num != num) - continue; - - stat = ipc->alloc(data); - if (!stat) { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } - ret = ipc->init(stat, data, unit, 0); - if(!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - break; + spin_lock(&ipc_head_lock); + list_for_each_entry(ipc, &ipc_head, list) { + if (ipc->num == num && + try_module_get(ipc->owner)) + goto found; + } + spin_unlock(&ipc_head_lock); + return -EINVAL; + + found: + spin_unlock(&ipc_head_lock); + + stat = ipc->alloc(data); + if (!stat) { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + goto err; + } + ret = ipc->init(stat, data, unit, 0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + goto err; + } + if (data->flags & IPPP_COMP_FLAG_XMIT) { + if (ccp->comp_stat) { + ccp->compressor->free(ccp->comp_stat); + module_put(ccp->compressor->owner); } - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (ccp->comp_stat) - ccp->compressor->free(ccp->comp_stat); ccp->comp_stat = stat; ccp->compressor = ipc; - } else { - if (ccp->decomp_stat) - ccp->decompressor->free(ccp->decomp_stat); - ccp->decomp_stat = stat; - ccp->decompressor = ipc; + } else { + if (ccp->decomp_stat) { + ccp->decompressor->free(ccp->decomp_stat); + module_put(ccp->decompressor->owner); } - return 0; + ccp->decomp_stat = stat; + ccp->decompressor = ipc; } + return 0; + + err: + module_put(ipc->owner); return -EINVAL; } @@ -606,36 +624,34 @@ int i, j; memset(protos, 0, sizeof(unsigned long) * 8); - for (ipc = ipc_head; ipc; ipc = ipc->next) { + + spin_lock(&ipc_head_lock); + list_for_each_entry(ipc, &ipc_head, list) { j = ipc->num / (sizeof(long)*8); i = ipc->num % (sizeof(long)*8); if (j < 8) protos[j] |= 1 << i; } + spin_unlock(&ipc_head_lock); } int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) { - ipc->next = ipc_head; - ipc->prev = NULL; - if (ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; + spin_lock(&ipc_head_lock); + list_add_tail(&ipc->list, &ipc_head); + spin_unlock(&ipc_head_lock); + return 0; } int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) { - if (ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if (ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; + spin_lock(&ipc_head_lock); + list_del(&ipc->list); + spin_unlock(&ipc_head_lock); + return 0; } diff -Nru a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c --- a/drivers/isdn/i4l/isdn_tty.c Wed Jun 11 12:32:42 2003 +++ b/drivers/isdn/i4l/isdn_tty.c Wed Jun 18 21:25:09 2003 @@ -1983,7 +1983,7 @@ memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) - group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd); + kill_pg_info(SIGIO, SEND_SIG_PRIV, dev->profd->pgrp); } static struct tty_operations modem_ops = { @@ -2095,11 +2095,10 @@ #endif kfree(info->xmit_buf - 4); } - err_unregister_tty: - tty_unregister_driver(&isdn_mdm->tty_modem); + tty_unregister_driver(m->tty_modem); err: - put_tty_driver(&isdn_mdm->tty_modem); - isdn_mdm->tty_modem = NULL; + put_tty_driver(m->tty_modem); + m->tty_modem = NULL; return retval; } @@ -2118,9 +2117,9 @@ #endif kfree(info->xmit_buf - 4); } - tty_unregister_driver(&isdn_mdm->tty_modem); - put_tty_driver(&isdn_mdm->tty_modem); - isdn_mdm->tty_modem = NULL; + tty_unregister_driver(isdn_mdm.tty_modem); + put_tty_driver(isdn_mdm.tty_modem); + isdn_mdm.tty_modem = NULL; } /* diff -Nru a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c --- a/drivers/isdn/i4l/isdn_ttyfax.c Tue Oct 29 19:01:54 2002 +++ b/drivers/isdn/i4l/isdn_ttyfax.c Fri May 23 11:33:46 2003 @@ -303,7 +303,7 @@ isdn_ctrl c; int par; struct isdn_slot *slot; - long flags; + unsigned long flags; for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) diff -Nru a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile --- a/drivers/isdn/isdnloop/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/isdnloop/Makefile Fri May 23 11:27:32 2003 @@ -1,6 +1,4 @@ -# # Makefile for the isdnloop ISDN device driver -# # Each configuration option enables a list of files. diff -Nru a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile --- a/drivers/isdn/pcbit/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/pcbit/Makefile Fri May 23 11:27:32 2003 @@ -6,4 +6,4 @@ # Multipart objects. -pcbit-objs := module.o edss1.o drv.o layer2.o capi.o callbacks.o +pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o diff -Nru a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile --- a/drivers/isdn/sc/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/sc/Makefile Fri May 23 11:27:32 2003 @@ -6,5 +6,5 @@ # Multipart objects. -sc-objs := shmem.o init.o debug.o packet.o command.o event.o \ - ioctl.o interrupt.o message.o timer.o +sc-y := shmem.o init.o debug.o packet.o command.o event.o \ + ioctl.o interrupt.o message.o timer.o diff -Nru a/drivers/isdn/tpam/Makefile b/drivers/isdn/tpam/Makefile --- a/drivers/isdn/tpam/Makefile Wed Oct 23 19:38:06 2002 +++ b/drivers/isdn/tpam/Makefile Fri May 23 11:27:32 2003 @@ -6,5 +6,6 @@ # Multipart objects. -tpam-objs := tpam_main.o tpam_nco.o tpam_memory.o tpam_commands.o \ - tpam_queues.o tpam_hdlc.o tpam_crcpc.o +tpam-y := tpam_main.o tpam_nco.o tpam_memory.o \ + tpam_commands.o tpam_queues.o tpam_hdlc.o \ + tpam_crcpc.o diff -Nru a/drivers/isdn/tpam/tpam_queues.c b/drivers/isdn/tpam/tpam_queues.c --- a/drivers/isdn/tpam/tpam_queues.c Mon Apr 21 03:58:37 2003 +++ b/drivers/isdn/tpam/tpam_queues.c Fri May 9 18:12:27 2003 @@ -145,6 +145,7 @@ do { hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); if (waiting_too_long++ > 0xfffffff) { + kfree_skb(skb); spin_unlock(&card->lock); printk(KERN_ERR "TurboPAM(tpam_irq): " "waiting too long...\n"); diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c --- a/drivers/md/dm-ioctl.c Sat Jun 14 16:16:11 2003 +++ b/drivers/md/dm-ioctl.c Mon Jun 16 13:20:05 2003 @@ -297,13 +297,14 @@ /* * rename and move the name cell. */ + unregister_with_devfs(hc); + list_del(&hc->name_list); old_name = hc->name; hc->name = new_name; list_add(&hc->name_list, _name_buckets + hash_str(new_name)); /* rename the device node in devfs */ - unregister_with_devfs(hc); register_with_devfs(hc); up_write(&_hash_lock); diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c --- a/drivers/message/i2o/i2o_scsi.c Thu Mar 13 17:14:29 2003 +++ b/drivers/message/i2o/i2o_scsi.c Sun Jun 8 12:18:41 2003 @@ -866,34 +866,6 @@ } /** - * internal_done - legacy scsi glue - * @SCPnt: command - * - * Completion function for a synchronous command - */ - -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -/** - * i2o_scsi_command - issue a scsi command and wait - * @SCPnt: command - * - * Issue a SCSI command and wait for it to complete. - */ - -static int i2o_scsi_command(Scsi_Cmnd * SCpnt) -{ - i2o_scsi_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - -/** * i2o_scsi_abort - abort a running command * @SCpnt: command to abort * @@ -1091,7 +1063,6 @@ .detect = i2o_scsi_detect, .release = i2o_scsi_release, .info = i2o_scsi_info, - .command = i2o_scsi_command, .queuecommand = i2o_scsi_queuecommand, .eh_abort_handler = i2o_scsi_abort, .eh_bus_reset_handler = i2o_scsi_bus_reset, diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c Thu May 29 13:46:33 2003 +++ b/drivers/net/amd8111e.c Thu Jun 19 19:17:11 2003 @@ -53,6 +53,8 @@ 2. Bug fix: Fixed VLAN support failure. 3. Bug fix: Fixed receive interrupt coalescing bug. 4. Dynamic IPG support is disabled by default. + 3.0.3 06/05/2003 + 1. Bug fix: Fixed failure to close the interface if SMP is enabled. */ @@ -89,9 +91,9 @@ #include "amd8111e.h" #define MODULE_NAME "amd8111e" -#define MODULE_VERSION "3.0.2" +#define MODULE_VERSION "3.0.3" MODULE_AUTHOR("Advanced Micro Devices, Inc."); -MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.2"); +MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3"); MODULE_LICENSE("GPL"); MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); @@ -1171,11 +1173,11 @@ if(lp->options & OPTION_DYN_IPG_ENABLE) del_timer_sync(&lp->ipg_data.ipg_timer); - /* Update the statistics before closing */ - amd8111e_get_stats(dev); spin_unlock_irq(&lp->lock); - free_irq(dev->irq, dev); + + /* Update the statistics before closing */ + amd8111e_get_stats(dev); lp->opened = 0; return 0; } diff -Nru a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c --- a/drivers/net/bonding/bond_main.c Mon May 26 21:45:02 2003 +++ b/drivers/net/bonding/bond_main.c Wed Jun 18 04:03:04 2003 @@ -390,6 +390,7 @@ #include #include #include +#include #include #include #include @@ -497,9 +498,7 @@ { NULL, -1}, }; -static int first_pass = 1; -static struct bonding *these_bonds = NULL; -static struct net_device *dev_bonds = NULL; +static LIST_HEAD(bond_dev_list); MODULE_PARM(max_bonds, "i"); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); @@ -952,8 +951,6 @@ add_timer(alb_timer); } - MOD_INC_USE_COUNT; - if (miimon > 0) { /* link check interval, in milliseconds. */ init_timer(timer); timer->expires = jiffies + (miimon * HZ / 1000); @@ -1027,7 +1024,6 @@ bond_alb_deinitialize(bond); } - MOD_DEC_USE_COUNT; return 0; } @@ -2797,84 +2793,6 @@ mod_timer(&bond->arp_timer, next_timer); } -typedef uint32_t in_addr_t; - -int -my_inet_aton(char *cp, unsigned long *the_addr) { - static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; - in_addr_t val; - char c; - union iaddr { - uint8_t bytes[4]; - uint32_t word; - } res; - uint8_t *pp = res.bytes; - int digit,base; - - res.word = 0; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!isdigit(c)) goto ret_0; - val = 0; base = 10; digit = 0; - for (;;) { - if (isdigit(c)) { - val = (val * base) + (c - '0'); - c = *++cp; - digit = 1; - } else { - break; - } - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp > res.bytes + 2 || val > 0xff) { - goto ret_0; - } - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) { - goto ret_0; - } - /* - * Did we get a valid digit? - */ - if (!digit) { - goto ret_0; - } - - /* Check whether the last part is in its limits depending on - the number of parts in total. */ - if (val > max[pp - res.bytes]) { - goto ret_0; - } - - if (the_addr != NULL) { - *the_addr = res.word | htonl (val); - } - - return (1); - -ret_0: - return (0); -} - static int bond_sethwaddr(struct net_device *master, struct net_device *slave) { #ifdef BONDING_DEBUG @@ -3411,7 +3329,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) { - bonding_t *bond = these_bonds; + bonding_t *bond; int len = 0; off_t begin = 0; u16 link; @@ -3419,7 +3337,8 @@ len += sprintf(buf + len, "%s\n", version); - while (bond != NULL) { + read_lock(&dev_base_lock); + list_for_each_entry(bond, &bond_dev_list, bond_list) { /* * This function locks the mutex, so we can't lock it until * afterwards @@ -3529,93 +3448,48 @@ len = 0; } - - bond = bond->next_bond; } + read_unlock(&dev_base_lock); + return len; } static int bond_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct bonding *this_bond = (struct bonding *)these_bonds; - struct bonding *last_bond; struct net_device *event_dev = (struct net_device *)ptr; + struct net_device *master = event_dev->master; - /* while there are bonds configured */ - while (this_bond != NULL) { - if (this_bond == event_dev->priv ) { - switch (event) { - case NETDEV_UNREGISTER: - /* - * remove this bond from a linked list of - * bonds - */ - if (this_bond == these_bonds) { - these_bonds = this_bond->next_bond; - } else { - for (last_bond = these_bonds; - last_bond != NULL; - last_bond = last_bond->next_bond) { - if (last_bond->next_bond == - this_bond) { - last_bond->next_bond = - this_bond->next_bond; - } - } - } - return NOTIFY_DONE; + if (event == NETDEV_UNREGISTER && master != NULL) + bond_release(master, event_dev); - default: - return NOTIFY_DONE; - } - } else if (this_bond->device == event_dev->master) { - switch (event) { - case NETDEV_UNREGISTER: - bond_release(this_bond->device, event_dev); - break; - } - return NOTIFY_DONE; - } - this_bond = this_bond->next_bond; - } return NOTIFY_DONE; } static struct notifier_block bond_netdev_notifier = { - notifier_call: bond_event, + .notifier_call = bond_event, }; static int __init bond_init(struct net_device *dev) { - bonding_t *bond, *this_bond, *last_bond; + bonding_t *bond; int count; #ifdef BONDING_DEBUG printk (KERN_INFO "Begin bond_init for %s\n", dev->name); #endif - bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); - if (bond == NULL) { - return -ENOMEM; - } - memset(bond, 0, sizeof(struct bonding)); + bond = dev->priv; /* initialize rwlocks */ rwlock_init(&bond->lock); rwlock_init(&bond->ptrlock); - bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); - if (bond->stats == NULL) { - kfree(bond); - return -ENOMEM; - } - memset(bond->stats, 0, sizeof(struct net_device_stats)); - + /* space is reserved for stats in alloc_netdev call. */ + bond->stats = (struct net_device_stats *)(bond + 1); bond->next = bond->prev = (slave_t *)bond; bond->current_slave = NULL; bond->current_arp_slave = NULL; bond->device = dev; - dev->priv = bond; /* Initialize the device structure. */ switch (bond_mode) { @@ -3640,8 +3514,6 @@ break; default: printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); - kfree(bond->stats); - kfree(bond); return -EINVAL; } @@ -3651,13 +3523,6 @@ dev->set_multicast_list = set_multicast_list; dev->do_ioctl = bond_ioctl; - /* - * Fill in the fields of the device structure with ethernet-generic - * values. - */ - - ether_setup(dev); - dev->tx_queue_len = 0; dev->flags |= IFF_MASTER|IFF_MULTICAST; #ifdef CONFIG_NET_FASTROUTE @@ -3690,10 +3555,10 @@ if (bond->bond_proc_dir == NULL) { printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", dev->name, dev->name); - kfree(bond->stats); - kfree(bond); return -ENOMEM; } + bond->bond_proc_dir->owner = THIS_MODULE; + bond->bond_proc_info_file = create_proc_info_entry("info", 0, bond->bond_proc_dir, bond_get_info); @@ -3701,26 +3566,13 @@ printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", dev->name, dev->name); remove_proc_entry(dev->name, proc_net); - kfree(bond->stats); - kfree(bond); return -ENOMEM; } + bond->bond_proc_info_file->owner = THIS_MODULE; #endif /* CONFIG_PROC_FS */ - if (first_pass == 1) { - these_bonds = bond; - register_netdevice_notifier(&bond_netdev_notifier); - first_pass = 0; - } else { - last_bond = these_bonds; - this_bond = these_bonds->next_bond; - while (this_bond != NULL) { - last_bond = this_bond; - this_bond = this_bond->next_bond; - } - last_bond->next_bond = bond; - } + list_add_tail(&bond->bond_list, &bond_dev_list); return 0; } @@ -3753,15 +3605,11 @@ return -1; } - static int __init bonding_init(void) { int no; int err; - /* Find a name for this unit */ - static struct net_device *dev_bond = NULL; - printk(KERN_INFO "%s", version); /* @@ -3812,12 +3660,6 @@ max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } - dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), - GFP_KERNEL); - if (dev_bond == NULL) { - return -ENOMEM; - } - memset(dev_bonds, 0, max_bonds*sizeof(struct net_device)); if (miimon < 0) { printk(KERN_WARNING @@ -3958,15 +3800,18 @@ for (arp_ip_count=0 ; (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count]; arp_ip_count++ ) { - /* TODO: check and log bad ip address */ - if (my_inet_aton(arp_ip_target[arp_ip_count], - &arp_target[arp_ip_count]) == 0) { + /* not complete check, but should be good enough to + catch mistakes */ + if (!isdigit(arp_ip_target[arp_ip_count][0])) { printk(KERN_WARNING "bonding_init(): bad arp_ip_target module " "parameter (%s), ARP monitoring will not be " "performed\n", arp_ip_target[arp_ip_count]); arp_interval = 0; + } else { + u32 ip = in_aton(arp_ip_target[arp_ip_count]); + *(u32 *)(arp_ip_target[arp_ip_count]) = ip; } } @@ -4005,48 +3850,50 @@ primary = NULL; } + register_netdevice_notifier(&bond_netdev_notifier); for (no = 0; no < max_bonds; no++) { - dev_bond->init = bond_init; - - err = dev_alloc_name(dev_bond,"bond%d"); - if (err < 0) { - kfree(dev_bonds); + struct net_device *dev; + char name[IFNAMSIZ]; + + snprintf(name, IFNAMSIZ, "bond%d", no); + + dev = alloc_netdev(sizeof(bonding_t) + + sizeof(struct net_device_stats), + name, ether_setup); + if (!dev) + return -ENOMEM; + + dev->init = bond_init; + SET_MODULE_OWNER(dev); + + if ( (err = register_netdev(dev)) ) { +#ifdef BONDING_DEBUG + printk(KERN_INFO "%s: register_netdev failed %d\n", + dev->name, err); +#endif + kfree(dev); return err; - } - SET_MODULE_OWNER(dev_bond); - if (register_netdev(dev_bond) != 0) { - kfree(dev_bonds); - return -EIO; } - dev_bond++; } return 0; } static void __exit bonding_exit(void) { - struct net_device *dev_bond = dev_bonds; - struct bonding *bond; - int no; + struct bonding *bond, *nxt; unregister_netdevice_notifier(&bond_netdev_notifier); - for (no = 0; no < max_bonds; no++) { - + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) { + struct net_device *dev = bond->device; #ifdef CONFIG_PROC_FS - bond = (struct bonding *) dev_bond->priv; remove_proc_entry("info", bond->bond_proc_dir); - remove_proc_entry(dev_bond->name, proc_net); + remove_proc_entry(dev->name, proc_net); #endif - unregister_netdev(dev_bond); - kfree(bond->stats); - kfree(dev_bond->priv); - - dev_bond->priv = NULL; - dev_bond++; + unregister_netdev(dev); + kfree(dev); } - kfree(dev_bonds); } module_init(bonding_init); diff -Nru a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h --- a/drivers/net/bonding/bonding.h Sun May 25 21:26:18 2003 +++ b/drivers/net/bonding/bonding.h Wed Jun 18 16:33:48 2003 @@ -104,7 +104,7 @@ struct proc_dir_entry *bond_proc_dir; struct proc_dir_entry *bond_proc_info_file; #endif /* CONFIG_PROC_FS */ - struct bonding *next_bond; + struct list_head bond_list; struct net_device *device; struct dev_mc_list *mc_list; unsigned short flags; diff -Nru a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c --- a/drivers/net/ixgb/ixgb_ethtool.c Sun Apr 27 21:22:07 2003 +++ b/drivers/net/ixgb/ixgb_ethtool.c Tue Jun 17 13:40:55 2003 @@ -50,7 +50,6 @@ return (IXGB_EEPROM_SIZE << 1); } -#define SUPPORTED_10000baseT_Full (1 << 11) #define SPEED_10000 10000 static void diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c --- a/drivers/net/myri_sbus.c Sun May 11 19:48:01 2003 +++ b/drivers/net/myri_sbus.c Thu Jun 19 14:25:16 2003 @@ -766,10 +766,14 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - unsigned char *pad = (unsigned char *) hh->hh_data; - struct ethhdr *eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + unsigned char *pad; + struct ethhdr *eth; struct net_device *dev = neigh->dev; + pad = ((unsigned char *) hh->hh_data) + + HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN); + eth = (struct ethhdr *) (pad + MYRI_PAD_LEN); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -788,7 +792,8 @@ /* Called by Address Resolution module to notify changes in address. */ void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } static int myri_change_mtu(struct net_device *dev, int new_mtu) diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Sun May 25 14:07:51 2003 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Tue Jun 10 11:17:04 2003 @@ -358,7 +358,6 @@ typedef struct local_info_t { dev_link_t link; - struct net_device dev; dev_node_t node; struct net_device_stats stats; int card_type; @@ -432,22 +431,10 @@ #define PutByte(reg,value) outb((value), ioaddr+(reg)) #define PutWord(reg,value) outw((value), ioaddr+(reg)) -static void -busy_loop(u_long len) -{ - if (in_interrupt()) { - u_long timeout = jiffies + len; - u_long flags; - save_flags(flags); - sti(); - while (time_before_eq(jiffies, timeout)) - ; - restore_flags(flags); - } else { - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(len); - } -} +#define Wait(n) do { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout(n); \ +} while (0) /*====== Functions used for debugging =================================*/ #if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */ @@ -619,11 +606,12 @@ flush_stale_links(); /* Allocate the device structure */ - local = kmalloc(sizeof(*local), GFP_KERNEL); - if (!local) return NULL; - memset(local, 0, sizeof(*local)); - link = &local->link; dev = &local->dev; - link->priv = dev->priv = local; + dev = alloc_etherdev(sizeof(local_info_t)); + if (!dev) + return NULL; + local = dev->priv; + link = &local->link; + link->priv = dev; init_timer(&link->release); link->release.function = &xirc2ps_release; @@ -645,7 +633,6 @@ dev->get_stats = &do_get_stats; dev->do_ioctl = &do_ioctl; dev->set_multicast_list = &set_multicast_list; - ether_setup(dev); dev->open = &do_open; dev->stop = &do_stop; #ifdef HAVE_TX_TIMEOUT @@ -684,7 +671,7 @@ static void xirc2ps_detach(dev_link_t * link) { - local_info_t *local = link->priv; + struct net_device *dev = link->priv; dev_link_t **linkp; DEBUG(0, "detach(0x%p)\n", link); @@ -706,10 +693,11 @@ */ del_timer(&link->release); if (link->state & DEV_CONFIG) { - DEBUG(0, "detach postponed, '%s' still locked\n", - link->dev->dev_name); - link->state |= DEV_STALE_LINK; - return; + xirc2ps_release((unsigned long)link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } /* Break the link with Card Services */ @@ -719,8 +707,8 @@ /* Unlink device structure, free it */ *linkp = link->next; if (link->dev) - unregister_netdev(&local->dev); - kfree(local); + unregister_netdev(dev); + kfree(dev); } /* xirc2ps_detach */ @@ -745,7 +733,8 @@ static int set_card_type(dev_link_t *link, const void *s) { - local_info_t *local = link->priv; + struct net_device *dev = link->priv; + local_info_t *local = dev->priv; #ifdef PCMCIA_DEBUG unsigned cisrev = ((const unsigned char *)s)[2]; #endif @@ -839,8 +828,8 @@ xirc2ps_config(dev_link_t * link) { client_handle_t handle = link->handle; - local_info_t *local = link->priv; - struct net_device *dev = &local->dev; + struct net_device *dev = link->priv; + local_info_t *local = dev->priv; tuple_t tuple; cisparse_t parse; ioaddr_t ioaddr; @@ -1195,11 +1184,10 @@ xirc2ps_release(u_long arg) { dev_link_t *link = (dev_link_t *) arg; - local_info_t *local = link->priv; - struct net_device *dev = &local->dev; DEBUG(0, "release(0x%p)\n", link); +#if 0 /* * If the device is currently in use, we won't release until it * is actually closed. @@ -1210,8 +1198,10 @@ link->state |= DEV_STALE_CONFIG; return; } +#endif if (link->win) { + struct net_device *dev = link->priv; local_info_t *local = dev->priv; if (local->dingo) iounmap(local->dingo_ccr - 0x0800); @@ -1243,8 +1233,7 @@ event_callback_args_t * args) { dev_link_t *link = args->client_data; - local_info_t *lp = link->priv; - struct net_device *dev = &lp->dev; + struct net_device *dev = link->priv; DEBUG(0, "event(%d)\n", (int)event); @@ -1779,12 +1768,12 @@ SelectPage(4); udelay(1); PutByte(XIRCREG4_GPR1, 0); /* clear bit 0: power down */ - busy_loop(HZ/25); /* wait 40 msec */ + Wait(HZ/25); /* wait 40 msec */ if (local->mohawk) PutByte(XIRCREG4_GPR1, 1); /* set bit 0: power up */ else PutByte(XIRCREG4_GPR1, 1 | 4); /* set bit 0: power up, bit 2: AIC */ - busy_loop(HZ/50); /* wait 20 msec */ + Wait(HZ/50); /* wait 20 msec */ } static void @@ -1798,9 +1787,9 @@ hardreset(dev); PutByte(XIRCREG_CR, SoftReset); /* set */ - busy_loop(HZ/50); /* wait 20 msec */ + Wait(HZ/50); /* wait 20 msec */ PutByte(XIRCREG_CR, 0); /* clear */ - busy_loop(HZ/25); /* wait 40 msec */ + Wait(HZ/25); /* wait 40 msec */ if (local->mohawk) { SelectPage(4); /* set pin GP1 and GP2 to output (0x0c) @@ -1811,7 +1800,7 @@ } /* give the circuits some time to power up */ - busy_loop(HZ/2); /* about 500ms */ + Wait(HZ/2); /* about 500ms */ local->last_ptr_value = 0; local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4 @@ -1830,7 +1819,7 @@ SelectPage(0x42); PutByte(XIRCREG42_SWC1, 0x80); } - busy_loop(HZ/25); /* wait 40 msec to let it complete */ + Wait(HZ/25); /* wait 40 msec to let it complete */ #ifdef PCMCIA_DEBUG if (pc_debug) { @@ -1889,7 +1878,7 @@ printk(KERN_INFO "%s: MII selected\n", dev->name); SelectPage(2); PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08); - busy_loop(HZ/50); + Wait(HZ/50); } else { printk(KERN_INFO "%s: MII detected; using 10mbs\n", dev->name); @@ -1898,7 +1887,7 @@ PutByte(XIRCREG42_SWC1, 0xC0); else /* enable 10BaseT */ PutByte(XIRCREG42_SWC1, 0x80); - busy_loop(HZ/25); /* wait 40 msec to let it complete */ + Wait(HZ/25); /* wait 40 msec to let it complete */ } if (full_duplex) PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR | FullDuplex)); @@ -1991,7 +1980,7 @@ * Fixme: Better to use a timer here! */ for (i=0; i < 35; i++) { - busy_loop(HZ/10); /* wait 100 msec */ + Wait(HZ/10); /* wait 100 msec */ status = mii_rd(ioaddr, 0, 1); if ((status & 0x0020) && (status & 0x0004)) break; @@ -2083,12 +2072,8 @@ { pcmcia_unregister_driver(&xirc2ps_cs_driver); - while (dev_list) { - if (dev_list->state & DEV_CONFIG) - xirc2ps_release((u_long)dev_list); - if (dev_list) /* xirc2ps_release() might already have detached... */ - xirc2ps_detach(dev_list); - } + while (dev_list) + xirc2ps_detach(dev_list); } module_init(init_xirc2ps_cs); diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Mon May 26 22:37:07 2003 +++ b/drivers/net/pcnet32.c Thu Jun 19 21:27:25 2003 @@ -1003,7 +1003,7 @@ skb_reserve (rx_skbuff, 2); } - if (lp->rx_dma_addr[i] == NULL) + if (lp->rx_dma_addr[i] == 0) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c --- a/drivers/net/plip.c Mon Dec 30 20:26:12 2002 +++ b/drivers/net/plip.c Thu Jun 19 14:25:16 2003 @@ -1078,7 +1078,10 @@ if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) { - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; + + eth = (struct ethhdr*)(((u8*)hh->hh_data) + + HH_DATA_OFF(sizeof(*eth))); plip_rewrite_address (neigh->dev, eth); } diff -Nru a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c --- a/drivers/net/ppp_async.c Sat Jun 7 00:45:00 2003 +++ b/drivers/net/ppp_async.c Thu Jun 19 18:48:08 2003 @@ -147,7 +147,6 @@ struct asyncppp *ap; int err; - MOD_INC_USE_COUNT; err = -ENOMEM; ap = kmalloc(sizeof(*ap), GFP_KERNEL); if (ap == 0) @@ -183,7 +182,6 @@ out_free: kfree(ap); out: - MOD_DEC_USE_COUNT; return err; } @@ -223,7 +221,6 @@ if (ap->tpkt != 0) kfree_skb(ap->tpkt); kfree(ap); - MOD_DEC_USE_COUNT; } /* @@ -351,6 +348,7 @@ static struct tty_ldisc ppp_ldisc = { + .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, .name = "ppp", .open = ppp_asynctty_open, diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c --- a/drivers/net/pppoe.c Wed Jun 4 17:57:06 2003 +++ b/drivers/net/pppoe.c Thu Jun 19 12:39:38 2003 @@ -1061,6 +1061,7 @@ } static struct file_operations pppoe_seq_fops = { + .owner = THIS_MODULE, .open = pppoe_seq_open, .read = seq_read, .llseek = seq_lseek, diff -Nru a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c --- a/drivers/net/rcpci45.c Tue May 20 20:02:20 2003 +++ b/drivers/net/rcpci45.c Wed Jun 18 16:36:53 2003 @@ -171,13 +171,14 @@ * will be assigned to the LAN API layer. */ - dev = init_etherdev (NULL, sizeof (*pDpa)); + dev = alloc_etherdev(sizeof(*pDpa)); if (!dev) { printk (KERN_ERR - "(rcpci45 driver:) init_etherdev alloc failed\n"); + "(rcpci45 driver:) alloc_etherdev alloc failed\n"); error = -ENOMEM; goto err_out; } + SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -257,6 +258,9 @@ dev->do_ioctl = &RCioctl; dev->set_config = &RCconfig; + if ((error = register_netdev(dev))) + goto err_out_free_region; + return 0; /* success */ err_out_free_region: @@ -265,7 +269,6 @@ pci_free_consistent (pdev, MSG_BUF_SIZE, pDpa->msgbuf, pDpa->msgbuf_dma); err_out_free_dev: - unregister_netdev (dev); kfree (dev); err_out: card_idx--; @@ -534,17 +537,6 @@ (PFNCALLBACK) RCreset_callback); } -int -broadcast_packet (unsigned char *address) -{ - int i; - for (i = 0; i < 6; i++) - if (address[i] != 0xff) - return 0; - - return 1; -} - /* * RCrecv_callback() * @@ -717,11 +709,9 @@ if (retry > REBOOT_REINIT_RETRY_LIMIT) { printk (KERN_WARNING "%s unable to reinitialize adapter after reboot\n", dev->name); - printk (KERN_WARNING "%s decrementing driver and closing interface\n", dev->name); + printk (KERN_WARNING "%s shutting down interface\n", dev->name); RCDisableI2OInterrupts (dev); dev->flags &= ~IFF_UP; - MOD_DEC_USE_COUNT; - /* FIXME: kill MOD_DEC_USE_COUNT, use dev_put */ } else { printk (KERN_INFO "%s: rescheduling timer...\n", dev->name); diff -Nru a/drivers/net/shaper.c b/drivers/net/shaper.c --- a/drivers/net/shaper.c Thu Apr 3 07:19:43 2003 +++ b/drivers/net/shaper.c Mon Jun 16 14:26:40 2003 @@ -630,7 +630,7 @@ * Add a shaper device to the system */ -static int __init shaper_probe(struct net_device *dev) +static void __init shaper_setup(struct net_device *dev) { /* * Set up the shaper. @@ -642,6 +642,7 @@ dev->open = shaper_open; dev->stop = shaper_close; + dev->destructor = (void (*)(struct net_device *))kfree; dev->hard_start_xmit = shaper_start_xmit; dev->get_stats = shaper_get_stats; dev->set_multicast_list = NULL; @@ -669,12 +670,6 @@ dev->addr_len = 0; dev->tx_queue_len = 10; dev->flags = 0; - - /* - * Shaper is ok - */ - - return 0; } static int shapers = 1; @@ -695,35 +690,38 @@ #endif /* MODULE */ -static struct net_device *devs; +static struct net_device **devs; static unsigned int shapers_registered = 0; static int __init shaper_init(void) { - int i, err; + int i; size_t alloc_size; - struct shaper *sp; + struct net_device *dev; + char name[IFNAMSIZ]; if (shapers < 1) return -ENODEV; - alloc_size = (sizeof(*devs) * shapers) + - (sizeof(struct shaper) * shapers); + alloc_size = sizeof(*dev) * shapers; devs = kmalloc(alloc_size, GFP_KERNEL); if (!devs) return -ENOMEM; memset(devs, 0, alloc_size); - sp = (struct shaper *) &devs[shapers]; for (i = 0; i < shapers; i++) { - err = dev_alloc_name(&devs[i], "shaper%d"); - if (err < 0) + + snprintf(name, IFNAMSIZ, "shaper%d", i); + dev = alloc_netdev(sizeof(struct shaper), name, + shaper_setup); + if (!dev) break; - devs[i].init = shaper_probe; - devs[i].priv = &sp[i]; - if (register_netdev(&devs[i])) + + if (register_netdev(dev)) break; + + devs[i] = dev; shapers_registered++; } @@ -740,7 +738,8 @@ int i; for (i = 0; i < shapers_registered; i++) - unregister_netdev(&devs[i]); + if (devs[i]) + unregister_netdev(devs[i]); kfree(devs); devs = NULL; diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c Sat Jun 7 00:25:40 2003 +++ b/drivers/net/sis900.c Thu Jun 19 19:51:00 2003 @@ -124,6 +124,7 @@ { "ICS LAN PHY", 0x0015, 0xF440, LAN }, { "NS 83851 PHY", 0x2000, 0x5C20, MIX }, { "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN }, + { "VIA 6103 PHY", 0x0101, 0x8f20, LAN }, {0,}, }; diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Mon May 26 22:05:38 2003 +++ b/drivers/net/sundance.c Thu Jun 19 17:11:29 2003 @@ -980,8 +980,8 @@ { int i; for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring), + printk(KERN_DEBUG "%02x %08Zx %08x %08x(%02x) %08x %08x\n", i, + np->tx_ring_dma + i*sizeof(*np->tx_ring), le32_to_cpu(np->tx_ring[i].next_desc), le32_to_cpu(np->tx_ring[i].status), (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff, @@ -1666,7 +1666,7 @@ switch (cmd) { case SIOCDEVPRIVATE: for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring), le32_to_cpu(np->tx_ring[i].next_desc), le32_to_cpu(np->tx_ring[i].status), diff -Nru a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig --- a/drivers/net/tulip/Kconfig Sun Apr 20 12:56:51 2003 +++ b/drivers/net/tulip/Kconfig Thu Jun 19 20:34:58 2003 @@ -37,7 +37,7 @@ ---help--- This driver is developed for the SMC EtherPower series Ethernet cards and also works with cards based on the DECchip - 21040/21041/21140 (Tulip series) chips. Some LinkSys PCI cards are + 21140 (Tulip series) chips. Some LinkSys PCI cards are of this type. (If your card is NOT SMC EtherPower 10/100 PCI (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c --- a/drivers/net/wan/syncppp.c Wed Nov 27 11:25:41 2002 +++ b/drivers/net/wan/syncppp.c Fri May 30 12:33:58 2003 @@ -132,6 +132,9 @@ static struct timer_list sppp_keepalive_timer; static spinlock_t spppq_lock = SPIN_LOCK_UNLOCKED; +/* global xmit queue for sending packets while spinlock is held */ +static struct sk_buff_head tx_queue; + static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, u8 ident, u16 len, void *data); @@ -150,6 +153,20 @@ static int debug; +/* Flush global outgoing packet queue to dev_queue_xmit(). + * + * dev_queue_xmit() must be called with interrupts enabled + * which means it can't be called with spinlocks held. + * If a packet needs to be sent while a spinlock is held, + * then put the packet into tx_queue, and call sppp_flush_xmit() + * after spinlock is released. + */ +static void sppp_flush_xmit() +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&tx_queue)) != NULL) + dev_queue_xmit(skb); +} /* * Interface down stub @@ -207,7 +224,8 @@ { struct ppp_header *h; struct sppp *sp = (struct sppp *)sppp_of(dev); - + unsigned long flags; + skb->dev=dev; skb->mac.raw=skb->data; @@ -223,7 +241,7 @@ if (sp->pp_flags & PP_DEBUG) printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", dev->name, skb->len); -drop: kfree_skb(skb); + kfree_skb(skb); return; } @@ -231,13 +249,11 @@ h = (struct ppp_header *)skb->data; skb_pull(skb,sizeof(struct ppp_header)); + spin_lock_irqsave(&sp->lock, flags); + switch (h->address) { default: /* Invalid PPP packet. */ -invalid: if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; + goto invalid; case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; @@ -261,15 +277,13 @@ goto drop; case PPP_LCP: sppp_lcp_input (sp, skb); - kfree_skb(skb); - return; + goto drop; case PPP_IPCP: if (sp->lcp.state == LCP_STATE_OPENED) sppp_ipcp_input (sp, skb); else printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); - kfree_skb(skb); - return; + goto drop; case PPP_IP: if (sp->ipcp.state == IPCP_STATE_OPENED) { if(sp->pp_flags&PP_DEBUG) @@ -277,7 +291,7 @@ skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; } break; #ifdef IPX @@ -287,7 +301,7 @@ skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; } break; #endif @@ -308,26 +322,36 @@ goto invalid; case CISCO_KEEPALIVE: sppp_cisco_input (sp, skb); - kfree_skb(skb); - return; + goto drop; #ifdef CONFIG_INET case ETH_P_IP: skb->protocol=htons(ETH_P_IP); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; #endif #ifdef CONFIG_IPX case ETH_P_IPX: skb->protocol=htons(ETH_P_IPX); netif_rx(skb); dev->last_rx = jiffies; - return; + goto done; #endif } break; } + goto drop; + +invalid: + if (sp->pp_flags & PP_DEBUG) + printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", + dev->name, h->address, h->control, ntohs (h->protocol)); +drop: kfree_skb(skb); +done: + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); + return; } EXPORT_SYMBOL(sppp_input); @@ -394,10 +418,14 @@ ! (dev->flags & IFF_UP)) continue; + spin_lock(&sp->lock); + /* No keepalive in PPP mode if LCP not opened yet. */ if (! (sp->pp_flags & PP_CISCO) && - sp->lcp.state != LCP_STATE_OPENED) + sp->lcp.state != LCP_STATE_OPENED) { + spin_unlock(&sp->lock); continue; + } if (sp->pp_alivecnt == MAXALIVECNT) { /* No keepalive packets got. Stop the interface. */ @@ -424,8 +452,11 @@ sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, sp->lcp.echoid, 4, &nmagic); } + + spin_unlock(&sp->lock); } spin_unlock_irqrestore(&spppq_lock, flags); + sppp_flush_xmit(); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } @@ -757,6 +788,7 @@ } } + /* * Send PPP LCP packet. */ @@ -804,7 +836,7 @@ /* Control is high priority so it doesn't get queued behind data */ skb->priority=TC_PRIO_CONTROL; skb->dev = dev; - dev_queue_xmit(skb); + skb_queue_tail(&tx_queue, skb); } /* @@ -846,7 +878,7 @@ sp->obytes += skb->len; skb->priority=TC_PRIO_CONTROL; skb->dev = dev; - dev_queue_xmit(skb); + skb_queue_tail(&tx_queue, skb); } /** @@ -861,10 +893,15 @@ int sppp_close (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + + spin_lock_irqsave(&sp->lock, flags); sp->pp_link_state = SPPP_LINK_DOWN; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sppp_clear_timeout (sp); + spin_unlock_irqrestore(&sp->lock, flags); + return 0; } @@ -883,11 +920,18 @@ int sppp_open (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + sppp_close(dev); + + spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sppp_lcp_open (sp); } sp->pp_link_state = SPPP_LINK_DOWN; + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); + return 0; } @@ -912,7 +956,11 @@ int sppp_reopen (struct net_device *dev) { struct sppp *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + sppp_close(dev); + + spin_lock_irqsave(&sp->lock, flags); if (!(sp->pp_flags & PP_CISCO)) { sp->lcp.magic = jiffies; @@ -923,6 +971,8 @@ sppp_set_timeout (sp, 1); } sp->pp_link_state=SPPP_LINK_DOWN; + spin_unlock_irqrestore(&sp->lock, flags); + return 0; } @@ -1040,6 +1090,7 @@ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; sp->pp_if = dev; + spin_lock_init(&sp->lock); /* * Device specific setup. All but interrupt handler and @@ -1290,11 +1341,11 @@ struct sppp *sp = (struct sppp*) arg; unsigned long flags; - spin_lock_irqsave(&spppq_lock, flags); + spin_lock_irqsave(&sp->lock, flags); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { - spin_unlock_irqrestore(&spppq_lock, flags); + spin_unlock_irqrestore(&sp->lock, flags); return; } switch (sp->lcp.state) { @@ -1333,7 +1384,8 @@ } break; } - spin_unlock_irqrestore(&spppq_lock, flags); + spin_unlock_irqrestore(&sp->lock, flags); + sppp_flush_xmit(); } static char *sppp_lcp_type_name (u8 type) @@ -1393,6 +1445,8 @@ static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) { + if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) + return NET_RX_DROP; sppp_input(dev,skb); return 0; } @@ -1400,6 +1454,7 @@ struct packet_type sppp_packet_type = { .type = __constant_htons(ETH_P_WAN_PPP), .func = sppp_rcv, + .data = (void*)1, /* must be non-NULL to indicate 'new' protocol */ }; static char banner[] __initdata = @@ -1412,6 +1467,7 @@ if(debug) debug=PP_DEBUG; printk(banner); + skb_queue_head_init(&tx_queue); dev_add_pack(&sppp_packet_type); return 0; } diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Sat May 17 14:09:51 2003 +++ b/drivers/net/wireless/airo.c Tue Jun 17 14:28:27 2003 @@ -888,7 +888,7 @@ #ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) -const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; // A few details needed for WEP (Wireless Equivalent Privacy) diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- a/drivers/net/wireless/atmel.c Thu Jun 5 21:54:46 2003 +++ b/drivers/net/wireless/atmel.c Tue Jun 17 14:28:27 2003 @@ -1903,7 +1903,7 @@ return 0; } -const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, +static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; static int atmel_set_freq(struct net_device *dev, diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c --- a/drivers/oprofile/buffer_sync.c Wed Jun 11 18:05:19 2003 +++ b/drivers/oprofile/buffer_sync.c Sun Jun 15 07:34:47 2003 @@ -425,7 +425,7 @@ { struct mm_struct * mm = 0; struct task_struct * new; - unsigned long cookie; + unsigned long cookie = 0; int in_kernel = 1; unsigned int i; @@ -442,13 +442,15 @@ in_kernel = s->event; add_kernel_ctx_switch(s->event); } else { + struct mm_struct * oldmm = mm; + /* userspace context switch */ new = (struct task_struct *)s->event; - release_mm(mm); + release_mm(oldmm); mm = take_tasks_mm(new); - - cookie = get_exec_dcookie(mm); + if (mm != oldmm) + cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); } } else { diff -Nru a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h --- a/drivers/pci/hotplug/acpiphp.h Tue Jun 3 20:47:31 2003 +++ b/drivers/pci/hotplug/acpiphp.h Tue Jun 17 17:36:42 2003 @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -35,6 +34,7 @@ #define _ACPIPHP_H #include +#include /* for KOBJ_NAME_LEN */ #include "pci_hotplug.h" #define dbg(format, arg...) \ @@ -49,7 +49,7 @@ #define SLOT_MAGIC 0x67267322 /* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ +#define SLOT_NAME_SIZE KOBJ_NAME_LEN /* {_SUN} */ struct acpiphp_bridge; struct acpiphp_slot; @@ -212,11 +212,7 @@ #define FUNC_HAS_PS2 (0x00000040) #define FUNC_HAS_PS3 (0x00000080) -/* not yet */ -#define SLOT_SUPPORT_66MHZ (0x00010000) -#define SLOT_SUPPORT_100MHZ (0x00020000) -#define SLOT_SUPPORT_133MHZ (0x00040000) -#define SLOT_SUPPORT_PCIX (0x00080000) +#define FUNC_EXISTS (0x10000000) /* to make sure we call _EJ0 only for existing funcs */ /* function prototypes */ diff -Nru a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c --- a/drivers/pci/hotplug/acpiphp_core.c Tue Jun 3 20:47:31 2003 +++ b/drivers/pci/hotplug/acpiphp_core.c Tue Jun 17 17:36:42 2003 @@ -5,8 +5,8 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -26,8 +26,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to , - * , - * + * * */ @@ -57,7 +56,7 @@ static int num_slots; #define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " +#define DRIVER_AUTHOR "Greg Kroah-Hartman , Takayoshi Kochi " #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -376,10 +375,8 @@ */ static void make_slot_name (struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", - slot->acpi_slot->sun, - slot->acpi_slot->bridge->bus, - slot->acpi_slot->device); + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%u", + slot->acpi_slot->sun); } /** diff -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c --- a/drivers/pci/hotplug/acpiphp_glue.c Tue Jun 3 15:48:10 2003 +++ b/drivers/pci/hotplug/acpiphp_glue.c Tue Jun 17 17:36:42 2003 @@ -1,9 +1,9 @@ /* * ACPI PCI HotPlug glue functions to ACPI CA subsystem * - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation + * Copyright (c) 2002,2003 NEC Corporation * * All rights reserved. * @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ @@ -204,7 +204,6 @@ if (ACPI_FAILURE(status)) { err("failed to register interrupt notify handler\n"); - kfree(newfunc); return status; } @@ -617,9 +616,8 @@ /* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridges(struct acpi_device *device) +static int add_bridge(acpi_handle handle) { - acpi_handle *handle = device->handle; acpi_status status; unsigned long tmp; int seg, bus; @@ -673,6 +671,12 @@ } +static void remove_bridge (acpi_handle handle) +{ + /* No-op for now .. */ +} + + static int power_on_slot (struct acpiphp_slot *slot) { acpi_status status; @@ -725,9 +729,7 @@ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_PS3) { - dbg("%s: executing _PS3 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); + if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -740,10 +742,8 @@ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & FUNC_HAS_EJ0) { - dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - + /* We don't want to call _EJ0 on non-existing functions. */ + if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) { /* _EJ0 method take one argument */ arg_list.count = 1; arg_list.pointer = &arg; @@ -756,6 +756,7 @@ retval = -1; goto err_exit; } + func->flags &= (~FUNC_EXISTS); } } @@ -835,6 +836,8 @@ retval = acpiphp_configure_function(func); if (retval) goto err_exit; + + func->flags |= FUNC_EXISTS; } slot->flags |= SLOT_ENABLED; @@ -1029,13 +1032,10 @@ } } -static struct acpi_driver acpi_pci_hp_driver = { - .name = "pci_hp", - .class = "", - .ids = ACPI_PCI_HOST_HID, - .ops = { - .add = add_bridges, - } + +static struct acpi_pci_driver acpi_pci_hp_driver = { + .add = add_bridge, + .remove = remove_bridge, }; /** @@ -1044,17 +1044,15 @@ */ int acpiphp_glue_init (void) { - acpi_status status; + int num; if (list_empty(&pci_root_buses)) return -1; - status = acpi_bus_register_driver(&acpi_pci_hp_driver); + num = acpi_pci_register_driver(&acpi_pci_hp_driver); - if (ACPI_FAILURE(status)) { - err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); + if (num <= 0) return -1; - } return 0; } @@ -1296,7 +1294,7 @@ /* * attention LED ON: 1 - * OFF: 0 + * OFF: 0 * * TBD * no direct attention led status information via ACPI diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c --- a/drivers/pci/hotplug/acpiphp_pci.c Tue Jun 3 15:48:10 2003 +++ b/drivers/pci/hotplug/acpiphp_pci.c Tue Jun 17 17:36:43 2003 @@ -4,7 +4,7 @@ * Copyright (c) 1995,2001 Compaq Computer Corporation * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001,2002 IBM Corp. - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (c) 2002 NEC Corporation * @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to + * Send feedback to * */ diff -Nru a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c --- a/drivers/pci/hotplug/acpiphp_res.c Tue Jun 3 20:47:31 2003 +++ b/drivers/pci/hotplug/acpiphp_res.c Tue Jun 17 17:36:43 2003 @@ -5,7 +5,7 @@ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (c) 2002 NEC Corporation * * All rights reserved. @@ -25,7 +25,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Send feedback to , + * Send feedback to , * */ diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile --- a/drivers/pcmcia/Makefile Wed Jun 11 14:52:42 2003 +++ b/drivers/pcmcia/Makefile Mon Jun 16 08:06:42 2003 @@ -3,7 +3,7 @@ # obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o -obj-$(CONFIG_YENTA) += yenta.o +obj-$(CONFIG_YENTA) += yenta_socket.o obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82092) += i82092.o diff -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c --- a/drivers/pcmcia/cistpl.c Sun Jun 15 08:20:51 2003 +++ b/drivers/pcmcia/cistpl.c Mon Jun 16 08:46:25 2003 @@ -106,11 +106,10 @@ pccard_mem_map *mem = &s->cis_mem; if (!(s->features & SS_CAP_STATIC_MAP) && mem->sys_start == 0) { - int low = !(s->features & SS_CAP_PAGE_REGS); validate_mem(s); mem->sys_start = 0; if (find_mem_region(&mem->sys_start, s->map_size, - s->map_size, low, "card services", s)) { + s->map_size, 0, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); return NULL; } diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Sun Jun 15 09:58:50 2003 +++ b/drivers/pcmcia/cs.c Tue Jun 17 01:06:34 2003 @@ -816,7 +816,8 @@ if ((skt->state & SOCKET_PRESENT) && !(status & SS_DETECT)) socket_shutdown(skt); - if (status & SS_DETECT) + if (!(skt->state & SOCKET_PRESENT) && + (status & SS_DETECT)) socket_insert(skt); } if (events & SS_BATDEAD) @@ -2043,8 +2044,7 @@ if (!(s->features & SS_CAP_STATIC_MAP) && find_mem_region(&win->base, win->size, align, - (req->Attributes & WIN_MAP_BELOW_1MB) || - !(s->features & SS_CAP_PAGE_REGS), + (req->Attributes & WIN_MAP_BELOW_1MB), (*handle)->dev_info, s)) return CS_IN_USE; (*handle)->state |= CLIENT_WIN_REQ(w); diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h --- a/drivers/pcmcia/cs_internal.h Sun Jun 15 04:42:53 2003 +++ b/drivers/pcmcia/cs_internal.h Mon Jun 16 08:46:25 2003 @@ -168,7 +168,7 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, char *name, struct pcmcia_socket *s); int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, struct pcmcia_socket *s); + int low, char *name, struct pcmcia_socket *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff -Nru a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c --- a/drivers/pcmcia/rsrc_mgr.c Sun Jun 15 08:20:52 2003 +++ b/drivers/pcmcia/rsrc_mgr.c Mon Jun 16 08:46:26 2003 @@ -139,22 +139,6 @@ return 0; } -/* FIXME: Fundamentally racy. */ -static inline int check_mem_resource(unsigned long b, unsigned long n, - struct pci_dev *dev) -{ - struct resource *region; - - region = __request_region(resource_parent(b, n, IORESOURCE_MEM, dev), - b, n, "check_mem_resource"); - if (!region) - return -EBUSY; - - release_resource(region); - kfree(region); - return 0; -} - static struct resource *make_resource(unsigned long b, unsigned long n, int flags, char *name) { @@ -340,52 +324,103 @@ ======================================================================*/ /* Validation function for cards with a valid CIS */ -static int cis_readable(struct pcmcia_socket *s, u_long base) +static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info) { - cisinfo_t info1, info2; - int ret; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->map_size-1; - s->cis_virt = ioremap(base, s->map_size); - ret = pcmcia_validate_cis(s->clients, &info1); - /* invalidate mapping and CIS cache */ - iounmap(s->cis_virt); - destroy_cis_cache(s); - if ((ret != 0) || (info1.Chains == 0)) - return 0; - s->cis_mem.sys_start = base+s->map_size; - s->cis_mem.sys_stop = base+2*s->map_size-1; - s->cis_virt = ioremap(base+s->map_size, s->map_size); - ret = pcmcia_validate_cis(s->clients, &info2); - iounmap(s->cis_virt); - destroy_cis_cache(s); - return ((ret == 0) && (info1.Chains == info2.Chains)); + int ret = -1; + + s->cis_mem.sys_start = res->start; + s->cis_mem.sys_stop = res->end; + s->cis_virt = ioremap(res->start, s->map_size); + if (s->cis_virt) { + ret = pcmcia_validate_cis(s->clients, info); + /* invalidate mapping and CIS cache */ + iounmap(s->cis_virt); + s->cis_virt = NULL; + destroy_cis_cache(s); + } + s->cis_mem.sys_start = 0; + s->cis_mem.sys_stop = 0; + if ((ret != 0) || (info->Chains == 0)) + return 0; + return 1; } /* Validation function for simple memory cards */ -static int checksum(struct pcmcia_socket *s, u_long base) +static int checksum(struct pcmcia_socket *s, struct resource *res) { - int i, a, b, d; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->map_size-1; - s->cis_virt = ioremap(base, s->map_size); - s->cis_mem.card_start = 0; - s->cis_mem.flags = MAP_ACTIVE; - s->ss_entry->set_mem_map(s, &s->cis_mem); - /* Don't bother checking every word... */ - a = 0; b = -1; - for (i = 0; i < s->map_size; i += 44) { - d = readl(s->cis_virt+i); - a += d; b &= d; - } - iounmap(s->cis_virt); - return (b == -1) ? -1 : (a>>1); + pccard_mem_map map; + int i, a = 0, b = -1, d; + void *virt; + + virt = ioremap(res->start, s->map_size); + if (virt) { + map.map = 0; + map.flags = MAP_ACTIVE; + map.speed = 0; + map.sys_start = res->start; + map.sys_stop = res->end; + map.card_start = 0; + s->ss_entry->set_mem_map(s, &map); + + /* Don't bother checking every word... */ + for (i = 0; i < s->map_size; i += 44) { + d = readl(virt+i); + a += d; + b &= d; + } + + map.flags = 0; + s->ss_entry->set_mem_map(s, &map); + + iounmap(virt); + } + + return (b == -1) ? -1 : (a>>1); } -static int checksum_match(struct pcmcia_socket *s, u_long base) +static int +cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) { - int a = checksum(s, base), b = checksum(s, base+s->map_size); - return ((a == b) && (a >= 0)); + struct resource *res1, *res2; + cisinfo_t info1, info2; + int ret = 0; + + res1 = request_mem_region(base, size/2, "cs memory probe"); + res2 = request_mem_region(base + size/2, size/2, "cs memory probe"); + + if (res1 && res2) { + ret = readable(s, res1, &info1); + ret += readable(s, res2, &info2); + } + + if (res2) + release_resource(res2); + if (res1) + release_resource(res1); + + return (ret == 2) && (info1.Chains == info2.Chains); +} + +static int +checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size) +{ + struct resource *res1, *res2; + int a = -1, b = -1; + + res1 = request_mem_region(base, size/2, "cs memory probe"); + res2 = request_mem_region(base + size/2, size/2, "cs memory probe"); + + if (res1 && res2) { + a = checksum(s, res1); + b = checksum(s, res2); + } + + if (res2) + release_resource(res2); + if (res1) + release_resource(res1); + + return (a == b) && (a >= 0); } /*====================================================================== @@ -409,16 +444,16 @@ step = 2 * s->map_size; for (i = j = base; i < base+num; i = j + step) { if (!fail) { - for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step, s->cb_dev) == 0) && - cis_readable(s, j)) + for (j = i; j < base+num; j += step) { + if (cis_readable(s, j, step)) break; + } fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step, s->cb_dev) == 0) && - checksum_match(s, j) && checksum_match(s, j + step)) + if (checksum_match(s, j, step) && + checksum_match(s, j + step, step)) break; } if (i != j) { @@ -555,17 +590,19 @@ } int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, struct pcmcia_socket *s) + int low, char *name, struct pcmcia_socket *s) { u_long try; resource_map_t *m; int ret = -1; + low = low || !(s->features & SS_CAP_PAGE_REGS); + down(&rsrc_sem); while (1) { for (m = mem_db.next; m != &mem_db; m = m->next) { /* first pass >1MB, second pass <1MB */ - if ((force_low != 0) ^ (m->base < 0x100000)) + if ((low != 0) ^ (m->base < 0x100000)) continue; try = (m->base & ~(align-1)) + *base; @@ -581,9 +618,9 @@ break; } } - if (force_low) + if (low) break; - force_low++; + low++; } out: up(&rsrc_sem); diff -Nru a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c --- a/drivers/pcmcia/yenta.c Sun Jun 15 08:32:41 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,974 +0,0 @@ -/* - * Regular cardbus driver ("yenta") - * - * (C) Copyright 1999, 2000 Linus Torvalds - * - * Changelog: - * Aug 2002: Manfred Spraul - * Dynamically adjust the size of the bridge resource - * - * May 2003: Dominik Brodowski - * Merge pci_socket.c and yenta.c into one file - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "yenta.h" -#include "i82365.h" - - -#if 0 -#define DEBUG(x,args...) printk("%s: " x, __FUNCTION__, ##args) -#else -#define DEBUG(x,args...) -#endif - -/* Don't ask.. */ -#define to_cycles(ns) ((ns)/120) -#define to_ns(cycles) ((cycles)*120) - -/* - * Generate easy-to-use ways of reading a cardbus sockets - * regular memory space ("cb_xxx"), configuration space - * ("config_xxx") and compatibility space ("exca_xxxx") - */ -static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg) -{ - u32 val = readl(socket->base + reg); - DEBUG("%p %04x %08x\n", socket, reg, val); - return val; -} - -static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) -{ - DEBUG("%p %04x %08x\n", socket, reg, val); - writel(val, socket->base + reg); -} - -static inline u8 config_readb(struct yenta_socket *socket, unsigned offset) -{ - u8 val; - pci_read_config_byte(socket->dev, offset, &val); - DEBUG("%p %04x %02x\n", socket, offset, val); - return val; -} - -static inline u16 config_readw(struct yenta_socket *socket, unsigned offset) -{ - u16 val; - pci_read_config_word(socket->dev, offset, &val); - DEBUG("%p %04x %04x\n", socket, offset, val); - return val; -} - -static inline u32 config_readl(struct yenta_socket *socket, unsigned offset) -{ - u32 val; - pci_read_config_dword(socket->dev, offset, &val); - DEBUG("%p %04x %08x\n", socket, offset, val); - return val; -} - -static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val) -{ - DEBUG("%p %04x %02x\n", socket, offset, val); - pci_write_config_byte(socket->dev, offset, val); -} - -static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val) -{ - DEBUG("%p %04x %04x\n", socket, offset, val); - pci_write_config_word(socket->dev, offset, val); -} - -static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val) -{ - DEBUG("%p %04x %08x\n", socket, offset, val); - pci_write_config_dword(socket->dev, offset, val); -} - -static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg) -{ - u8 val = readb(socket->base + 0x800 + reg); - DEBUG("%p %04x %02x\n", socket, reg, val); - return val; -} - -static inline u8 exca_readw(struct yenta_socket *socket, unsigned reg) -{ - u16 val; - val = readb(socket->base + 0x800 + reg); - val |= readb(socket->base + 0x800 + reg + 1) << 8; - DEBUG("%p %04x %04x\n", socket, reg, val); - return val; -} - -static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val) -{ - DEBUG("%p %04x %02x\n", socket, reg, val); - writeb(val, socket->base + 0x800 + reg); -} - -static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) -{ - DEBUG("%p %04x %04x\n", socket, reg, val); - writeb(val, socket->base + 0x800 + reg); - writeb(val >> 8, socket->base + 0x800 + reg + 1); -} - -/* - * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend - * on what kind of card is inserted.. - */ -static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - unsigned int val; - u32 state = cb_readl(socket, CB_SOCKET_STATE); - - val = (state & CB_3VCARD) ? SS_3VCARD : 0; - val |= (state & CB_XVCARD) ? SS_XVCARD : 0; - val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD - | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; - - if (state & CB_CBCARD) { - val |= SS_CARDBUS; - val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; - val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; - val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; - } else { - u8 status = exca_readb(socket, I365_STATUS); - val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; - if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { - val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; - } else { - val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; - val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; - } - val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; - val |= (status & I365_CS_READY) ? SS_READY : 0; - val |= (status & I365_CS_POWERON) ? SS_POWERON : 0; - } - - *value = val; - return 0; -} - -static int yenta_Vcc_power(u32 control) -{ - switch (control & CB_SC_VCC_MASK) { - case CB_SC_VCC_5V: return 50; - case CB_SC_VCC_3V: return 33; - default: return 0; - } -} - -static int yenta_Vpp_power(u32 control) -{ - switch (control & CB_SC_VPP_MASK) { - case CB_SC_VPP_12V: return 120; - case CB_SC_VPP_5V: return 50; - case CB_SC_VPP_3V: return 33; - default: return 0; - } -} - -static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - u8 reg; - u32 control; - - control = cb_readl(socket, CB_SOCKET_CONTROL); - - state->Vcc = yenta_Vcc_power(control); - state->Vpp = yenta_Vpp_power(control); - state->io_irq = socket->io_irq; - - if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { - u16 bridge = config_readw(socket, CB_BRIDGE_CONTROL); - if (bridge & CB_BRIDGE_CRST) - state->flags |= SS_RESET; - return 0; - } - - /* 16-bit card state.. */ - reg = exca_readb(socket, I365_POWER); - state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; - state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; - - reg = exca_readb(socket, I365_INTCTL); - state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; - state->flags |= (reg & I365_PC_IOCARD) ? SS_IOCARD : 0; - - reg = exca_readb(socket, I365_CSCINT); - state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; - if (state->flags & SS_IOCARD) { - state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; - } else { - state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; - state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; - state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; - } - - return 0; -} - -static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) -{ - u32 reg = 0; /* CB_SC_STPCLK? */ - switch (state->Vcc) { - case 33: reg = CB_SC_VCC_3V; break; - case 50: reg = CB_SC_VCC_5V; break; - default: reg = 0; break; - } - switch (state->Vpp) { - case 33: reg |= CB_SC_VPP_3V; break; - case 50: reg |= CB_SC_VPP_5V; break; - case 120: reg |= CB_SC_VPP_12V; break; - } - if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) - cb_writel(socket, CB_SOCKET_CONTROL, reg); -} - -static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - u16 bridge; - - if (state->flags & SS_DEBOUNCED) { - /* The insertion debounce period has ended. Clear any pending insertion events */ - socket->events &= ~SS_DETECT; - state->flags &= ~SS_DEBOUNCED; /* SS_DEBOUNCED is oneshot */ - } - yenta_set_power(socket, state); - socket->io_irq = state->io_irq; - bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); - if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { - u8 intr; - bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; - - /* ISA interrupt control? */ - intr = exca_readb(socket, I365_INTCTL); - intr = (intr & ~0xf); - if (!socket->cb_irq) { - intr |= state->io_irq; - bridge |= CB_BRIDGE_INTR; - } - exca_writeb(socket, I365_INTCTL, intr); - } else { - u8 reg; - - reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA); - reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; - reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; - if (state->io_irq != socket->cb_irq) { - reg |= state->io_irq; - bridge |= CB_BRIDGE_INTR; - } - exca_writeb(socket, I365_INTCTL, reg); - - reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK); - reg |= I365_PWR_NORESET; - if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; - if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; - if (exca_readb(socket, I365_POWER) != reg) - exca_writeb(socket, I365_POWER, reg); - - /* CSC interrupt: no ISA irq for CSC */ - reg = I365_CSC_DETECT; - if (state->flags & SS_IOCARD) { - if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; - } else { - if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; - if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; - if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; - } - exca_writeb(socket, I365_CSCINT, reg); - exca_readb(socket, I365_CSC); - } - config_writew(socket, CB_BRIDGE_CONTROL, bridge); - /* Socket event mask: get card insert/remove events.. */ - cb_writel(socket, CB_SOCKET_EVENT, -1); - cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); - return 0; -} - -static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - int map; - unsigned char ioctl, addr, enable; - - map = io->map; - - if (map > 1) - return -EINVAL; - - enable = I365_ENA_IO(map); - addr = exca_readb(socket, I365_ADDRWIN); - - /* Disable the window before changing it.. */ - if (addr & enable) { - addr &= ~enable; - exca_writeb(socket, I365_ADDRWIN, addr); - } - - exca_writew(socket, I365_IO(map)+I365_W_START, io->start); - exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop); - - ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); - if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); - if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); - if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); - exca_writeb(socket, I365_IOCTL, ioctl); - - if (io->flags & MAP_ACTIVE) - exca_writeb(socket, I365_ADDRWIN, addr | enable); - return 0; -} - -static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - int map; - unsigned char addr, enable; - unsigned int start, stop, card_start; - unsigned short word; - - map = mem->map; - start = mem->sys_start; - stop = mem->sys_stop; - card_start = mem->card_start; - - if (map > 4 || start > stop || ((start ^ stop) >> 24) || - (card_start >> 26) || mem->speed > 1000) - return -EINVAL; - - enable = I365_ENA_MEM(map); - addr = exca_readb(socket, I365_ADDRWIN); - if (addr & enable) { - addr &= ~enable; - exca_writeb(socket, I365_ADDRWIN, addr); - } - - exca_writeb(socket, CB_MEM_PAGE(map), start >> 24); - - word = (start >> 12) & 0x0fff; - if (mem->flags & MAP_16BIT) - word |= I365_MEM_16BIT; - if (mem->flags & MAP_0WS) - word |= I365_MEM_0WS; - exca_writew(socket, I365_MEM(map) + I365_W_START, word); - - word = (stop >> 12) & 0x0fff; - switch (to_cycles(mem->speed)) { - case 0: break; - case 1: word |= I365_MEM_WS0; break; - case 2: word |= I365_MEM_WS1; break; - default: word |= I365_MEM_WS1 | I365_MEM_WS0; break; - } - exca_writew(socket, I365_MEM(map) + I365_W_STOP, word); - - word = ((card_start - start) >> 12) & 0x3fff; - if (mem->flags & MAP_WRPROT) - word |= I365_MEM_WRPROT; - if (mem->flags & MAP_ATTRIB) - word |= I365_MEM_REG; - exca_writew(socket, I365_MEM(map) + I365_W_OFF, word); - - if (mem->flags & MAP_ACTIVE) - exca_writeb(socket, I365_ADDRWIN, addr | enable); - return 0; -} - - -static unsigned int yenta_events(struct yenta_socket *socket) -{ - u8 csc; - u32 cb_event; - unsigned int events; - - /* Clear interrupt status for the event */ - cb_event = cb_readl(socket, CB_SOCKET_EVENT); - cb_writel(socket, CB_SOCKET_EVENT, cb_event); - - csc = exca_readb(socket, I365_CSC); - - events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; - events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; - if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { - events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; - } else { - events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; - events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; - events |= (csc & I365_CSC_READY) ? SS_READY : 0; - } - return events; -} - - -static void yenta_bh(void *data) -{ - struct yenta_socket *socket = data; - unsigned int events; - - spin_lock_irq(&socket->event_lock); - events = socket->events; - socket->events = 0; - spin_unlock_irq(&socket->event_lock); - if (socket->handler) - socket->handler(socket->info, events); -} - -static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned int events; - struct yenta_socket *socket = (struct yenta_socket *) dev_id; - - events = yenta_events(socket); - if (events) { - spin_lock(&socket->event_lock); - socket->events |= events; - spin_unlock(&socket->event_lock); - schedule_work(&socket->tq_task); - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -static void yenta_interrupt_wrapper(unsigned long data) -{ - struct yenta_socket *socket = (struct yenta_socket *) data; - - yenta_interrupt(0, (void *)socket, NULL); - socket->poll_timer.expires = jiffies + HZ; - add_timer(&socket->poll_timer); -} - -/* - * Only probe "regular" interrupts, don't - * touch dangerous spots like the mouse irq, - * because there are mice that apparently - * get really confused if they get fondled - * too intimately. - * - * Default to 11, 10, 9, 7, 6, 5, 4, 3. - */ -static u32 isa_interrupts = 0x0ef8; - -static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask) -{ - int i; - unsigned long val; - u16 bridge_ctrl; - u32 mask; - - /* Set up ISA irq routing to probe the ISA irqs.. */ - bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); - if (!(bridge_ctrl & CB_BRIDGE_INTR)) { - bridge_ctrl |= CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - } - - /* - * Probe for usable interrupts using the force - * register to generate bogus card status events. - */ - cb_writel(socket, CB_SOCKET_EVENT, -1); - cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); - exca_writeb(socket, I365_CSCINT, 0); - val = probe_irq_on() & isa_irq_mask; - for (i = 1; i < 16; i++) { - if (!((val >> i) & 1)) - continue; - exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); - cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); - udelay(100); - cb_writel(socket, CB_SOCKET_EVENT, -1); - } - cb_writel(socket, CB_SOCKET_MASK, 0); - exca_writeb(socket, I365_CSCINT, 0); - - mask = probe_irq_mask(val) & 0xffff; - - bridge_ctrl &= ~CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); - - return mask; -} - -/* - * Set static data that doesn't need re-initializing.. - */ -static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask) -{ - socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; - socket->socket.map_size = 0x1000; - socket->socket.pci_irq = socket->cb_irq; - socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); - socket->socket.cb_dev = socket->dev; - - printk("Yenta IRQ list %04x, PCI irq%d\n", socket->socket.irq_mask, socket->cb_irq); -} - - -static void yenta_clear_maps(struct yenta_socket *socket) -{ - int i; - pccard_io_map io = { 0, 0, 0, 0, 1 }; - pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; - - mem.sys_stop = 0x0fff; - yenta_set_socket(&socket->socket, &dead_socket); - for (i = 0; i < 2; i++) { - io.map = i; - yenta_set_io_map(&socket->socket, &io); - } - for (i = 0; i < 5; i++) { - mem.map = i; - yenta_set_mem_map(&socket->socket, &mem); - } -} - -/* - * Initialize the standard cardbus registers - */ -static void yenta_config_init(struct yenta_socket *socket) -{ - u16 bridge; - struct pci_dev *dev = socket->dev; - - pci_set_power_state(socket->dev, 0); - - config_writel(socket, CB_LEGACY_MODE_BASE, 0); - config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); - config_writew(socket, PCI_COMMAND, - PCI_COMMAND_IO | - PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | - PCI_COMMAND_WAIT); - - /* MAGIC NUMBERS! Fixme */ - config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); - config_writeb(socket, PCI_LATENCY_TIMER, 168); - config_writel(socket, PCI_PRIMARY_BUS, - (176 << 24) | /* sec. latency timer */ - (dev->subordinate->subordinate << 16) | /* subordinate bus */ - (dev->subordinate->secondary << 8) | /* secondary bus */ - dev->subordinate->primary); /* primary bus */ - - /* - * Set up the bridging state: - * - enable write posting. - * - memory window 0 prefetchable, window 1 non-prefetchable - * - PCI interrupts enabled if a PCI interrupt exists.. - */ - bridge = config_readw(socket, CB_BRIDGE_CONTROL); - bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); - bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; - if (!socket->cb_irq) - bridge |= CB_BRIDGE_INTR; - config_writew(socket, CB_BRIDGE_CONTROL, bridge); - - exca_writeb(socket, I365_GBLCTL, 0x00); - exca_writeb(socket, I365_GENCTL, 0x00); - - /* Redo card voltage interrogation */ - cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); -} - -/* Called at resume and initialization events */ -static int yenta_init(struct pcmcia_socket *sock) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - yenta_config_init(socket); - yenta_clear_maps(socket); - - /* Re-enable interrupts */ - cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); - return 0; -} - -static int yenta_suspend(struct pcmcia_socket *sock) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - - yenta_set_socket(sock, &dead_socket); - - /* Disable interrupts */ - cb_writel(socket, CB_SOCKET_MASK, 0x0); - - /* - * This does not work currently. The controller - * loses too much information during D3 to come up - * cleanly. We should probably fix yenta_init() - * to update all the critical registers, notably - * the IO and MEM bridging region data.. That is - * something that pci_set_power_state() should - * probably know about bridges anyway. - * - pci_set_power_state(socket->dev, 3); - */ - - return 0; -} - -/* - * Use an adaptive allocation for the memory resource, - * sometimes the memory behind pci bridges is limited: - * 1/8 of the size of the io window of the parent. - * max 4 MB, min 16 kB. - */ -#define BRIDGE_MEM_MAX 4*1024*1024 -#define BRIDGE_MEM_MIN 16*1024 - -#define BRIDGE_IO_MAX 256 -#define BRIDGE_IO_MIN 32 - -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) -{ - struct pci_bus *bus; - struct resource *root, *res; - u32 start, end; - u32 align, size, min; - unsigned offset; - unsigned mask; - - /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ - mask = ~0xfff; - if (type & IORESOURCE_IO) - mask = ~3; - - offset = 0x1c + 8*nr; - bus = socket->dev->subordinate; - res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; - res->name = bus->name; - res->flags = type; - res->start = 0; - res->end = 0; - root = pci_find_parent_resource(socket->dev, res); - - if (!root) - return; - - start = config_readl(socket, offset) & mask; - end = config_readl(socket, offset+4) | ~mask; - if (start && end > start) { - res->start = start; - res->end = end; - if (request_resource(root, res) == 0) - return; - printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", - socket->dev->slot_name, nr); - res->start = res->end = 0; - } - - if (type & IORESOURCE_IO) { - align = 1024; - size = BRIDGE_IO_MAX; - min = BRIDGE_IO_MIN; - start = PCIBIOS_MIN_IO; - end = ~0U; - } else { - unsigned long avail = root->end - root->start; - int i; - size = BRIDGE_MEM_MAX; - if (size > avail/8) { - size=(avail+1)/8; - /* round size down to next power of 2 */ - i = 0; - while ((size /= 2) != 0) - i++; - size = 1 << i; - } - if (size < BRIDGE_MEM_MIN) - size = BRIDGE_MEM_MIN; - min = BRIDGE_MEM_MIN; - align = size; - start = PCIBIOS_MIN_MEM; - end = ~0U; - } - - do { - if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { - config_writel(socket, offset, res->start); - config_writel(socket, offset+4, res->end); - return; - } - size = size/2; - align = size; - } while (size >= min); - printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", - socket->dev->slot_name, type); - res->start = res->end = 0; -} - -/* - * Allocate the bridge mappings for the device.. - */ -static void yenta_allocate_resources(struct yenta_socket *socket) -{ - yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); - yenta_allocate_res(socket, 1, IORESOURCE_MEM); - yenta_allocate_res(socket, 2, IORESOURCE_IO); - yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ -} - - -/* - * Free the bridge mappings for the device.. - */ -static void yenta_free_resources(struct yenta_socket *socket) -{ - int i; - for (i=0;i<4;i++) { - struct resource *res; - res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; - if (res->start != 0 && res->end != 0) - release_resource(res); - res->start = res->end = 0; - } -} - - -/* - * Close it down - release our resources and go home.. - */ -static void yenta_close(struct pci_dev *dev) -{ - struct yenta_socket *sock = pci_get_drvdata(dev); - - /* we don't want a dying socket registered */ - pcmcia_unregister_socket(&sock->socket); - - /* Disable all events so we don't die in an IRQ storm */ - cb_writel(sock, CB_SOCKET_MASK, 0x0); - exca_writeb(sock, I365_CSCINT, 0); - - if (sock->cb_irq) - free_irq(sock->cb_irq, sock); - else - del_timer_sync(&sock->poll_timer); - - if (sock->base) - iounmap(sock->base); - yenta_free_resources(sock); - - pci_set_drvdata(dev, NULL); -} - - -static int yenta_register_callback(struct pcmcia_socket *sock, void (*handler)(void *, unsigned int), void * info) -{ - struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); - - socket->handler = handler; - socket->info = info; - return 0; -} - - -static struct pccard_operations yenta_socket_operations = { - .owner = THIS_MODULE, - .init = yenta_init, - .suspend = yenta_suspend, - .register_callback = yenta_register_callback, - .get_status = yenta_get_status, - .get_socket = yenta_get_socket, - .set_socket = yenta_set_socket, - .set_io_map = yenta_set_io_map, - .set_mem_map = yenta_set_mem_map, -}; - - -#include "ti113x.h" -#include "ricoh.h" - -/* - * Different cardbus controllers have slightly different - * initialization sequences etc details. List them here.. - */ -#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y -struct cardbus_override_struct { - unsigned short vendor; - unsigned short device; - int (*override) (struct yenta_socket *socket); -} cardbus_override[] = { - { PD(TI,1130), &ti113x_override }, - { PD(TI,1031), &ti_override }, - { PD(TI,1131), &ti113x_override }, - { PD(TI,1250), &ti1250_override }, - { PD(TI,1220), &ti_override }, - { PD(TI,1221), &ti_override }, - { PD(TI,1210), &ti_override }, - { PD(TI,1450), &ti_override }, - { PD(TI,1225), &ti_override }, - { PD(TI,1251A), &ti_override }, - { PD(TI,1211), &ti_override }, - { PD(TI,1251B), &ti_override }, - { PD(TI,1410), ti1250_override }, - { PD(TI,1420), &ti_override }, - { PD(TI,4410), &ti_override }, - { PD(TI,4451), &ti_override }, - - { PD(RICOH,RL5C465), &ricoh_override }, - { PD(RICOH,RL5C466), &ricoh_override }, - { PD(RICOH,RL5C475), &ricoh_override }, - { PD(RICOH,RL5C476), &ricoh_override }, - { PD(RICOH,RL5C478), &ricoh_override }, - - { }, /* all zeroes */ -}; - - -/* - * Initialize a cardbus controller. Make sure we have a usable - * interrupt, and that we can map the cardbus area. Fill in the - * socket information structure.. - */ -static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_id *id) -{ - struct yenta_socket *socket; - struct cardbus_override_struct *d; - - socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); - if (!socket) - return -ENOMEM; - memset(socket, 0, sizeof(*socket)); - - /* prepare pcmcia_socket */ - socket->socket.ss_entry = ¥ta_socket_operations; - socket->socket.dev.dev = &dev->dev; - socket->socket.driver_data = socket; - - /* prepare struct yenta_socket */ - socket->dev = dev; - pci_set_drvdata(dev, socket); - spin_lock_init(&socket->event_lock); - - /* - * Do some basic sanity checking.. - */ - if (pci_enable_device(dev)) - return -1; - if (!pci_resource_start(dev, 0)) { - printk("No cardbus resource!\n"); - return -1; - } - - /* - * Ok, start setup.. Map the cardbus registers, - * and request the IRQ. - */ - socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); - if (!socket->base) - return -1; - - yenta_config_init(socket); - - /* Disable all events */ - cb_writel(socket, CB_SOCKET_MASK, 0x0); - - /* Set up the bridge regions.. */ - yenta_allocate_resources(socket); - - socket->cb_irq = dev->irq; - - /* Do we have special options for the device? */ - d = cardbus_override; - while (d->override) { - if ((dev->vendor == d->vendor) && (dev->device == d->device)) { - int retval = d->override(socket); - if (retval < 0) - return retval; - } - d++; - } - - /* We must finish initialization here */ - - INIT_WORK(&socket->tq_task, yenta_bh, socket); - - if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) { - /* No IRQ or request_irq failed. Poll */ - socket->cb_irq = 0; /* But zero is a valid IRQ number. */ - init_timer(&socket->poll_timer); - socket->poll_timer.function = yenta_interrupt_wrapper; - socket->poll_timer.data = (unsigned long)socket; - socket->poll_timer.expires = jiffies + HZ; - add_timer(&socket->poll_timer); - } - - /* Figure out what the dang thing can do for the PCMCIA layer... */ - yenta_get_socket_capabilities(socket, isa_interrupts); - printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); - - /* Register it with the pcmcia layer.. */ - return pcmcia_register_socket(&socket->socket); -} - - -static int yenta_dev_suspend (struct pci_dev *dev, u32 state) -{ - return pcmcia_socket_dev_suspend(&dev->dev, state, 0); -} - - -static int yenta_dev_resume (struct pci_dev *dev) -{ - return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); -} - - -static struct pci_device_id yenta_table [] __devinitdata = { { - .class = PCI_CLASS_BRIDGE_CARDBUS << 8, - .class_mask = ~0, - - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* all zeroes */ } -}; -MODULE_DEVICE_TABLE(pci, yenta_table); - - -static struct pci_driver yenta_cardbus_driver = { - .name = "yenta_cardbus", - .id_table = yenta_table, - .probe = yenta_probe, - .remove = __devexit_p(yenta_close), - .suspend = yenta_dev_suspend, - .resume = yenta_dev_resume, -}; - - -static int __init yenta_socket_init(void) -{ - return pci_register_driver (¥ta_cardbus_driver); -} - - -static void __exit yenta_socket_exit (void) -{ - pci_unregister_driver (¥ta_cardbus_driver); -} - - -module_init(yenta_socket_init); -module_exit(yenta_socket_exit); - -MODULE_LICENSE("GPL"); diff -Nru a/drivers/pcmcia/yenta.h b/drivers/pcmcia/yenta.h --- a/drivers/pcmcia/yenta.h Sun Jun 15 08:20:53 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,116 +0,0 @@ -#ifndef __YENTA_H -#define __YENTA_H - -#include - -#define CB_SOCKET_EVENT 0x00 -#define CB_CSTSEVENT 0x00000001 /* Card status event */ -#define CB_CD1EVENT 0x00000002 /* Card detect 1 change event */ -#define CB_CD2EVENT 0x00000004 /* Card detect 2 change event */ -#define CB_PWREVENT 0x00000008 /* PWRCYCLE change event */ - -#define CB_SOCKET_MASK 0x04 -#define CB_CSTSMASK 0x00000001 /* Card status mask */ -#define CB_CDMASK 0x00000006 /* Card detect 1&2 mask */ -#define CB_PWRMASK 0x00000008 /* PWRCYCLE change mask */ - -#define CB_SOCKET_STATE 0x08 -#define CB_CARDSTS 0x00000001 /* CSTSCHG status */ -#define CB_CDETECT1 0x00000002 /* Card detect status 1 */ -#define CB_CDETECT2 0x00000004 /* Card detect status 2 */ -#define CB_PWRCYCLE 0x00000008 /* Socket powered */ -#define CB_16BITCARD 0x00000010 /* 16-bit card detected */ -#define CB_CBCARD 0x00000020 /* CardBus card detected */ -#define CB_IREQCINT 0x00000040 /* READY(xIRQ)/xCINT high */ -#define CB_NOTACARD 0x00000080 /* Unrecognizable PC card detected */ -#define CB_DATALOST 0x00000100 /* Potential data loss due to card removal */ -#define CB_BADVCCREQ 0x00000200 /* Invalid Vcc request by host software */ -#define CB_5VCARD 0x00000400 /* Card Vcc at 5.0 volts? */ -#define CB_3VCARD 0x00000800 /* Card Vcc at 3.3 volts? */ -#define CB_XVCARD 0x00001000 /* Card Vcc at X.X volts? */ -#define CB_YVCARD 0x00002000 /* Card Vcc at Y.Y volts? */ -#define CB_5VSOCKET 0x10000000 /* Socket Vcc at 5.0 volts? */ -#define CB_3VSOCKET 0x20000000 /* Socket Vcc at 3.3 volts? */ -#define CB_XVSOCKET 0x40000000 /* Socket Vcc at X.X volts? */ -#define CB_YVSOCKET 0x80000000 /* Socket Vcc at Y.Y volts? */ - -#define CB_SOCKET_FORCE 0x0C -#define CB_FCARDSTS 0x00000001 /* Force CSTSCHG */ -#define CB_FCDETECT1 0x00000002 /* Force CD1EVENT */ -#define CB_FCDETECT2 0x00000004 /* Force CD2EVENT */ -#define CB_FPWRCYCLE 0x00000008 /* Force PWREVENT */ -#define CB_F16BITCARD 0x00000010 /* Force 16-bit PCMCIA card */ -#define CB_FCBCARD 0x00000020 /* Force CardBus line */ -#define CB_FNOTACARD 0x00000080 /* Force NOTACARD */ -#define CB_FDATALOST 0x00000100 /* Force data lost */ -#define CB_FBADVCCREQ 0x00000200 /* Force bad Vcc request */ -#define CB_F5VCARD 0x00000400 /* Force 5.0 volt card */ -#define CB_F3VCARD 0x00000800 /* Force 3.3 volt card */ -#define CB_FXVCARD 0x00001000 /* Force X.X volt card */ -#define CB_FYVCARD 0x00002000 /* Force Y.Y volt card */ -#define CB_CVSTEST 0x00004000 /* Card VS test */ - -#define CB_SOCKET_CONTROL 0x10 -#define CB_SC_VPP_MASK 0x00000007 -#define CB_SC_VPP_OFF 0x00000000 -#define CB_SC_VPP_12V 0x00000001 -#define CB_SC_VPP_5V 0x00000002 -#define CB_SC_VPP_3V 0x00000003 -#define CB_SC_VPP_XV 0x00000004 -#define CB_SC_VPP_YV 0x00000005 -#define CB_SC_VCC_MASK 0x00000070 -#define CB_SC_VCC_OFF 0x00000000 -#define CB_SC_VCC_5V 0x00000020 -#define CB_SC_VCC_3V 0x00000030 -#define CB_SC_VCC_XV 0x00000040 -#define CB_SC_VCC_YV 0x00000050 -#define CB_SC_CCLK_STOP 0x00000080 - -#define CB_SOCKET_POWER 0x20 -#define CB_SKTACCES 0x02000000 /* A PC card access has occurred (clear on read) */ -#define CB_SKTMODE 0x01000000 /* Clock frequency has changed (clear on read) */ -#define CB_CLKCTRLEN 0x00010000 /* Clock control enabled (RW) */ -#define CB_CLKCTRL 0x00000001 /* Stop(0) or slow(1) CB clock (RW) */ - -/* - * Cardbus configuration space - */ -#define CB_BRIDGE_BASE(m) (0x1c + 8*(m)) -#define CB_BRIDGE_LIMIT(m) (0x20 + 8*(m)) -#define CB_BRIDGE_CONTROL 0x3e -#define CB_BRIDGE_CPERREN 0x00000001 -#define CB_BRIDGE_CSERREN 0x00000002 -#define CB_BRIDGE_ISAEN 0x00000004 -#define CB_BRIDGE_VGAEN 0x00000008 -#define CB_BRIDGE_MABTMODE 0x00000020 -#define CB_BRIDGE_CRST 0x00000040 -#define CB_BRIDGE_INTR 0x00000080 -#define CB_BRIDGE_PREFETCH0 0x00000100 -#define CB_BRIDGE_PREFETCH1 0x00000200 -#define CB_BRIDGE_POSTEN 0x00000400 -#define CB_LEGACY_MODE_BASE 0x44 - -/* - * ExCA area extensions in Yenta - */ -#define CB_MEM_PAGE(map) (0x40 + (map)) - -struct yenta_socket { - struct pci_dev *dev; - int cb_irq, io_irq; - void *base; - void (*handler)(void *, unsigned int); - void *info; - spinlock_t event_lock; - unsigned int events; - struct work_struct tq_task; - struct timer_list poll_timer; - - struct pcmcia_socket socket; - - /* A few words of private data for special stuff of overrides... */ - unsigned int private[8]; -}; - - -#endif diff -Nru a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pcmcia/yenta_socket.c Mon Jun 16 08:06:42 2003 @@ -0,0 +1,974 @@ +/* + * Regular cardbus driver ("yenta_socket") + * + * (C) Copyright 1999, 2000 Linus Torvalds + * + * Changelog: + * Aug 2002: Manfred Spraul + * Dynamically adjust the size of the bridge resource + * + * May 2003: Dominik Brodowski + * Merge pci_socket.c and yenta.c into one file + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "yenta_socket.h" +#include "i82365.h" + + +#if 0 +#define DEBUG(x,args...) printk("%s: " x, __FUNCTION__, ##args) +#else +#define DEBUG(x,args...) +#endif + +/* Don't ask.. */ +#define to_cycles(ns) ((ns)/120) +#define to_ns(cycles) ((cycles)*120) + +/* + * Generate easy-to-use ways of reading a cardbus sockets + * regular memory space ("cb_xxx"), configuration space + * ("config_xxx") and compatibility space ("exca_xxxx") + */ +static inline u32 cb_readl(struct yenta_socket *socket, unsigned reg) +{ + u32 val = readl(socket->base + reg); + DEBUG("%p %04x %08x\n", socket, reg, val); + return val; +} + +static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, reg, val); + writel(val, socket->base + reg); +} + +static inline u8 config_readb(struct yenta_socket *socket, unsigned offset) +{ + u8 val; + pci_read_config_byte(socket->dev, offset, &val); + DEBUG("%p %04x %02x\n", socket, offset, val); + return val; +} + +static inline u16 config_readw(struct yenta_socket *socket, unsigned offset) +{ + u16 val; + pci_read_config_word(socket->dev, offset, &val); + DEBUG("%p %04x %04x\n", socket, offset, val); + return val; +} + +static inline u32 config_readl(struct yenta_socket *socket, unsigned offset) +{ + u32 val; + pci_read_config_dword(socket->dev, offset, &val); + DEBUG("%p %04x %08x\n", socket, offset, val); + return val; +} + +static inline void config_writeb(struct yenta_socket *socket, unsigned offset, u8 val) +{ + DEBUG("%p %04x %02x\n", socket, offset, val); + pci_write_config_byte(socket->dev, offset, val); +} + +static inline void config_writew(struct yenta_socket *socket, unsigned offset, u16 val) +{ + DEBUG("%p %04x %04x\n", socket, offset, val); + pci_write_config_word(socket->dev, offset, val); +} + +static inline void config_writel(struct yenta_socket *socket, unsigned offset, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, offset, val); + pci_write_config_dword(socket->dev, offset, val); +} + +static inline u8 exca_readb(struct yenta_socket *socket, unsigned reg) +{ + u8 val = readb(socket->base + 0x800 + reg); + DEBUG("%p %04x %02x\n", socket, reg, val); + return val; +} + +static inline u8 exca_readw(struct yenta_socket *socket, unsigned reg) +{ + u16 val; + val = readb(socket->base + 0x800 + reg); + val |= readb(socket->base + 0x800 + reg + 1) << 8; + DEBUG("%p %04x %04x\n", socket, reg, val); + return val; +} + +static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val) +{ + DEBUG("%p %04x %02x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); +} + +static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) +{ + DEBUG("%p %04x %04x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); + writeb(val >> 8, socket->base + 0x800 + reg + 1); +} + +/* + * Ugh, mixed-mode cardbus and 16-bit pccard state: things depend + * on what kind of card is inserted.. + */ +static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + unsigned int val; + u32 state = cb_readl(socket, CB_SOCKET_STATE); + + val = (state & CB_3VCARD) ? SS_3VCARD : 0; + val |= (state & CB_XVCARD) ? SS_XVCARD : 0; + val |= (state & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD + | CB_XVCARD | CB_YVCARD)) ? 0 : SS_PENDING; + + if (state & CB_CBCARD) { + val |= SS_CARDBUS; + val |= (state & CB_CARDSTS) ? SS_STSCHG : 0; + val |= (state & (CB_CDETECT1 | CB_CDETECT2)) ? 0 : SS_DETECT; + val |= (state & CB_PWRCYCLE) ? SS_POWERON | SS_READY : 0; + } else { + u8 status = exca_readb(socket, I365_STATUS); + val |= ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; + if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { + val |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; + } else { + val |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; + val |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; + } + val |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; + val |= (status & I365_CS_READY) ? SS_READY : 0; + val |= (status & I365_CS_POWERON) ? SS_POWERON : 0; + } + + *value = val; + return 0; +} + +static int yenta_Vcc_power(u32 control) +{ + switch (control & CB_SC_VCC_MASK) { + case CB_SC_VCC_5V: return 50; + case CB_SC_VCC_3V: return 33; + default: return 0; + } +} + +static int yenta_Vpp_power(u32 control) +{ + switch (control & CB_SC_VPP_MASK) { + case CB_SC_VPP_12V: return 120; + case CB_SC_VPP_5V: return 50; + case CB_SC_VPP_3V: return 33; + default: return 0; + } +} + +static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + u8 reg; + u32 control; + + control = cb_readl(socket, CB_SOCKET_CONTROL); + + state->Vcc = yenta_Vcc_power(control); + state->Vpp = yenta_Vpp_power(control); + state->io_irq = socket->io_irq; + + if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { + u16 bridge = config_readw(socket, CB_BRIDGE_CONTROL); + if (bridge & CB_BRIDGE_CRST) + state->flags |= SS_RESET; + return 0; + } + + /* 16-bit card state.. */ + reg = exca_readb(socket, I365_POWER); + state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; + state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; + + reg = exca_readb(socket, I365_INTCTL); + state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; + state->flags |= (reg & I365_PC_IOCARD) ? SS_IOCARD : 0; + + reg = exca_readb(socket, I365_CSCINT); + state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; + if (state->flags & SS_IOCARD) { + state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; + } else { + state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; + state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; + state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; + } + + return 0; +} + +static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) +{ + u32 reg = 0; /* CB_SC_STPCLK? */ + switch (state->Vcc) { + case 33: reg = CB_SC_VCC_3V; break; + case 50: reg = CB_SC_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 33: reg |= CB_SC_VPP_3V; break; + case 50: reg |= CB_SC_VPP_5V; break; + case 120: reg |= CB_SC_VPP_12V; break; + } + if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) + cb_writel(socket, CB_SOCKET_CONTROL, reg); +} + +static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + u16 bridge; + + if (state->flags & SS_DEBOUNCED) { + /* The insertion debounce period has ended. Clear any pending insertion events */ + socket->events &= ~SS_DETECT; + state->flags &= ~SS_DEBOUNCED; /* SS_DEBOUNCED is oneshot */ + } + yenta_set_power(socket, state); + socket->io_irq = state->io_irq; + bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); + if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { + u8 intr; + bridge |= (state->flags & SS_RESET) ? CB_BRIDGE_CRST : 0; + + /* ISA interrupt control? */ + intr = exca_readb(socket, I365_INTCTL); + intr = (intr & ~0xf); + if (!socket->cb_irq) { + intr |= state->io_irq; + bridge |= CB_BRIDGE_INTR; + } + exca_writeb(socket, I365_INTCTL, intr); + } else { + u8 reg; + + reg = exca_readb(socket, I365_INTCTL) & (I365_RING_ENA | I365_INTR_ENA); + reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; + reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; + if (state->io_irq != socket->cb_irq) { + reg |= state->io_irq; + bridge |= CB_BRIDGE_INTR; + } + exca_writeb(socket, I365_INTCTL, reg); + + reg = exca_readb(socket, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK); + reg |= I365_PWR_NORESET; + if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; + if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; + if (exca_readb(socket, I365_POWER) != reg) + exca_writeb(socket, I365_POWER, reg); + + /* CSC interrupt: no ISA irq for CSC */ + reg = I365_CSC_DETECT; + if (state->flags & SS_IOCARD) { + if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; + } else { + if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1; + if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2; + if (state->csc_mask & SS_READY) reg |= I365_CSC_READY; + } + exca_writeb(socket, I365_CSCINT, reg); + exca_readb(socket, I365_CSC); + } + config_writew(socket, CB_BRIDGE_CONTROL, bridge); + /* Socket event mask: get card insert/remove events.. */ + cb_writel(socket, CB_SOCKET_EVENT, -1); + cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); + return 0; +} + +static int yenta_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + int map; + unsigned char ioctl, addr, enable; + + map = io->map; + + if (map > 1) + return -EINVAL; + + enable = I365_ENA_IO(map); + addr = exca_readb(socket, I365_ADDRWIN); + + /* Disable the window before changing it.. */ + if (addr & enable) { + addr &= ~enable; + exca_writeb(socket, I365_ADDRWIN, addr); + } + + exca_writew(socket, I365_IO(map)+I365_W_START, io->start); + exca_writew(socket, I365_IO(map)+I365_W_STOP, io->stop); + + ioctl = exca_readb(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); + if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); + if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); + if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); + exca_writeb(socket, I365_IOCTL, ioctl); + + if (io->flags & MAP_ACTIVE) + exca_writeb(socket, I365_ADDRWIN, addr | enable); + return 0; +} + +static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + int map; + unsigned char addr, enable; + unsigned int start, stop, card_start; + unsigned short word; + + map = mem->map; + start = mem->sys_start; + stop = mem->sys_stop; + card_start = mem->card_start; + + if (map > 4 || start > stop || ((start ^ stop) >> 24) || + (card_start >> 26) || mem->speed > 1000) + return -EINVAL; + + enable = I365_ENA_MEM(map); + addr = exca_readb(socket, I365_ADDRWIN); + if (addr & enable) { + addr &= ~enable; + exca_writeb(socket, I365_ADDRWIN, addr); + } + + exca_writeb(socket, CB_MEM_PAGE(map), start >> 24); + + word = (start >> 12) & 0x0fff; + if (mem->flags & MAP_16BIT) + word |= I365_MEM_16BIT; + if (mem->flags & MAP_0WS) + word |= I365_MEM_0WS; + exca_writew(socket, I365_MEM(map) + I365_W_START, word); + + word = (stop >> 12) & 0x0fff; + switch (to_cycles(mem->speed)) { + case 0: break; + case 1: word |= I365_MEM_WS0; break; + case 2: word |= I365_MEM_WS1; break; + default: word |= I365_MEM_WS1 | I365_MEM_WS0; break; + } + exca_writew(socket, I365_MEM(map) + I365_W_STOP, word); + + word = ((card_start - start) >> 12) & 0x3fff; + if (mem->flags & MAP_WRPROT) + word |= I365_MEM_WRPROT; + if (mem->flags & MAP_ATTRIB) + word |= I365_MEM_REG; + exca_writew(socket, I365_MEM(map) + I365_W_OFF, word); + + if (mem->flags & MAP_ACTIVE) + exca_writeb(socket, I365_ADDRWIN, addr | enable); + return 0; +} + + +static unsigned int yenta_events(struct yenta_socket *socket) +{ + u8 csc; + u32 cb_event; + unsigned int events; + + /* Clear interrupt status for the event */ + cb_event = cb_readl(socket, CB_SOCKET_EVENT); + cb_writel(socket, CB_SOCKET_EVENT, cb_event); + + csc = exca_readb(socket, I365_CSC); + + events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; + events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; + if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { + events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; + } else { + events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0; + events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0; + events |= (csc & I365_CSC_READY) ? SS_READY : 0; + } + return events; +} + + +static void yenta_bh(void *data) +{ + struct yenta_socket *socket = data; + unsigned int events; + + spin_lock_irq(&socket->event_lock); + events = socket->events; + socket->events = 0; + spin_unlock_irq(&socket->event_lock); + if (socket->handler) + socket->handler(socket->info, events); +} + +static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int events; + struct yenta_socket *socket = (struct yenta_socket *) dev_id; + + events = yenta_events(socket); + if (events) { + spin_lock(&socket->event_lock); + socket->events |= events; + spin_unlock(&socket->event_lock); + schedule_work(&socket->tq_task); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static void yenta_interrupt_wrapper(unsigned long data) +{ + struct yenta_socket *socket = (struct yenta_socket *) data; + + yenta_interrupt(0, (void *)socket, NULL); + socket->poll_timer.expires = jiffies + HZ; + add_timer(&socket->poll_timer); +} + +/* + * Only probe "regular" interrupts, don't + * touch dangerous spots like the mouse irq, + * because there are mice that apparently + * get really confused if they get fondled + * too intimately. + * + * Default to 11, 10, 9, 7, 6, 5, 4, 3. + */ +static u32 isa_interrupts = 0x0ef8; + +static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mask) +{ + int i; + unsigned long val; + u16 bridge_ctrl; + u32 mask; + + /* Set up ISA irq routing to probe the ISA irqs.. */ + bridge_ctrl = config_readw(socket, CB_BRIDGE_CONTROL); + if (!(bridge_ctrl & CB_BRIDGE_INTR)) { + bridge_ctrl |= CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); + } + + /* + * Probe for usable interrupts using the force + * register to generate bogus card status events. + */ + cb_writel(socket, CB_SOCKET_EVENT, -1); + cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK); + exca_writeb(socket, I365_CSCINT, 0); + val = probe_irq_on() & isa_irq_mask; + for (i = 1; i < 16; i++) { + if (!((val >> i) & 1)) + continue; + exca_writeb(socket, I365_CSCINT, I365_CSC_STSCHG | (i << 4)); + cb_writel(socket, CB_SOCKET_FORCE, CB_FCARDSTS); + udelay(100); + cb_writel(socket, CB_SOCKET_EVENT, -1); + } + cb_writel(socket, CB_SOCKET_MASK, 0); + exca_writeb(socket, I365_CSCINT, 0); + + mask = probe_irq_mask(val) & 0xffff; + + bridge_ctrl &= ~CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge_ctrl); + + return mask; +} + +/* + * Set static data that doesn't need re-initializing.. + */ +static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask) +{ + socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS; + socket->socket.map_size = 0x1000; + socket->socket.pci_irq = socket->cb_irq; + socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask); + socket->socket.cb_dev = socket->dev; + + printk("Yenta IRQ list %04x, PCI irq%d\n", socket->socket.irq_mask, socket->cb_irq); +} + + +static void yenta_clear_maps(struct yenta_socket *socket) +{ + int i; + pccard_io_map io = { 0, 0, 0, 0, 1 }; + pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; + + mem.sys_stop = 0x0fff; + yenta_set_socket(&socket->socket, &dead_socket); + for (i = 0; i < 2; i++) { + io.map = i; + yenta_set_io_map(&socket->socket, &io); + } + for (i = 0; i < 5; i++) { + mem.map = i; + yenta_set_mem_map(&socket->socket, &mem); + } +} + +/* + * Initialize the standard cardbus registers + */ +static void yenta_config_init(struct yenta_socket *socket) +{ + u16 bridge; + struct pci_dev *dev = socket->dev; + + pci_set_power_state(socket->dev, 0); + + config_writel(socket, CB_LEGACY_MODE_BASE, 0); + config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start); + config_writew(socket, PCI_COMMAND, + PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | + PCI_COMMAND_WAIT); + + /* MAGIC NUMBERS! Fixme */ + config_writeb(socket, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); + config_writeb(socket, PCI_LATENCY_TIMER, 168); + config_writel(socket, PCI_PRIMARY_BUS, + (176 << 24) | /* sec. latency timer */ + (dev->subordinate->subordinate << 16) | /* subordinate bus */ + (dev->subordinate->secondary << 8) | /* secondary bus */ + dev->subordinate->primary); /* primary bus */ + + /* + * Set up the bridging state: + * - enable write posting. + * - memory window 0 prefetchable, window 1 non-prefetchable + * - PCI interrupts enabled if a PCI interrupt exists.. + */ + bridge = config_readw(socket, CB_BRIDGE_CONTROL); + bridge &= ~(CB_BRIDGE_CRST | CB_BRIDGE_PREFETCH1 | CB_BRIDGE_INTR | CB_BRIDGE_ISAEN | CB_BRIDGE_VGAEN); + bridge |= CB_BRIDGE_PREFETCH0 | CB_BRIDGE_POSTEN; + if (!socket->cb_irq) + bridge |= CB_BRIDGE_INTR; + config_writew(socket, CB_BRIDGE_CONTROL, bridge); + + exca_writeb(socket, I365_GBLCTL, 0x00); + exca_writeb(socket, I365_GENCTL, 0x00); + + /* Redo card voltage interrogation */ + cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST); +} + +/* Called at resume and initialization events */ +static int yenta_init(struct pcmcia_socket *sock) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + yenta_config_init(socket); + yenta_clear_maps(socket); + + /* Re-enable interrupts */ + cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); + return 0; +} + +static int yenta_suspend(struct pcmcia_socket *sock) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + yenta_set_socket(sock, &dead_socket); + + /* Disable interrupts */ + cb_writel(socket, CB_SOCKET_MASK, 0x0); + + /* + * This does not work currently. The controller + * loses too much information during D3 to come up + * cleanly. We should probably fix yenta_init() + * to update all the critical registers, notably + * the IO and MEM bridging region data.. That is + * something that pci_set_power_state() should + * probably know about bridges anyway. + * + pci_set_power_state(socket->dev, 3); + */ + + return 0; +} + +/* + * Use an adaptive allocation for the memory resource, + * sometimes the memory behind pci bridges is limited: + * 1/8 of the size of the io window of the parent. + * max 4 MB, min 16 kB. + */ +#define BRIDGE_MEM_MAX 4*1024*1024 +#define BRIDGE_MEM_MIN 16*1024 + +#define BRIDGE_IO_MAX 256 +#define BRIDGE_IO_MIN 32 + +static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type) +{ + struct pci_bus *bus; + struct resource *root, *res; + u32 start, end; + u32 align, size, min; + unsigned offset; + unsigned mask; + + /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ + mask = ~0xfff; + if (type & IORESOURCE_IO) + mask = ~3; + + offset = 0x1c + 8*nr; + bus = socket->dev->subordinate; + res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; + res->name = bus->name; + res->flags = type; + res->start = 0; + res->end = 0; + root = pci_find_parent_resource(socket->dev, res); + + if (!root) + return; + + start = config_readl(socket, offset) & mask; + end = config_readl(socket, offset+4) | ~mask; + if (start && end > start) { + res->start = start; + res->end = end; + if (request_resource(root, res) == 0) + return; + printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n", + socket->dev->slot_name, nr); + res->start = res->end = 0; + } + + if (type & IORESOURCE_IO) { + align = 1024; + size = BRIDGE_IO_MAX; + min = BRIDGE_IO_MIN; + start = PCIBIOS_MIN_IO; + end = ~0U; + } else { + unsigned long avail = root->end - root->start; + int i; + size = BRIDGE_MEM_MAX; + if (size > avail/8) { + size=(avail+1)/8; + /* round size down to next power of 2 */ + i = 0; + while ((size /= 2) != 0) + i++; + size = 1 << i; + } + if (size < BRIDGE_MEM_MIN) + size = BRIDGE_MEM_MIN; + min = BRIDGE_MEM_MIN; + align = size; + start = PCIBIOS_MIN_MEM; + end = ~0U; + } + + do { + if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { + config_writel(socket, offset, res->start); + config_writel(socket, offset+4, res->end); + return; + } + size = size/2; + align = size; + } while (size >= min); + printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", + socket->dev->slot_name, type); + res->start = res->end = 0; +} + +/* + * Allocate the bridge mappings for the device.. + */ +static void yenta_allocate_resources(struct yenta_socket *socket) +{ + yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH); + yenta_allocate_res(socket, 1, IORESOURCE_MEM); + yenta_allocate_res(socket, 2, IORESOURCE_IO); + yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */ +} + + +/* + * Free the bridge mappings for the device.. + */ +static void yenta_free_resources(struct yenta_socket *socket) +{ + int i; + for (i=0;i<4;i++) { + struct resource *res; + res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; + if (res->start != 0 && res->end != 0) + release_resource(res); + res->start = res->end = 0; + } +} + + +/* + * Close it down - release our resources and go home.. + */ +static void yenta_close(struct pci_dev *dev) +{ + struct yenta_socket *sock = pci_get_drvdata(dev); + + /* we don't want a dying socket registered */ + pcmcia_unregister_socket(&sock->socket); + + /* Disable all events so we don't die in an IRQ storm */ + cb_writel(sock, CB_SOCKET_MASK, 0x0); + exca_writeb(sock, I365_CSCINT, 0); + + if (sock->cb_irq) + free_irq(sock->cb_irq, sock); + else + del_timer_sync(&sock->poll_timer); + + if (sock->base) + iounmap(sock->base); + yenta_free_resources(sock); + + pci_set_drvdata(dev, NULL); +} + + +static int yenta_register_callback(struct pcmcia_socket *sock, void (*handler)(void *, unsigned int), void * info) +{ + struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); + + socket->handler = handler; + socket->info = info; + return 0; +} + + +static struct pccard_operations yenta_socket_operations = { + .owner = THIS_MODULE, + .init = yenta_init, + .suspend = yenta_suspend, + .register_callback = yenta_register_callback, + .get_status = yenta_get_status, + .get_socket = yenta_get_socket, + .set_socket = yenta_set_socket, + .set_io_map = yenta_set_io_map, + .set_mem_map = yenta_set_mem_map, +}; + + +#include "ti113x.h" +#include "ricoh.h" + +/* + * Different cardbus controllers have slightly different + * initialization sequences etc details. List them here.. + */ +#define PD(x,y) PCI_VENDOR_ID_##x, PCI_DEVICE_ID_##x##_##y +struct cardbus_override_struct { + unsigned short vendor; + unsigned short device; + int (*override) (struct yenta_socket *socket); +} cardbus_override[] = { + { PD(TI,1130), &ti113x_override }, + { PD(TI,1031), &ti_override }, + { PD(TI,1131), &ti113x_override }, + { PD(TI,1250), &ti1250_override }, + { PD(TI,1220), &ti_override }, + { PD(TI,1221), &ti_override }, + { PD(TI,1210), &ti_override }, + { PD(TI,1450), &ti_override }, + { PD(TI,1225), &ti_override }, + { PD(TI,1251A), &ti_override }, + { PD(TI,1211), &ti_override }, + { PD(TI,1251B), &ti_override }, + { PD(TI,1410), ti1250_override }, + { PD(TI,1420), &ti_override }, + { PD(TI,4410), &ti_override }, + { PD(TI,4451), &ti_override }, + + { PD(RICOH,RL5C465), &ricoh_override }, + { PD(RICOH,RL5C466), &ricoh_override }, + { PD(RICOH,RL5C475), &ricoh_override }, + { PD(RICOH,RL5C476), &ricoh_override }, + { PD(RICOH,RL5C478), &ricoh_override }, + + { }, /* all zeroes */ +}; + + +/* + * Initialize a cardbus controller. Make sure we have a usable + * interrupt, and that we can map the cardbus area. Fill in the + * socket information structure.. + */ +static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + struct yenta_socket *socket; + struct cardbus_override_struct *d; + + socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); + if (!socket) + return -ENOMEM; + memset(socket, 0, sizeof(*socket)); + + /* prepare pcmcia_socket */ + socket->socket.ss_entry = ¥ta_socket_operations; + socket->socket.dev.dev = &dev->dev; + socket->socket.driver_data = socket; + + /* prepare struct yenta_socket */ + socket->dev = dev; + pci_set_drvdata(dev, socket); + spin_lock_init(&socket->event_lock); + + /* + * Do some basic sanity checking.. + */ + if (pci_enable_device(dev)) + return -1; + if (!pci_resource_start(dev, 0)) { + printk("No cardbus resource!\n"); + return -1; + } + + /* + * Ok, start setup.. Map the cardbus registers, + * and request the IRQ. + */ + socket->base = ioremap(pci_resource_start(dev, 0), 0x1000); + if (!socket->base) + return -1; + + yenta_config_init(socket); + + /* Disable all events */ + cb_writel(socket, CB_SOCKET_MASK, 0x0); + + /* Set up the bridge regions.. */ + yenta_allocate_resources(socket); + + socket->cb_irq = dev->irq; + + /* Do we have special options for the device? */ + d = cardbus_override; + while (d->override) { + if ((dev->vendor == d->vendor) && (dev->device == d->device)) { + int retval = d->override(socket); + if (retval < 0) + return retval; + } + d++; + } + + /* We must finish initialization here */ + + INIT_WORK(&socket->tq_task, yenta_bh, socket); + + if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, socket->dev->dev.name, socket)) { + /* No IRQ or request_irq failed. Poll */ + socket->cb_irq = 0; /* But zero is a valid IRQ number. */ + init_timer(&socket->poll_timer); + socket->poll_timer.function = yenta_interrupt_wrapper; + socket->poll_timer.data = (unsigned long)socket; + socket->poll_timer.expires = jiffies + HZ; + add_timer(&socket->poll_timer); + } + + /* Figure out what the dang thing can do for the PCMCIA layer... */ + yenta_get_socket_capabilities(socket, isa_interrupts); + printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); + + /* Register it with the pcmcia layer.. */ + return pcmcia_register_socket(&socket->socket); +} + + +static int yenta_dev_suspend (struct pci_dev *dev, u32 state) +{ + return pcmcia_socket_dev_suspend(&dev->dev, state, 0); +} + + +static int yenta_dev_resume (struct pci_dev *dev) +{ + return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); +} + + +static struct pci_device_id yenta_table [] __devinitdata = { { + .class = PCI_CLASS_BRIDGE_CARDBUS << 8, + .class_mask = ~0, + + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}, { /* all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, yenta_table); + + +static struct pci_driver yenta_cardbus_driver = { + .name = "yenta_cardbus", + .id_table = yenta_table, + .probe = yenta_probe, + .remove = __devexit_p(yenta_close), + .suspend = yenta_dev_suspend, + .resume = yenta_dev_resume, +}; + + +static int __init yenta_socket_init(void) +{ + return pci_register_driver (¥ta_cardbus_driver); +} + + +static void __exit yenta_socket_exit (void) +{ + pci_unregister_driver (¥ta_cardbus_driver); +} + + +module_init(yenta_socket_init); +module_exit(yenta_socket_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pcmcia/yenta_socket.h Mon Jun 16 08:00:31 2003 @@ -0,0 +1,116 @@ +#ifndef __YENTA_H +#define __YENTA_H + +#include + +#define CB_SOCKET_EVENT 0x00 +#define CB_CSTSEVENT 0x00000001 /* Card status event */ +#define CB_CD1EVENT 0x00000002 /* Card detect 1 change event */ +#define CB_CD2EVENT 0x00000004 /* Card detect 2 change event */ +#define CB_PWREVENT 0x00000008 /* PWRCYCLE change event */ + +#define CB_SOCKET_MASK 0x04 +#define CB_CSTSMASK 0x00000001 /* Card status mask */ +#define CB_CDMASK 0x00000006 /* Card detect 1&2 mask */ +#define CB_PWRMASK 0x00000008 /* PWRCYCLE change mask */ + +#define CB_SOCKET_STATE 0x08 +#define CB_CARDSTS 0x00000001 /* CSTSCHG status */ +#define CB_CDETECT1 0x00000002 /* Card detect status 1 */ +#define CB_CDETECT2 0x00000004 /* Card detect status 2 */ +#define CB_PWRCYCLE 0x00000008 /* Socket powered */ +#define CB_16BITCARD 0x00000010 /* 16-bit card detected */ +#define CB_CBCARD 0x00000020 /* CardBus card detected */ +#define CB_IREQCINT 0x00000040 /* READY(xIRQ)/xCINT high */ +#define CB_NOTACARD 0x00000080 /* Unrecognizable PC card detected */ +#define CB_DATALOST 0x00000100 /* Potential data loss due to card removal */ +#define CB_BADVCCREQ 0x00000200 /* Invalid Vcc request by host software */ +#define CB_5VCARD 0x00000400 /* Card Vcc at 5.0 volts? */ +#define CB_3VCARD 0x00000800 /* Card Vcc at 3.3 volts? */ +#define CB_XVCARD 0x00001000 /* Card Vcc at X.X volts? */ +#define CB_YVCARD 0x00002000 /* Card Vcc at Y.Y volts? */ +#define CB_5VSOCKET 0x10000000 /* Socket Vcc at 5.0 volts? */ +#define CB_3VSOCKET 0x20000000 /* Socket Vcc at 3.3 volts? */ +#define CB_XVSOCKET 0x40000000 /* Socket Vcc at X.X volts? */ +#define CB_YVSOCKET 0x80000000 /* Socket Vcc at Y.Y volts? */ + +#define CB_SOCKET_FORCE 0x0C +#define CB_FCARDSTS 0x00000001 /* Force CSTSCHG */ +#define CB_FCDETECT1 0x00000002 /* Force CD1EVENT */ +#define CB_FCDETECT2 0x00000004 /* Force CD2EVENT */ +#define CB_FPWRCYCLE 0x00000008 /* Force PWREVENT */ +#define CB_F16BITCARD 0x00000010 /* Force 16-bit PCMCIA card */ +#define CB_FCBCARD 0x00000020 /* Force CardBus line */ +#define CB_FNOTACARD 0x00000080 /* Force NOTACARD */ +#define CB_FDATALOST 0x00000100 /* Force data lost */ +#define CB_FBADVCCREQ 0x00000200 /* Force bad Vcc request */ +#define CB_F5VCARD 0x00000400 /* Force 5.0 volt card */ +#define CB_F3VCARD 0x00000800 /* Force 3.3 volt card */ +#define CB_FXVCARD 0x00001000 /* Force X.X volt card */ +#define CB_FYVCARD 0x00002000 /* Force Y.Y volt card */ +#define CB_CVSTEST 0x00004000 /* Card VS test */ + +#define CB_SOCKET_CONTROL 0x10 +#define CB_SC_VPP_MASK 0x00000007 +#define CB_SC_VPP_OFF 0x00000000 +#define CB_SC_VPP_12V 0x00000001 +#define CB_SC_VPP_5V 0x00000002 +#define CB_SC_VPP_3V 0x00000003 +#define CB_SC_VPP_XV 0x00000004 +#define CB_SC_VPP_YV 0x00000005 +#define CB_SC_VCC_MASK 0x00000070 +#define CB_SC_VCC_OFF 0x00000000 +#define CB_SC_VCC_5V 0x00000020 +#define CB_SC_VCC_3V 0x00000030 +#define CB_SC_VCC_XV 0x00000040 +#define CB_SC_VCC_YV 0x00000050 +#define CB_SC_CCLK_STOP 0x00000080 + +#define CB_SOCKET_POWER 0x20 +#define CB_SKTACCES 0x02000000 /* A PC card access has occurred (clear on read) */ +#define CB_SKTMODE 0x01000000 /* Clock frequency has changed (clear on read) */ +#define CB_CLKCTRLEN 0x00010000 /* Clock control enabled (RW) */ +#define CB_CLKCTRL 0x00000001 /* Stop(0) or slow(1) CB clock (RW) */ + +/* + * Cardbus configuration space + */ +#define CB_BRIDGE_BASE(m) (0x1c + 8*(m)) +#define CB_BRIDGE_LIMIT(m) (0x20 + 8*(m)) +#define CB_BRIDGE_CONTROL 0x3e +#define CB_BRIDGE_CPERREN 0x00000001 +#define CB_BRIDGE_CSERREN 0x00000002 +#define CB_BRIDGE_ISAEN 0x00000004 +#define CB_BRIDGE_VGAEN 0x00000008 +#define CB_BRIDGE_MABTMODE 0x00000020 +#define CB_BRIDGE_CRST 0x00000040 +#define CB_BRIDGE_INTR 0x00000080 +#define CB_BRIDGE_PREFETCH0 0x00000100 +#define CB_BRIDGE_PREFETCH1 0x00000200 +#define CB_BRIDGE_POSTEN 0x00000400 +#define CB_LEGACY_MODE_BASE 0x44 + +/* + * ExCA area extensions in Yenta + */ +#define CB_MEM_PAGE(map) (0x40 + (map)) + +struct yenta_socket { + struct pci_dev *dev; + int cb_irq, io_irq; + void *base; + void (*handler)(void *, unsigned int); + void *info; + spinlock_t event_lock; + unsigned int events; + struct work_struct tq_task; + struct timer_list poll_timer; + + struct pcmcia_socket socket; + + /* A few words of private data for special stuff of overrides... */ + unsigned int private[8]; +}; + + +#endif diff -Nru a/drivers/pnp/base.h b/drivers/pnp/base.h --- a/drivers/pnp/base.h Wed Feb 19 08:45:42 2003 +++ b/drivers/pnp/base.h Wed Jun 18 15:22:42 2003 @@ -4,29 +4,11 @@ int pnp_interface_attach_device(struct pnp_dev *dev); void pnp_name_device(struct pnp_dev *dev); void pnp_fixup_device(struct pnp_dev *dev); -void pnp_free_resources(struct pnp_resources *resources); +void pnp_free_option(struct pnp_option *option); int __pnp_add_device(struct pnp_dev *dev); void __pnp_remove_device(struct pnp_dev *dev); -/* resource conflict types */ -#define CONFLICT_TYPE_NONE 0x0000 /* there are no conflicts, other than those in the link */ -#define CONFLICT_TYPE_RESERVED 0x0001 /* the resource requested was reserved */ -#define CONFLICT_TYPE_IN_USE 0x0002 /* there is a conflict because the resource is in use */ -#define CONFLICT_TYPE_PCI 0x0004 /* there is a conflict with a pci device */ -#define CONFLICT_TYPE_INVALID 0x0008 /* the resource requested is invalid */ -#define CONFLICT_TYPE_INTERNAL 0x0010 /* resources within the device conflict with each ohter */ -#define CONFLICT_TYPE_PNP_WARM 0x0020 /* there is a conflict with a pnp device that is active */ -#define CONFLICT_TYPE_PNP_COLD 0x0040 /* there is a conflict with a pnp device that is disabled */ - -/* conflict search modes */ -#define SEARCH_WARM 1 /* check for conflicts with active devices */ -#define SEARCH_COLD 0 /* check for conflicts with disabled devices */ - -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_port(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_mem(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_irq(struct pnp_dev * dev, int idx); -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode); int pnp_check_dma(struct pnp_dev * dev, int idx); diff -Nru a/drivers/pnp/core.c b/drivers/pnp/core.c --- a/drivers/pnp/core.c Sun May 25 17:00:00 2003 +++ b/drivers/pnp/core.c Wed Jun 18 15:22:42 2003 @@ -104,8 +104,8 @@ static void pnp_release_device(struct device *dmdev) { struct pnp_dev * dev = to_pnp_dev(dmdev); - if (dev->possible) - pnp_free_resources(dev->possible); + pnp_free_option(dev->independent); + pnp_free_option(dev->dependent); pnp_free_ids(dev); kfree(dev); } @@ -122,7 +122,7 @@ list_add_tail(&dev->global_list, &pnp_global); list_add_tail(&dev->protocol_list, &dev->protocol->devices); spin_unlock(&pnp_lock); - pnp_auto_config_dev(dev); + ret = device_register(&dev->dev); if (ret == 0) pnp_interface_attach_device(dev); diff -Nru a/drivers/pnp/interface.c b/drivers/pnp/interface.c --- a/drivers/pnp/interface.c Sun Mar 9 15:17:52 2003 +++ b/drivers/pnp/interface.c Wed Jun 18 15:33:52 2003 @@ -168,7 +168,8 @@ pnp_printf(buffer, ", %s\n", s); } -static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct pnp_resources *res, int dep) +static void pnp_print_option(pnp_info_buffer_t *buffer, char *space, + struct pnp_option *option, int dep) { char *s; struct pnp_port *port; @@ -176,49 +177,55 @@ struct pnp_dma *dma; struct pnp_mem *mem; - switch (res->priority) { - case PNP_RES_PRIORITY_PREFERRED: - s = "preferred"; - break; - case PNP_RES_PRIORITY_ACCEPTABLE: - s = "acceptable"; - break; - case PNP_RES_PRIORITY_FUNCTIONAL: - s = "functional"; - break; - default: - s = "invalid"; - } - if (dep > 0) + if (dep) { + switch (option->priority) { + case PNP_RES_PRIORITY_PREFERRED: + s = "preferred"; + break; + case PNP_RES_PRIORITY_ACCEPTABLE: + s = "acceptable"; + break; + case PNP_RES_PRIORITY_FUNCTIONAL: + s = "functional"; + break; + default: + s = "invalid"; + } pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s); - for (port = res->port; port; port = port->next) + } + + for (port = option->port; port; port = port->next) pnp_print_port(buffer, space, port); - for (irq = res->irq; irq; irq = irq->next) + for (irq = option->irq; irq; irq = irq->next) pnp_print_irq(buffer, space, irq); - for (dma = res->dma; dma; dma = dma->next) + for (dma = option->dma; dma; dma = dma->next) pnp_print_dma(buffer, space, dma); - for (mem = res->mem; mem; mem = mem->next) + for (mem = option->mem; mem; mem = mem->next) pnp_print_mem(buffer, space, mem); } -static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf) + +static ssize_t pnp_show_options(struct device *dmdev, char *buf) { struct pnp_dev *dev = to_pnp_dev(dmdev); - struct pnp_resources * res = dev->possible; - int ret, dep = 0; + struct pnp_option * independent = dev->independent; + struct pnp_option * dependent = dev->dependent; + int ret, dep = 1; + pnp_info_buffer_t *buffer = (pnp_info_buffer_t *) pnp_alloc(sizeof(pnp_info_buffer_t)); if (!buffer) return -ENOMEM; + buffer->len = PAGE_SIZE; buffer->buffer = buf; buffer->curr = buffer->buffer; - while (res){ - if (dep == 0) - pnp_print_resources(buffer, "", res, dep); - else - pnp_print_resources(buffer, " ", res, dep); - res = res->dep; + if (independent) + pnp_print_option(buffer, "", independent, 0); + + while (dependent){ + pnp_print_option(buffer, " ", dependent, dep); + dependent = dependent->next; dep++; } ret = (buffer->curr - buf); @@ -226,97 +233,8 @@ return ret; } -static DEVICE_ATTR(possible,S_IRUGO,pnp_show_possible_resources,NULL); - -static void pnp_print_conflict_node(pnp_info_buffer_t *buffer, struct pnp_dev * dev) -{ - if (!dev) - return; - pnp_printf(buffer, "'%s'.\n", dev->dev.bus_id); -} - -static void pnp_print_conflict_desc(pnp_info_buffer_t *buffer, int conflict) -{ - if (!conflict) - return; - pnp_printf(buffer, " Conflict Detected: %2x - ", conflict); - switch (conflict) { - case CONFLICT_TYPE_RESERVED: - pnp_printf(buffer, "manually reserved.\n"); - break; - - case CONFLICT_TYPE_IN_USE: - pnp_printf(buffer, "currently in use.\n"); - break; - - case CONFLICT_TYPE_PCI: - pnp_printf(buffer, "PCI device.\n"); - break; - - case CONFLICT_TYPE_INVALID: - pnp_printf(buffer, "invalid.\n"); - break; - - case CONFLICT_TYPE_INTERNAL: - pnp_printf(buffer, "another resource on this device.\n"); - break; - - case CONFLICT_TYPE_PNP_WARM: - pnp_printf(buffer, "active PnP device "); - break; - - case CONFLICT_TYPE_PNP_COLD: - pnp_printf(buffer, "disabled PnP device "); - break; - default: - pnp_printf(buffer, "Unknown conflict.\n"); - break; - } -} +static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL); -static void pnp_print_conflict(pnp_info_buffer_t *buffer, struct pnp_dev * dev, int idx, int type) -{ - struct pnp_dev * cdev, * wdev = NULL; - int conflict; - switch (type) { - case IORESOURCE_IO: - conflict = pnp_check_port(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_port_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_port_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_MEM: - conflict = pnp_check_mem(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_mem_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_mem_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_IRQ: - conflict = pnp_check_irq(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_irq_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_irq_conflicts(dev, idx, SEARCH_COLD); - break; - case IORESOURCE_DMA: - conflict = pnp_check_dma(dev, idx); - if (conflict == CONFLICT_TYPE_PNP_WARM) - wdev = pnp_check_dma_conflicts(dev, idx, SEARCH_WARM); - cdev = pnp_check_dma_conflicts(dev, idx, SEARCH_COLD); - break; - default: - return; - } - - pnp_print_conflict_desc(buffer, conflict); - - if (wdev) - pnp_print_conflict_node(buffer, wdev); - - if (cdev) { - pnp_print_conflict_desc(buffer, CONFLICT_TYPE_PNP_COLD); - pnp_print_conflict_node(buffer, cdev); - } -} static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf) { @@ -332,12 +250,6 @@ buffer->buffer = buf; buffer->curr = buffer->buffer; - pnp_printf(buffer,"mode = "); - if (dev->config_mode & PNP_CONFIG_MANUAL) - pnp_printf(buffer,"manual\n"); - else - pnp_printf(buffer,"auto\n"); - pnp_printf(buffer,"state = "); if (dev->active) pnp_printf(buffer,"active\n"); @@ -350,7 +262,6 @@ pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_port_start(dev, i), pnp_port_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IO); } } for (i = 0; i < PNP_MAX_MEM; i++) { @@ -359,21 +270,18 @@ pnp_printf(buffer," 0x%lx-0x%lx \n", pnp_mem_start(dev, i), pnp_mem_end(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_MEM); } } for (i = 0; i < PNP_MAX_IRQ; i++) { if (pnp_irq_valid(dev, i)) { pnp_printf(buffer,"irq"); pnp_printf(buffer," %ld \n", pnp_irq(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_IRQ); } } for (i = 0; i < PNP_MAX_DMA; i++) { if (pnp_dma_valid(dev, i)) { pnp_printf(buffer,"dma"); pnp_printf(buffer," %ld \n", pnp_dma(dev, i)); - pnp_print_conflict(buffer, dev, i, IORESOURCE_DMA); } } ret = (buffer->curr - buf); @@ -381,7 +289,7 @@ return ret; } -extern int pnp_resolve_conflicts(struct pnp_dev *dev); +extern struct semaphore pnp_res_mutex; static ssize_t pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count) @@ -390,6 +298,12 @@ char *buf = (void *)ubuf; int retval = 0; + if (dev->status & PNP_ATTACHED) { + retval = -EBUSY; + pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id); + goto done; + } + while (isspace(*buf)) ++buf; if (!strnicmp(buf,"disable",7)) { @@ -400,41 +314,30 @@ retval = pnp_activate_dev(dev); goto done; } - if (!strnicmp(buf,"reset",5)) { - if (!dev->active) - goto done; - retval = pnp_disable_dev(dev); - if (retval) + if (!strnicmp(buf,"fill",4)) { + if (dev->active) goto done; - retval = pnp_activate_dev(dev); + retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"auto",4)) { if (dev->active) goto done; + pnp_init_resources(&dev->res); retval = pnp_auto_config_dev(dev); goto done; } if (!strnicmp(buf,"clear",5)) { if (dev->active) goto done; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); - if (dev->rule) - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - goto done; - } - if (!strnicmp(buf,"resolve",7)) { - retval = pnp_resolve_conflicts(dev); + pnp_init_resources(&dev->res); goto done; } if (!strnicmp(buf,"get",3)) { - spin_lock(&pnp_lock); + down(&pnp_res_mutex); if (pnp_can_read(dev)) dev->protocol->get(dev, &dev->res); - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); goto done; } if (!strnicmp(buf,"set",3)) { @@ -442,9 +345,8 @@ if (dev->active) goto done; buf += 3; - spin_lock(&pnp_lock); - dev->config_mode = PNP_CONFIG_MANUAL; - pnp_init_resource_table(&dev->res); + pnp_init_resources(&dev->res); + down(&pnp_res_mutex); while (1) { while (isspace(*buf)) ++buf; @@ -514,7 +416,7 @@ } break; } - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); goto done; } done: @@ -543,7 +445,7 @@ int pnp_interface_attach_device(struct pnp_dev *dev) { - device_create_file(&dev->dev,&dev_attr_possible); + device_create_file(&dev->dev,&dev_attr_options); device_create_file(&dev->dev,&dev_attr_resources); device_create_file(&dev->dev,&dev_attr_id); return 0; diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c --- a/drivers/pnp/isapnp/core.c Tue Jun 10 00:49:51 2003 +++ b/drivers/pnp/isapnp/core.c Wed Jun 18 15:37:05 2003 @@ -31,6 +31,7 @@ * 2002-06-06 Made the use of dma channel 0 configurable * Gerald Teschl * 2002-10-06 Ported to PnP Layer - Adam Belay + * 2003-08-11 Resource Management Updates - Adam Belay */ #include @@ -54,7 +55,6 @@ int isapnp_disable; /* Disable ISA PnP */ int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ -int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ MODULE_AUTHOR("Jaroslav Kysela "); @@ -66,8 +66,6 @@ MODULE_PARM(isapnp_reset, "i"); MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards"); MODULE_PARM(isapnp_allow_dma0, "i"); -MODULE_PARM(isapnp_skip_pci_scan, "i"); -MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning"); MODULE_PARM(isapnp_verbose, "i"); MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode"); MODULE_LICENSE("GPL"); @@ -460,6 +458,7 @@ dev->capabilities |= PNP_READ; dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_DISABLE; + pnp_init_resources(&dev->res); return dev; } @@ -468,8 +467,8 @@ * Add IRQ resource to resources list. */ -static void __init isapnp_add_irq_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_irq_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_irq *irq; @@ -483,7 +482,7 @@ irq->flags = tmp[2]; else irq->flags = IORESOURCE_IRQ_HIGHEDGE; - pnp_add_irq_resource(dev, depnum, irq); + pnp_register_irq_resource(option, irq); return; } @@ -491,8 +490,8 @@ * Add DMA resource to resources list. */ -static void __init isapnp_add_dma_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_dma_resource(struct pnp_option *option, + int size) { unsigned char tmp[2]; struct pnp_dma *dma; @@ -503,7 +502,7 @@ return; dma->map = tmp[0]; dma->flags = tmp[1]; - pnp_add_dma_resource(dev, depnum, dma); + pnp_register_dma_resource(option, dma); return; } @@ -511,8 +510,8 @@ * Add port resource to resources list. */ -static void __init isapnp_add_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[7]; struct pnp_port *port; @@ -526,7 +525,7 @@ port->align = tmp[5]; port->size = tmp[6]; port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -534,8 +533,8 @@ * Add fixed port resource to resources list. */ -static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option, + int size) { unsigned char tmp[3]; struct pnp_port *port; @@ -548,7 +547,7 @@ port->size = tmp[2]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -556,8 +555,8 @@ * Add memory resource to resources list. */ -static void __init isapnp_add_mem_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -571,7 +570,7 @@ mem->align = (tmp[6] << 8) | tmp[5]; mem->size = ((tmp[8] << 8) | tmp[7]) << 8; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); return; } @@ -579,8 +578,8 @@ * Add 32-bit memory resource to resources list. */ -static void __init isapnp_add_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[17]; struct pnp_mem *mem; @@ -594,15 +593,15 @@ mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9]; mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13]; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Add 32-bit fixed memory resource to resources list. */ -static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev, - int depnum, int size) +static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option, + int size) { unsigned char tmp[9]; struct pnp_mem *mem; @@ -615,14 +614,14 @@ mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5]; mem->align = 0; mem->flags = tmp[0]; - pnp_add_mem_resource(dev,depnum,mem); + pnp_register_mem_resource(option,mem); } /* * Parse card name for ISA PnP device. */ - -static void __init + +static void __init isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size) { if (name[0] == '\0') { @@ -634,7 +633,7 @@ /* clean whitespace from end of string */ while (size1 > 0 && name[--size1] == ' ') name[size1] = '\0'; - } + } } /* @@ -644,14 +643,17 @@ static int __init isapnp_create_device(struct pnp_card *card, unsigned short size) { - int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0; + int number = 0, skip = 0, priority = 0, compat = 0; unsigned char type, tmp[17]; + struct pnp_option *option; struct pnp_dev *dev; if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return 1; pnp_add_card_device(card,dev); + while (1) { if (isapnp_read_tag(&type, &size)<0) return 1; @@ -662,15 +664,16 @@ if (size >= 5 && size <= 6) { if ((dev = isapnp_parse_device(card, size, number++)) == NULL) return 1; - pnp_build_resource(dev,0); - pnp_add_card_device(card,dev); size = 0; skip = 0; + option = pnp_register_independent_option(dev); + if (!option) + return 1; + pnp_add_card_device(card,dev); } else { skip = 1; } - dependent = 0; - depnum = 0; + priority = 0; compat = 0; break; case _STAG_COMPATDEVID: @@ -684,43 +687,43 @@ case _STAG_IRQ: if (size < 2 || size > 3) goto __skip; - isapnp_add_irq_resource(dev, depnum, size); + isapnp_parse_irq_resource(option, size); size = 0; break; case _STAG_DMA: if (size != 2) goto __skip; - isapnp_add_dma_resource(dev, depnum, size); + isapnp_parse_dma_resource(option, size); size = 0; break; case _STAG_STARTDEP: if (size > 1) goto __skip; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (size > 0) { isapnp_peek(tmp, size); - dependent = 0x100 | tmp[0]; + priority = 0x100 | tmp[0]; size = 0; } - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + option = pnp_register_dependent_option(dev,priority); + if (!option) + return 1; break; case _STAG_ENDDEP: if (size != 0) goto __skip; - dependent = 0; - depnum = 0; + priority = 0; break; case _STAG_IOPORT: if (size != 7) goto __skip; - isapnp_add_port_resource(dev, depnum, size); + isapnp_parse_port_resource(option, size); size = 0; break; case _STAG_FIXEDIO: if (size != 3) goto __skip; - isapnp_add_fixed_port_resource(dev, depnum, size); + isapnp_parse_fixed_port_resource(option, size); size = 0; break; case _STAG_VENDOR: @@ -728,7 +731,7 @@ case _LTAG_MEMRANGE: if (size != 9) goto __skip; - isapnp_add_mem_resource(dev, depnum, size); + isapnp_parse_mem_resource(option, size); size = 0; break; case _LTAG_ANSISTR: @@ -743,13 +746,13 @@ case _LTAG_MEM32RANGE: if (size != 17) goto __skip; - isapnp_add_mem32_resource(dev, depnum, size); + isapnp_parse_mem32_resource(option, size); size = 0; break; case _LTAG_FIXEDMEM32RANGE: if (size != 9) goto __skip; - isapnp_add_fixed_mem32_resource(dev, depnum, size); + isapnp_parse_fixed_mem32_resource(option, size); size = 0; break; case _STAG_END: @@ -859,63 +862,6 @@ pnp_add_card_id(id,card); } - -static int isapnp_parse_current_resources(struct pnp_dev *dev, struct pnp_resource_table * res) -{ - int tmp, ret; - struct pnp_rule_table rule; - if (dev->rule) - rule = *dev->rule; - else { - if (!pnp_generate_rule(dev,1,&rule)) - return -EINVAL; - } - - dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); - if (dev->active) { - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); - if (!ret) - continue; - res->port_resource[tmp].start = ret; - if (rule.port[tmp]) - res->port_resource[tmp].end = ret + rule.port[tmp]->size - 1; - else - res->port_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->port_resource[tmp].flags = IORESOURCE_IO; - } - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); - if (!ret) - continue; - res->mem_resource[tmp].start = ret; - if (rule.mem[tmp]) - res->mem_resource[tmp].end = ret + rule.mem[tmp]->size - 1; - else - res->mem_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */ - res->mem_resource[tmp].flags = IORESOURCE_MEM; - } - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); - if (!ret) - continue; - res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; - res->irq_resource[tmp].flags = IORESOURCE_IRQ; - } - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); - if (ret == 4) - continue; - if (rule.dma[tmp]) { /* some isapnp systems forget to set this to 4 so we have to check */ - res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; - res->dma_resource[tmp].flags = IORESOURCE_DMA; - } - } - } - return 0; -} - - /* * Build device list for all present ISA PnP devices. */ @@ -925,7 +871,6 @@ int csn; unsigned char header[9], checksum; struct pnp_card *card; - struct pnp_dev *dev; isapnp_wait(); isapnp_key(); @@ -959,13 +904,6 @@ card->checksum = isapnp_checksum_value; card->protocol = &isapnp_protocol; - /* read the current resource data */ - card_for_each_dev(card,dev) { - isapnp_device(dev->number); - pnp_init_resource_table(&dev->res); - isapnp_parse_current_resources(dev, &dev->res); - } - pnp_add_card(card); } isapnp_wait(); @@ -1041,12 +979,50 @@ EXPORT_SYMBOL(isapnp_wake); EXPORT_SYMBOL(isapnp_device); +static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res) +{ + int tmp, ret; + + dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE); + if (dev->active) { + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1)); + if (!ret) + continue; + res->port_resource[tmp].start = ret; + res->port_resource[tmp].flags = IORESOURCE_IO; + } + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3)); + if (!ret) + continue; + res->mem_resource[tmp].start = ret; + res->mem_resource[tmp].flags = IORESOURCE_MEM; + } + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8); + if (!ret) + continue; + res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret; + res->irq_resource[tmp].flags = IORESOURCE_IRQ; + } + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp); + if (ret == 4) + continue; + res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret; + res->dma_resource[tmp].flags = IORESOURCE_DMA; + } + } + return 0; +} + static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res) { int ret; - pnp_init_resource_table(res); + pnp_init_resources(res); isapnp_cfg_begin(dev->card->number, dev->number); - ret = isapnp_parse_current_resources(dev, res); + ret = isapnp_read_resources(dev, res); isapnp_cfg_end(); return ret; } @@ -1196,7 +1172,6 @@ { (void)((get_option(&str,&isapnp_rdp) == 2) && (get_option(&str,&isapnp_reset) == 2) && - (get_option(&str,&isapnp_skip_pci_scan) == 2) && (get_option(&str,&isapnp_verbose) == 2)); return 1; } diff -Nru a/drivers/pnp/manager.c b/drivers/pnp/manager.c --- a/drivers/pnp/manager.c Tue Mar 25 13:34:31 2003 +++ b/drivers/pnp/manager.c Wed Jun 18 15:22:42 2003 @@ -1,6 +1,7 @@ /* * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices * + * based on isapnp.c resource management (c) Jaroslav Kysela * Copyright 2003 Adam Belay * */ @@ -20,549 +21,339 @@ #include #include "base.h" +DECLARE_MUTEX(pnp_res_mutex); -int pnp_max_moves = 4; - - -static int pnp_next_port(struct pnp_dev * dev, int idx) +static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { - struct pnp_port *port; unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_PORT) - return 0; - port = dev->rule->port[idx]; - if (!port) + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_PORT) { + pnp_err("More than 4 ports is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO)) return 1; start = &dev->res.port_resource[idx].start; end = &dev->res.port_resource[idx].end; flags = &dev->res.port_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = port->min; - *end = *start + port->size - 1; - *flags = port->flags | IORESOURCE_IO; - if (!pnp_check_port(dev, idx)) - return 1; - } + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size - 1; + *flags = *flags | rule->flags | IORESOURCE_IO; /* run through until pnp_check_port is happy */ - do { - *start += port->align; - *end = *start + port->size - 1; - if (*start > port->max || !port->align) + while (!pnp_check_port(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) return 0; - } while (pnp_check_port(dev, idx)); + } return 1; } -static int pnp_next_mem(struct pnp_dev * dev, int idx) +static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) { - struct pnp_mem *mem; unsigned long *start, *end, *flags; - if (!dev || idx < 0 || idx >= PNP_MAX_MEM) - return 0; - mem = dev->rule->mem[idx]; - if (!mem) + + if (!dev || !rule) + return -EINVAL; + + if (idx >= PNP_MAX_MEM) { + pnp_err("More than 8 mems is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; + } + + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO)) return 1; start = &dev->res.mem_resource[idx].start; end = &dev->res.mem_resource[idx].end; flags = &dev->res.mem_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == 0) { - *start = mem->min; - *end = *start + mem->size -1; - *flags = mem->flags | IORESOURCE_MEM; - if (!(mem->flags & IORESOURCE_MEM_WRITEABLE)) - *flags |= IORESOURCE_READONLY; - if (mem->flags & IORESOURCE_MEM_CACHEABLE) - *flags |= IORESOURCE_CACHEABLE; - if (mem->flags & IORESOURCE_MEM_RANGELENGTH) - *flags |= IORESOURCE_RANGELENGTH; - if (mem->flags & IORESOURCE_MEM_SHADOWABLE) - *flags |= IORESOURCE_SHADOWABLE; - if (!pnp_check_mem(dev, idx)) - return 1; - } + /* set the initial values */ + *start = rule->min; + *end = *start + rule->size -1; + *flags = *flags | rule->flags | IORESOURCE_MEM; + + /* convert pnp flags to standard Linux flags */ + if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) + *flags |= IORESOURCE_READONLY; + if (rule->flags & IORESOURCE_MEM_CACHEABLE) + *flags |= IORESOURCE_CACHEABLE; + if (rule->flags & IORESOURCE_MEM_RANGELENGTH) + *flags |= IORESOURCE_RANGELENGTH; + if (rule->flags & IORESOURCE_MEM_SHADOWABLE) + *flags |= IORESOURCE_SHADOWABLE; /* run through until pnp_check_mem is happy */ - do { - *start += mem->align; - *end = *start + mem->size - 1; - if (*start > mem->max || !mem->align) + while (!pnp_check_mem(dev, idx)) { + *start += rule->align; + *end = *start + rule->size - 1; + if (*start > rule->max || !rule->align) return 0; - } while (pnp_check_mem(dev, idx)); + } return 1; } -static int pnp_next_irq(struct pnp_dev * dev, int idx) +static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx) { - struct pnp_irq *irq; unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_IRQ) - return 0; - irq = dev->rule->irq[idx]; - if (!irq) - return 1; + int i; - start = &dev->res.irq_resource[idx].start; - end = &dev->res.irq_resource[idx].end; - flags = &dev->res.irq_resource[idx].flags; + /* IRQ priority: this table is good for i386 */ + static unsigned short xtab[16] = { + 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 + }; - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = irq->flags | IORESOURCE_IRQ; - if (!pnp_check_irq(dev, idx)) - return 1; - } + if (!dev || !rule) + return -EINVAL; - mask = irq->map; - for (i = *start + 1; i < 16; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_irq(dev, idx)) - return 1; - } + if (idx >= PNP_MAX_IRQ) { + pnp_err("More than 2 irqs is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ + return 1; } - return 0; -} -static int pnp_next_dma(struct pnp_dev * dev, int idx) -{ - struct pnp_dma *dma; - unsigned long *start, *end, *flags; - int i, mask; - if (!dev || idx < 0 || idx >= PNP_MAX_DMA) - return -EINVAL; - dma = dev->rule->dma[idx]; - if (!dma) + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO)) return 1; - start = &dev->res.dma_resource[idx].start; - end = &dev->res.dma_resource[idx].end; - flags = &dev->res.dma_resource[idx].flags; + start = &dev->res.irq_resource[idx].start; + end = &dev->res.irq_resource[idx].end; + flags = &dev->res.irq_resource[idx].flags; - /* set the initial values if this is the first time */ - if (*start == -1) { - *start = *end = 0; - *flags = dma->flags | IORESOURCE_DMA; - if (!pnp_check_dma(dev, idx)) - return 1; - } + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_IRQ; - mask = dma->map; - for (i = *start + 1; i < 8; i++) - { - if(mask>>i & 0x01) { - *start = *end = i; - if(!pnp_check_dma(dev, idx)) + for (i = 0; i < 16; i++) { + if(rule->map & (1<rule->depnum; - int max = pnp_get_max_depnum(dev); - int priority = PNP_RES_PRIORITY_PREFERRED; - - if (depnum < 0) - return 0; - - if (max == 0) { - if (pnp_generate_rule(dev, 0, dev->rule)) { - dev->rule->depnum = -1; - return 1; - } - } - - if(depnum > 0) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - priority = res->priority; - } - - for (; priority <= PNP_RES_PRIORITY_FUNCTIONAL; priority++, depnum = 0) { - depnum += 1; - for (; depnum <= max; depnum++) { - struct pnp_resources * res = pnp_find_resources(dev, depnum); - if (res->priority == priority) { - if(pnp_generate_rule(dev, depnum, dev->rule)) { - dev->rule->depnum = depnum; - return 1; - } - } - } - } - return 0; -} - -struct pnp_change { - struct list_head change_list; - struct list_head changes; - struct pnp_resource_table res_bak; - struct pnp_rule_table rule_bak; - struct pnp_dev * dev; -}; - -static void pnp_free_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - list_del(&change->change_list); - kfree(change); - } -} - -static void pnp_undo_changes(struct pnp_change * parent) -{ - struct list_head * pos, * temp; - list_for_each_safe(pos, temp, &parent->changes) { - struct pnp_change * change = list_entry(pos, struct pnp_change, change_list); - *change->dev->rule = change->rule_bak; - change->dev->res = change->res_bak; - list_del(&change->change_list); - kfree(change); - } -} - -static struct pnp_change * pnp_add_change(struct pnp_change * parent, struct pnp_dev * dev) -{ - struct pnp_change * change = pnp_alloc(sizeof(struct pnp_change)); - if (!change) - return NULL; - change->res_bak = dev->res; - change->rule_bak = *dev->rule; - change->dev = dev; - INIT_LIST_HEAD(&change->changes); - if (parent) - list_add(&change->change_list, &parent->changes); - return change; -} - -static void pnp_commit_changes(struct pnp_change * parent, struct pnp_change * change) -{ - /* check if it's the root change */ - if (!parent) - return; - if (!list_empty(&change->changes)) - list_splice_init(&change->changes, &parent->changes); -} - -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent); - -static int pnp_next_request(struct pnp_dev * dev, int move, struct pnp_change * parent, struct pnp_change * change) +static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { + unsigned long *start, *end, *flags; int i; - struct pnp_dev * cdev; - for (i = 0; i < PNP_MAX_PORT; i++) { - if (dev->res.port_resource[i].start == 0 - || pnp_check_port_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_port(dev,i)) - return 0; - } - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_port(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (dev->res.mem_resource[i].start == 0 - || pnp_check_mem_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_mem(dev,i)) - return 0; - } - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_mem(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (dev->res.irq_resource[i].start == -1 - || pnp_check_irq_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_irq(dev,i)) - return 0; - } - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_irq(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (dev->res.dma_resource[i].start == -1 - || pnp_check_dma_conflicts(dev,i,SEARCH_WARM)) { - if (!pnp_next_dma(dev,i)) - return 0; - } - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev && (!move || !pnp_next_config(cdev,move,change))) { - pnp_undo_changes(change); - if (!pnp_next_dma(dev,i)) - return 0; - } - } while (cdev); - pnp_commit_changes(parent, change); - } - return 1; -} - -static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent) -{ - struct pnp_change * change; - move--; - if (!dev->rule) - return 0; - change = pnp_add_change(parent,dev); - if (!change) - return 0; - if (!pnp_can_configure(dev)) - goto fail; - if (!dev->rule->depnum) { - if (!pnp_next_rule(dev)) - goto fail; - } - while (!pnp_next_request(dev, move, parent, change)) { - if(!pnp_next_rule(dev)) - goto fail; - pnp_init_resource_table(&dev->res); - } - if (!parent) { - pnp_free_changes(change); - kfree(change); - } - return 1; + /* DMA priority: this table is good for i386 */ + static unsigned short xtab[8] = { + 1, 3, 5, 6, 7, 0, 2, 4 + }; -fail: - if (!parent) - kfree(change); - return 0; -} + if (!dev || !rule) + return -EINVAL; -/* this advanced algorithm will shuffle other configs to make room and ensure that the most possible devices have configs */ -static int pnp_advanced_config(struct pnp_dev * dev) -{ - int move; - /* if the device cannot be configured skip it */ - if (!pnp_can_configure(dev)) + if (idx >= PNP_MAX_DMA) { + pnp_err("More than 2 dmas is incompatible with pnp specifications."); + /* pretend we were successful so at least the manager won't try again */ return 1; - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) - return -ENOMEM; } - spin_lock(&pnp_lock); - for (move = 1; move <= pnp_max_moves; move++) { - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - if (pnp_next_config(dev,move,NULL)) { - spin_unlock(&pnp_lock); - return 1; - } - } - - pnp_init_resource_table(&dev->res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); - pnp_err("res: Unable to resolve resource conflicts for the device '%s', some devices may not be usable.", dev->dev.bus_id); - return 0; -} + /* check if this resource has been manually set, if so skip */ + if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO)) + return 1; -int pnp_resolve_conflicts(struct pnp_dev *dev) -{ - int i; - struct pnp_dev * cdev; + start = &dev->res.dma_resource[idx].start; + end = &dev->res.dma_resource[idx].end; + flags = &dev->res.dma_resource[idx].flags; - for (i = 0; i < PNP_MAX_PORT; i++) - { - do { - cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_MEM; i++) - { - do { - cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_IRQ; i++) - { - do { - cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - for (i = 0; i < PNP_MAX_DMA; i++) - { - do { - cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD); - if (cdev) - pnp_advanced_config(cdev); - } while (cdev); - } - return 1; -} + /* set the initial values */ + *flags = *flags | rule->flags | IORESOURCE_DMA; -/* this is a much faster algorithm but it may not leave resources for other devices to use */ -static int pnp_simple_config(struct pnp_dev * dev) -{ - int i; - spin_lock(&pnp_lock); - if (dev->active) { - spin_unlock(&pnp_lock); - return 1; - } - if (!dev->rule) { - dev->rule = pnp_alloc(sizeof(struct pnp_rule_table)); - if (!dev->rule) { - spin_unlock(&pnp_lock); - return -ENOMEM; - } - } - dev->rule->depnum = 0; - pnp_init_resource_table(&dev->res); - while (pnp_next_rule(dev)) { - for (i = 0; i < PNP_MAX_PORT; i++) { - if (!pnp_next_port(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_MEM; i++) { - if (!pnp_next_mem(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_IRQ; i++) { - if (!pnp_next_irq(dev,i)) - continue; - } - for (i = 0; i < PNP_MAX_DMA; i++) { - if (!pnp_next_dma(dev,i)) - continue; + for (i = 0; i < 8; i++) { + if(rule->map & (1<res); - dev->rule->depnum = 0; - spin_unlock(&pnp_lock); return 0; - -done: - pnp_resolve_conflicts(dev); /* this is required or we will break the advanced configs */ - return 1; } -static int pnp_compare_resources(struct pnp_resource_table * resa, struct pnp_resource_table * resb) +/** + * pnp_init_resources - Resets a resource table to default values. + * @table: pointer to the desired resource table + * + */ +void pnp_init_resources(struct pnp_resource_table *table) { int idx; + down(&pnp_res_mutex); for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (resa->irq_resource[idx].start != resb->irq_resource[idx].start) - return 1; + table->irq_resource[idx].name = NULL; + table->irq_resource[idx].start = -1; + table->irq_resource[idx].end = -1; + table->irq_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (resa->dma_resource[idx].start != resb->dma_resource[idx].start) - return 1; + table->dma_resource[idx].name = NULL; + table->dma_resource[idx].start = -1; + table->dma_resource[idx].end = -1; + table->dma_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (resa->port_resource[idx].start != resb->port_resource[idx].start) - return 1; - if (resa->port_resource[idx].end != resb->port_resource[idx].end) - return 1; + table->port_resource[idx].name = NULL; + table->port_resource[idx].start = 0; + table->port_resource[idx].end = 0; + table->port_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (resa->mem_resource[idx].start != resb->mem_resource[idx].start) - return 1; - if (resa->mem_resource[idx].end != resb->mem_resource[idx].end) - return 1; + table->mem_resource[idx].name = NULL; + table->mem_resource[idx].start = 0; + table->mem_resource[idx].end = 0; + table->mem_resource[idx].flags = IORESOURCE_AUTO; } - return 0; + up(&pnp_res_mutex); } - -/* - * PnP Device Resource Management - */ - /** - * pnp_auto_config_dev - determines the best possible resource configuration based on available information - * @dev: pointer to the desired device + * pnp_clean_resources - clears resources that were not manually set + * @res - the resources to clean * */ - -int pnp_auto_config_dev(struct pnp_dev *dev) -{ - int error; - if(!dev) - return -EINVAL; - - dev->config_mode = PNP_CONFIG_AUTO; - - if(dev->active) - error = pnp_resolve_conflicts(dev); - else - error = pnp_advanced_config(dev); - return error; -} - -static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struct pnp_resource_table * ntab) +static void pnp_clean_resources(struct pnp_resource_table * res) { int idx; for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->irq_resource[idx].start = ntab->irq_resource[idx].start; - ctab->irq_resource[idx].end = ntab->irq_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->irq_resource[idx].flags; + res->irq_resource[idx].start = -1; + res->irq_resource[idx].end = -1; + res->irq_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_DMA; idx++) { - if (ntab->dma_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->dma_resource[idx].start = ntab->dma_resource[idx].start; - ctab->dma_resource[idx].end = ntab->dma_resource[idx].end; - ctab->dma_resource[idx].flags = ntab->dma_resource[idx].flags; + res->dma_resource[idx].start = -1; + res->dma_resource[idx].end = -1; + res->dma_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_PORT; idx++) { - if (ntab->port_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->port_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->port_resource[idx].start = ntab->port_resource[idx].start; - ctab->port_resource[idx].end = ntab->port_resource[idx].end; - ctab->port_resource[idx].flags = ntab->port_resource[idx].flags; + res->port_resource[idx].start = 0; + res->port_resource[idx].end = 0; + res->port_resource[idx].flags = IORESOURCE_AUTO; } for (idx = 0; idx < PNP_MAX_MEM; idx++) { - if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO) + if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO)) continue; - ctab->irq_resource[idx].start = ntab->mem_resource[idx].start; - ctab->irq_resource[idx].end = ntab->mem_resource[idx].end; - ctab->irq_resource[idx].flags = ntab->mem_resource[idx].flags; + res->mem_resource[idx].start = 0; + res->mem_resource[idx].end = 0; + res->mem_resource[idx].flags = IORESOURCE_AUTO; + } +} + +/** + * pnp_assign_resources - assigns resources to the device based on the specified dependent number + * @dev: pointer to the desired device + * @depnum: the dependent function number + * + * Only set depnum to 0 if the device does not have dependent options. + */ +int pnp_assign_resources(struct pnp_dev *dev, int depnum) +{ + struct pnp_port *port; + struct pnp_mem *mem; + struct pnp_irq *irq; + struct pnp_dma *dma; + int nport = 0, nmem = 0, nirq = 0, ndma = 0; + + if (!pnp_can_configure(dev)) + return -ENODEV; + + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); /* start with a fresh slate */ + if (dev->independent) { + port = dev->independent->port; + mem = dev->independent->mem; + irq = dev->independent->irq; + dma = dev->independent->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } } + + if (depnum) { + struct pnp_option *dep; + int i; + for (i=1,dep=dev->dependent; inext) + if(!dep) + goto fail; + port =dep->port; + mem = dep->mem; + irq = dep->irq; + dma = dep->dma; + while (port) { + if (!pnp_assign_port(dev, port, nport)) + goto fail; + nport++; + port = port->next; + } + while (mem) { + if (!pnp_assign_mem(dev, mem, nmem)) + goto fail; + nmem++; + mem = mem->next; + } + while (irq) { + if (!pnp_assign_irq(dev, irq, nirq)) + goto fail; + nirq++; + irq = irq->next; + } + while (dma) { + if (!pnp_assign_dma(dev, dma, ndma)) + goto fail; + ndma++; + dma = dma->next; + } + } else if (dev->dependent) + goto fail; + + up(&pnp_res_mutex); + return 1; + +fail: + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + return 0; } /** @@ -572,22 +363,21 @@ * * This function can be used by drivers that want to manually set thier resources. */ - int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode) { int i; struct pnp_resource_table * bak; if (!dev || !res) return -EINVAL; - if (dev->active) - return -EBUSY; + if (!pnp_can_configure(dev)) + return -ENODEV; bak = pnp_alloc(sizeof(struct pnp_resource_table)); if (!bak) return -ENOMEM; *bak = dev->res; - spin_lock(&pnp_lock); - pnp_process_manual_resources(&dev->res, res); + down(&pnp_res_mutex); + dev->res = *res; if (!(mode & PNP_CONFIG_FORCE)) { for (i = 0; i < PNP_MAX_PORT; i++) { if(pnp_check_port(dev,i)) @@ -606,27 +396,64 @@ goto fail; } } - dev->config_mode = PNP_CONFIG_MANUAL; - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); - pnp_resolve_conflicts(dev); + pnp_auto_config_dev(dev); kfree(bak); return 0; fail: dev->res = *bak; - spin_unlock(&pnp_lock); + up(&pnp_res_mutex); kfree(bak); return -EINVAL; } /** - * pnp_activate_dev - activates a PnP device for use + * pnp_auto_config_dev - automatically assigns resources to a device * @dev: pointer to the desired device * - * finds the best resource configuration and then informs the correct pnp protocol */ +int pnp_auto_config_dev(struct pnp_dev *dev) +{ + struct pnp_option *dep; + int i = 1; + + if(!dev) + return -EINVAL; + + if(!pnp_can_configure(dev)) { + pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id); + return -ENODEV; + } + + if (!dev->dependent) { + if (pnp_assign_resources(dev, 0)) + return 1; + else + return 0; + } + + dep = dev->dependent; + do { + if (pnp_assign_resources(dev, i)) + return 1; + /* if this dependent resource failed, try the next one */ + dep = dep->next; + i++; + } while (dep); + + pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id); + return 0; +} + +/** + * pnp_activate_dev - activates a PnP device for use + * @dev: pointer to the desired device + * + * does not validate or set resources so be careful. + */ int pnp_activate_dev(struct pnp_dev *dev) { if (!dev) @@ -634,55 +461,25 @@ if (dev->active) { return 0; /* the device is already active */ } - /* If this condition is true, advanced configuration failed, we need to get this device up and running - * so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */ - if (!pnp_is_active(dev)) { - if (!pnp_simple_config(dev)) { - pnp_err("res: Unable to resolve resource conflicts for the device '%s'.", dev->dev.bus_id); - goto fail; - } - } - spin_lock(&pnp_lock); /* we lock just in case the device is being configured during this call */ - dev->active = 1; - spin_unlock(&pnp_lock); /* once the device is claimed active we know it won't be configured so we can unlock */ + /* ensure resources are allocated */ + if (!pnp_auto_config_dev(dev)) + return -EBUSY; - if (dev->config_mode & PNP_CONFIG_INVALID) { - pnp_info("res: Unable to activate the PnP device '%s' because its resource configuration is invalid.", dev->dev.bus_id); - goto fail; - } - if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){ - pnp_err("res: Activation failed because the PnP device '%s' is busy.", dev->dev.bus_id); - goto fail; - } if (!pnp_can_write(dev)) { - pnp_info("res: Unable to activate the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); - goto fail; + pnp_info("Device %s does not supported activation.", dev->dev.bus_id); + return -EINVAL; } + if (dev->protocol->set(dev, &dev->res)<0) { - pnp_err("res: The protocol '%s' reports that activating the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - goto fail; - } - if (pnp_can_read(dev)) { - struct pnp_resource_table * res = pnp_alloc(sizeof(struct pnp_resource_table)); - if (!res) - goto fail; - dev->protocol->get(dev, res); - if (pnp_compare_resources(&dev->res, res)) /* if this happens we may be in big trouble but it's best just to continue */ - pnp_err("res: The resources requested do not match those set for the PnP device '%s'.", dev->dev.bus_id); - kfree(res); - } else - dev->active = pnp_is_active(dev); - pnp_dbg("res: the device '%s' has been activated.", dev->dev.bus_id); - if (dev->rule) { - kfree(dev->rule); - dev->rule = NULL; + pnp_err("Failed to activate device %s.", dev->dev.bus_id); + return -EIO; } - return 0; -fail: - dev->active = 0; /* fixes incorrect active state */ - return -EINVAL; + dev->active = 1; + pnp_info("Device %s activated.", dev->dev.bus_id); + + return 1; } /** @@ -691,7 +488,6 @@ * * inform the correct pnp protocol so that resources can be used by other devices */ - int pnp_disable_dev(struct pnp_dev *dev) { if (!dev) @@ -699,21 +495,25 @@ if (!dev->active) { return 0; /* the device is already disabled */ } - if (dev->status != PNP_READY){ - pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id); - return -EINVAL; - } + if (!pnp_can_disable(dev)) { - pnp_info("res: Unable to disable the PnP device '%s' because this feature is not supported.", dev->dev.bus_id); + pnp_info("Device %s does not supported disabling.", dev->dev.bus_id); return -EINVAL; } if (dev->protocol->disable(dev)<0) { - pnp_err("res: The protocol '%s' reports that disabling the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id); - return -1; + pnp_err("Failed to disable device %s.", dev->dev.bus_id); + return -EIO; } - dev->active = 0; /* just in case the protocol doesn't do this */ - pnp_dbg("res: the device '%s' has been disabled.", dev->dev.bus_id); - return 0; + + dev->active = 0; + pnp_info("Device %s disabled.", dev->dev.bus_id); + + /* release the resources so that other devices can use them */ + down(&pnp_res_mutex); + pnp_clean_resources(&dev->res); + up(&pnp_res_mutex); + + return 1; } /** @@ -723,7 +523,6 @@ * @size: size of region * */ - void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { if (resource == NULL) @@ -734,19 +533,10 @@ } -EXPORT_SYMBOL(pnp_auto_config_dev); +EXPORT_SYMBOL(pnp_assign_resources); EXPORT_SYMBOL(pnp_manual_config_dev); +EXPORT_SYMBOL(pnp_auto_config_dev); EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_disable_dev); EXPORT_SYMBOL(pnp_resource_change); - - -/* format is: pnp_max_moves=num */ - -static int __init pnp_setup_max_moves(char *str) -{ - get_option(&str,&pnp_max_moves); - return 1; -} - -__setup("pnp_max_moves=", pnp_setup_max_moves); +EXPORT_SYMBOL(pnp_init_resources); diff -Nru a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c --- a/drivers/pnp/pnpbios/core.c Tue Jun 10 00:49:52 2003 +++ b/drivers/pnp/pnpbios/core.c Wed Jun 18 15:31:32 2003 @@ -935,6 +935,10 @@ dev->capabilities |= PNP_REMOVABLE; dev->protocol = &pnpbios_protocol; + /* clear out the damaged flags */ + if (!dev->active) + pnp_init_resources(&dev->res); + pnp_add_device(dev); pnpbios_interface_attach_device(node); diff -Nru a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c --- a/drivers/pnp/quirks.c Sun May 25 14:08:19 2003 +++ b/drivers/pnp/quirks.c Wed Jun 18 15:22:42 2003 @@ -30,7 +30,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev) { struct pnp_port *port, *port2, *port3; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; /* * Unfortunately the isapnp_add_port_resource is too tightly bound @@ -38,7 +38,7 @@ * two extra ports (at offset 0x400 and 0x800 from the one given) by * hand. */ - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { port2 = pnp_alloc(sizeof(struct pnp_port)); if (!port2) return; @@ -62,9 +62,9 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev) { - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; - for ( ; res ; res = res->dep ) { + for ( ; res ; res = res->next ) { struct pnp_irq *irq; struct pnp_dma *dma; @@ -82,7 +82,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) { struct pnp_port *port; - struct pnp_resources *res = dev->possible->dep; + struct pnp_option *res = dev->dependent; int changed = 0; /* @@ -91,7 +91,7 @@ * auto-configured. */ - for( ; res ; res = res->dep ) { + for( ; res ; res = res->next ) { port = res->port; if(!port) continue; @@ -118,11 +118,11 @@ * doesn't allow a DMA channel of 0, afflicted card is an * OPL3Sax where x=4. */ - struct pnp_resources *res; + struct pnp_option *res; int max; - res = dev->possible; + res = dev->dependent; max = 0; - for (res = res->dep; res; res = res->dep) { + for (; res; res = res->next) { if (res->dma->map > max) max = res->dma->map; } diff -Nru a/drivers/pnp/resource.c b/drivers/pnp/resource.c --- a/drivers/pnp/resource.c Wed Jun 4 05:28:30 2003 +++ b/drivers/pnp/resource.c Wed Jun 18 15:27:52 2003 @@ -10,18 +10,19 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include "base.h" -int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */ +int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: + * -1=off (:default), 0=off (set by user), 1=on */ int pnp_skip_pci_scan; /* skip PCI resource scanning */ int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */ @@ -30,88 +31,75 @@ /* - * possible resource registration + * option registration */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) +static struct pnp_option * pnp_build_option(int priority) { - struct pnp_resources *res, *ptr, *ptra; + struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); - res = pnp_alloc(sizeof(struct pnp_resources)); - if (!res) + /* check if pnp_alloc ran out of memory */ + if (!option) return NULL; - ptr = dev->possible; - if (ptr) { /* add to another list */ - ptra = ptr->dep; - while (ptra && ptra->dep) - ptra = ptra->dep; - if (!ptra) - ptr->dep = res; - else - ptra->dep = res; - } else - dev->possible = res; - if (dependent) { - res->priority = dependent & 0xff; - if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL) - res->priority = PNP_RES_PRIORITY_INVALID; - } else - res->priority = PNP_RES_PRIORITY_PREFERRED; - return res; + + option->priority = priority & 0xff; + /* make sure the priority is valid */ + if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL) + option->priority = PNP_RES_PRIORITY_INVALID; + + return option; } -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { - int i; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) return NULL; - res = dev->possible; - if (!res) - return NULL; - for (i = 0; i < depnum; i++) - { - if (res->dep) - res = res->dep; - else - return NULL; - } - return res; + + option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED); + + /* this should never happen but if it does we'll try to continue */ + if (dev->independent) + pnp_err("independent resource already registered"); + dev->independent = option; + return option; } -int pnp_get_max_depnum(struct pnp_dev *dev) +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { - int num = 0; - struct pnp_resources *res; + struct pnp_option *option; if (!dev) - return -EINVAL; - res = dev->possible; - if (!res) - return -EINVAL; - while (res->dep){ - res = res->dep; - num++; - } - return num; + return NULL; + + option = pnp_build_option(priority); + + if (dev->dependent) { + struct pnp_option *parent = dev->dependent; + while (parent->next) + parent = parent->next; + parent->next = option; + } else + dev->dependent = option; + return option; } -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { int i; - struct pnp_resources *res; struct pnp_irq *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->irq; + + ptr = option->irq; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->irq = data; + option->irq = data; + #ifdef CONFIG_PCI for (i=0; i<16; i++) if (data->map & (1<dma; + + ptr = option->dma; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->dma = data; + option->dma = data; + return 0; } -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data) +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { - struct pnp_resources *res; struct pnp_port *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->port; + + ptr = option->port; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->port = data; + option->port = data; + return 0; } -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data) +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { - struct pnp_resources *res; struct pnp_mem *ptr; - res = pnp_find_resources(dev,depnum); - if (!res) + if (!option) return -EINVAL; if (!data) return -EINVAL; - ptr = res->mem; + + ptr = option->mem; while (ptr && ptr->next) ptr = ptr->next; if (ptr) ptr->next = data; else - res->mem = data; + option->mem = data; return 0; } @@ -221,18 +208,18 @@ } } -void pnp_free_resources(struct pnp_resources *resources) +void pnp_free_option(struct pnp_option *option) { - struct pnp_resources *next; + struct pnp_option *next; - while (resources) { - next = resources->dep; - pnp_free_port(resources->port); - pnp_free_irq(resources->irq); - pnp_free_dma(resources->dma); - pnp_free_mem(resources->mem); - kfree(resources); - resources = next; + while (option) { + next = option->next; + pnp_free_port(option->port); + pnp_free_irq(option->irq); + pnp_free_dma(option->dma); + pnp_free_mem(option->mem); + kfree(option); + option = next; } } @@ -253,50 +240,23 @@ (*(enda) >= *(startb) && *(enda) <= *(endb)) || \ (*(starta) < *(startb) && *(enda) > *(endb))) -struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *port, *end, *tport, *tend; - struct pnp_dev *tdev; - port = &dev->res.port_resource[idx].start; - end = &dev->res.port_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.port_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ - pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) - continue; - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { - if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { - tport = &tdev->res.port_resource[tmp].start; - tend = &tdev->res.port_resource[tmp].end; - if (ranged_conflict(port,end,tport,tend)) - return tdev; - } - } - } - return NULL; -} - int pnp_check_port(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *port, *end, *tport, *tend; port = &dev->res.port_resource[idx].start; end = &dev->res.port_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.port_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { - if (check_region(*port, length(port,end))) - return CONFLICT_TYPE_IN_USE; + if (__check_region(&ioport_resource, *port, length(port,end))) + return 0; } /* check if the resource is reserved */ @@ -304,7 +264,7 @@ int rport = pnp_reserve_io[tmp << 1]; int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1; if (ranged_conflict(port,end,&rport,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -313,61 +273,44 @@ tport = &dev->res.port_resource[tmp].start; tend = &dev->res.port_resource[tmp].end; if (ranged_conflict(port,end,tport,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - unsigned long *addr, *end, *taddr, *tend; - struct pnp_dev *tdev; - addr = &dev->res.mem_resource[idx].start; - end = &dev->res.mem_resource[idx].end; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.mem_resource[idx].start == 0) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { - if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { - taddr = &tdev->res.mem_resource[tmp].start; - tend = &tdev->res.mem_resource[tmp].end; - if (ranged_conflict(addr,end,taddr,tend)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) { + if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) { + tport = &tdev->res.port_resource[tmp].start; + tend = &tdev->res.port_resource[tmp].end; + if (ranged_conflict(port,end,tport,tend)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_mem(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long *addr, *end, *taddr, *tend; addr = &dev->res.mem_resource[idx].start; end = &dev->res.mem_resource[idx].end; /* if the resource doesn't exist, don't complain about it */ if (dev->res.mem_resource[idx].start == 0) - return 0; + return 1; - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { - if (__check_region(&iomem_resource, *addr, length(addr,end))) - return CONFLICT_TYPE_IN_USE; + if (check_mem_region(*addr, length(addr,end))) + return 0; } /* check if the resource is reserved */ @@ -375,7 +318,7 @@ int raddr = pnp_reserve_mem[tmp << 1]; int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1; if (ranged_conflict(addr,end,&raddr,&rend)) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ @@ -384,40 +327,25 @@ taddr = &dev->res.mem_resource[tmp].start; tend = &dev->res.mem_resource[tmp].end; if (ranged_conflict(addr,end,taddr,tend)) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check for warm conflicts */ - if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - -struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * irq = &dev->res.irq_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.irq_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { - if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { - if ((tdev->res.irq_resource[tmp].start == *irq)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) { + if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) { + taddr = &tdev->res.mem_resource[tmp].start; + tend = &tdev->res.mem_resource[tmp].end; + if (ranged_conflict(addr,end,taddr,tend)) + return 0; } } } - return NULL; + + return 1; } static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs) @@ -428,27 +356,28 @@ int pnp_check_irq(struct pnp_dev * dev, int idx) { int tmp; + struct pnp_dev *tdev; unsigned long * irq = &dev->res.irq_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.irq_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (*irq < 0 || *irq > 15) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 16; tmp++) { if (pnp_reserve_irq[tmp] == *irq) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) { if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { if (dev->res.irq_resource[tmp].start == *irq) - return CONFLICT_TYPE_INTERNAL; + return 0; } } @@ -458,233 +387,94 @@ struct pci_dev * pci = NULL; while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { if (pci->irq == *irq) - return CONFLICT_TYPE_PCI; + return 0; } } #endif - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL)) - return CONFLICT_TYPE_IN_USE; + return 0; free_irq(*irq, NULL); } - /* check for warm conflicts */ - if (pnp_check_irq_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - - return 0; -} - - -struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode) -{ - int tmp; - struct pnp_dev * tdev; - unsigned long * dma = &dev->res.dma_resource[idx].start; - - /* if the resource doesn't exist, don't complain about it */ - if (dev->res.dma_resource[idx].start == -1) - return NULL; - - /* check for cold conflicts */ + /* check for conflicts with other pnp devices */ pnp_for_each_dev(tdev) { - /* Is the device configurable? */ - if (tdev == dev || (mode ? !tdev->active : tdev->active)) + if (tdev == dev) continue; - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { - if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { - if ((tdev->res.dma_resource[tmp].start == *dma)) - return tdev; + for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) { + if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) { + if ((tdev->res.irq_resource[tmp].start == *irq)) + return 0; } } } - return NULL; + + return 1; } int pnp_check_dma(struct pnp_dev * dev, int idx) { int tmp, mindma = 1; + struct pnp_dev *tdev; unsigned long * dma = &dev->res.dma_resource[idx].start; /* if the resource doesn't exist, don't complain about it */ if (dev->res.dma_resource[idx].start == -1) - return 0; + return 1; /* check if the resource is valid */ if (pnp_allow_dma0 == 1) mindma = 0; if (*dma < mindma || *dma == 4 || *dma > 7) - return CONFLICT_TYPE_INVALID; + return 0; /* check if the resource is reserved */ for (tmp = 0; tmp < 8; tmp++) { if (pnp_reserve_dma[tmp] == *dma) - return CONFLICT_TYPE_RESERVED; + return 0; } /* check for internal conflicts */ for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) { if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { if (dev->res.dma_resource[tmp].start == *dma) - return CONFLICT_TYPE_INTERNAL; + return 0; } } - /* check if the resource is already in use, skip if the device is active because it itself may be in use */ + /* check if the resource is already in use, skip if the + * device is active because it itself may be in use */ if(!dev->active) { if (request_dma(*dma, "pnp")) - return CONFLICT_TYPE_IN_USE; + return 0; free_dma(*dma); } - /* check for warm conflicts */ - if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM)) - return CONFLICT_TYPE_PNP_WARM; - return 0; -} - - -/** - * pnp_init_resource_table - Resets a resource table to default values. - * @table: pointer to the desired resource table - * - */ - -void pnp_init_resource_table(struct pnp_resource_table *table) -{ - int idx; - for (idx = 0; idx < PNP_MAX_IRQ; idx++) { - table->irq_resource[idx].name = NULL; - table->irq_resource[idx].start = -1; - table->irq_resource[idx].end = -1; - table->irq_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_DMA; idx++) { - table->dma_resource[idx].name = NULL; - table->dma_resource[idx].start = -1; - table->dma_resource[idx].end = -1; - table->dma_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_PORT; idx++) { - table->port_resource[idx].name = NULL; - table->port_resource[idx].start = 0; - table->port_resource[idx].end = 0; - table->port_resource[idx].flags = IORESOURCE_AUTO; - } - for (idx = 0; idx < PNP_MAX_MEM; idx++) { - table->mem_resource[idx].name = NULL; - table->mem_resource[idx].start = 0; - table->mem_resource[idx].end = 0; - table->mem_resource[idx].flags = IORESOURCE_AUTO; - } -} - - -/** - * pnp_generate_rule - Creates a rule table structure based on depnum and device. - * @dev: pointer to the desired device - * @depnum: dependent function, if not valid will return an error - * @rule: pointer to a rule structure to record data to - * - */ - -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) -{ - int nport = 0, nirq = 0, ndma = 0, nmem = 0; - struct pnp_resources * res; - struct pnp_port * port; - struct pnp_mem * mem; - struct pnp_irq * irq; - struct pnp_dma * dma; - - if (depnum < 0 || !rule) - return -EINVAL; - - /* independent */ - res = pnp_find_resources(dev, 0); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; + /* check for conflicts with other pnp devices */ + pnp_for_each_dev(tdev) { + if (tdev == dev) + continue; + for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) { + if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) { + if ((tdev->res.dma_resource[tmp].start == *dma)) + return 0; + } + } } - /* dependent */ - if (depnum == 0) - return 1; - res = pnp_find_resources(dev, depnum); - if (!res) - return -ENODEV; - port = res->port; - mem = res->mem; - irq = res->irq; - dma = res->dma; - while (port){ - rule->port[nport] = port; - nport++; - port = port->next; - } - while (mem){ - rule->mem[nmem] = mem; - nmem++; - mem = mem->next; - } - - while (irq){ - rule->irq[nirq] = irq; - nirq++; - irq = irq->next; - } - while (dma){ - rule->dma[ndma] = dma; - ndma++; - dma = dma->next; - } - - /* clear the remaining values */ - for (; nport < PNP_MAX_PORT; nport++) - rule->port[nport] = NULL; - for (; nmem < PNP_MAX_MEM; nmem++) - rule->mem[nmem] = NULL; - for (; nirq < PNP_MAX_IRQ; nirq++) - rule->irq[nirq] = NULL; - for (; ndma < PNP_MAX_DMA; ndma++) - rule->dma[ndma] = NULL; return 1; } -EXPORT_SYMBOL(pnp_build_resource); -EXPORT_SYMBOL(pnp_find_resources); -EXPORT_SYMBOL(pnp_get_max_depnum); -EXPORT_SYMBOL(pnp_add_irq_resource); -EXPORT_SYMBOL(pnp_add_dma_resource); -EXPORT_SYMBOL(pnp_add_port_resource); -EXPORT_SYMBOL(pnp_add_mem_resource); -EXPORT_SYMBOL(pnp_init_resource_table); -EXPORT_SYMBOL(pnp_generate_rule); +EXPORT_SYMBOL(pnp_register_dependent_option); +EXPORT_SYMBOL(pnp_register_independent_option); +EXPORT_SYMBOL(pnp_register_irq_resource); +EXPORT_SYMBOL(pnp_register_dma_resource); +EXPORT_SYMBOL(pnp_register_port_resource); +EXPORT_SYMBOL(pnp_register_mem_resource); /* format is: allowdma0 */ diff -Nru a/drivers/pnp/support.c b/drivers/pnp/support.c --- a/drivers/pnp/support.c Wed Feb 19 09:54:46 2003 +++ b/drivers/pnp/support.c Wed Jun 18 15:38:33 2003 @@ -1,7 +1,7 @@ /* * support.c - provides standard pnp functions for the use of pnp protocol drivers, * - * Copyright 2002 Adam Belay + * Copyright 2003 Adam Belay * * Resource parsing functions are based on those in the linux pnpbios driver. * Copyright Christian Schmidt, Tom Lees, David Hinds, Alan Cox, Thomas Hood, @@ -10,6 +10,7 @@ #include #include +#include #ifdef CONFIG_PNP_DEBUG #define DEBUG @@ -122,7 +123,7 @@ return NULL; /* Blank the resource table values */ - pnp_init_resource_table(res); + pnp_init_resources(res); while ((char *)p < (char *)end) { @@ -250,51 +251,51 @@ * Possible resource reading functions * */ -static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = ((p[3] << 8) | p[2]) << 8; - mem->max = ((p[5] << 8) | p[4]) << 8; - mem->align = (p[7] << 8) | p[6]; - mem->size = ((p[9] << 8) | p[8]) << 8; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->min = ((p[5] << 8) | p[4]) << 8; + mem->max = ((p[7] << 8) | p[6]) << 8; + mem->align = (p[9] << 8) | p[8]; + mem->size = ((p[11] << 8) | p[10]) << 8; + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2]; - mem->max = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6]; - mem->align = (p[13] << 24) | (p[12] << 16) | (p[11] << 8) | p[10]; - mem->size = (p[17] << 24) | (p[16] << 16) | (p[15] << 8) | p[14]; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; + mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12]; + mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16]; + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_mem32(unsigned char *p, int size, struct pnp_option *option) { struct pnp_mem * mem; mem = pnp_alloc(sizeof(struct pnp_mem)); if (!mem) return; - mem->min = mem->max = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2]; - mem->size = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6]; + mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]; + mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]; mem->align = 0; - mem->flags = p[1]; - pnp_add_mem_resource(dev,depnum,mem); + mem->flags = p[3]; + pnp_register_mem_resource(option,mem); return; } -static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_irq(unsigned char *p, int size, struct pnp_option *option) { struct pnp_irq * irq; irq = pnp_alloc(sizeof(struct pnp_irq)); @@ -303,11 +304,13 @@ irq->map = (p[2] << 8) | p[1]; if (size > 2) irq->flags = p[3]; - pnp_add_irq_resource(dev,depnum,irq); + else + irq->flags = IORESOURCE_IRQ_HIGHEDGE; + pnp_register_irq_resource(option,irq); return; } -static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_dma(unsigned char *p, int size, struct pnp_option *option) { struct pnp_dma * dma; dma = pnp_alloc(sizeof(struct pnp_dma)); @@ -315,11 +318,11 @@ return; dma->map = p[1]; dma->flags = p[2]; - pnp_add_dma_resource(dev,depnum,dma); + pnp_register_dma_resource(option,dma); return; } -static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -330,11 +333,11 @@ port->align = p[6]; port->size = p[7]; port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } -static void possible_fixed_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev) +static void possible_fixed_port(unsigned char *p, int size, struct pnp_option *option) { struct pnp_port * port; port = pnp_alloc(sizeof(struct pnp_port)); @@ -344,7 +347,7 @@ port->size = p[3]; port->align = 0; port->flags = PNP_PORT_FLAG_FIXED; - pnp_add_port_resource(dev,depnum,port); + pnp_register_port_resource(option,port); return; } @@ -358,12 +361,14 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev *dev) { - int len, depnum = 0, dependent = 0; + int len, priority = 0; + struct pnp_option *option; if (!p) return NULL; - if (pnp_build_resource(dev, 0) == NULL) + option = pnp_register_independent_option(dev); + if (!option) return NULL; while ((char *)p < (char *)end) { @@ -375,21 +380,21 @@ { if (len != 9) goto lrg_err; - possible_mem(p,len,depnum,dev); + possible_mem(p,len,option); break; } case LARGE_TAG_MEM32: { if (len != 17) goto lrg_err; - possible_mem32(p,len,depnum,dev); + possible_mem32(p,len,option); break; } case LARGE_TAG_FIXEDMEM32: { if (len != 9) goto lrg_err; - possible_fixed_mem32(p,len,depnum,dev); + possible_fixed_mem32(p,len,option); break; } default: /* an unkown tag */ @@ -410,46 +415,46 @@ { if (len < 2 || len > 3) goto sm_err; - possible_irq(p,len,depnum,dev); + possible_irq(p,len,option); break; } case SMALL_TAG_DMA: { if (len != 2) goto sm_err; - possible_dma(p,len,depnum,dev); + possible_dma(p,len,option); break; } case SMALL_TAG_STARTDEP: { if (len > 1) goto sm_err; - dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; + priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE; if (len > 0) - dependent = 0x100 | p[1]; - pnp_build_resource(dev,dependent); - depnum = pnp_get_max_depnum(dev); + priority = 0x100 | p[1]; + option = pnp_register_dependent_option(dev, priority); + if (!option) + return NULL; break; } case SMALL_TAG_ENDDEP: { if (len != 0) goto sm_err; - depnum = 0; break; } case SMALL_TAG_PORT: { if (len != 7) goto sm_err; - possible_port(p,len,depnum,dev); + possible_port(p,len,option); break; } case SMALL_TAG_FIXEDPORT: { if (len != 3) goto sm_err; - possible_fixed_port(p,len,depnum,dev); + possible_fixed_port(p,len,option); break; } case SMALL_TAG_END: @@ -481,12 +486,12 @@ { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = (base >> 8) & 0xff; - p[3] = ((base >> 8) >> 8) & 0xff; p[4] = (base >> 8) & 0xff; p[5] = ((base >> 8) >> 8) & 0xff; - p[8] = (len >> 8) & 0xff; - p[9] = ((len >> 8) >> 8) & 0xff; + p[6] = (base >> 8) & 0xff; + p[7] = ((base >> 8) >> 8) & 0xff; + p[10] = (len >> 8) & 0xff; + p[11] = ((len >> 8) >> 8) & 0xff; return; } @@ -494,32 +499,32 @@ { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = base & 0xff; - p[3] = (base >> 8) & 0xff; - p[4] = (base >> 16) & 0xff; - p[5] = (base >> 24) & 0xff; - p[6] = base & 0xff; - p[7] = (base >> 8) & 0xff; - p[8] = (base >> 16) & 0xff; - p[9] = (base >> 24) & 0xff; - p[14] = len & 0xff; - p[15] = (len >> 8) & 0xff; - p[16] = (len >> 16) & 0xff; - p[17] = (len >> 24) & 0xff; + p[4] = base & 0xff; + p[5] = (base >> 8) & 0xff; + p[6] = (base >> 16) & 0xff; + p[7] = (base >> 24) & 0xff; + p[8] = base & 0xff; + p[9] = (base >> 8) & 0xff; + p[10] = (base >> 16) & 0xff; + p[11] = (base >> 24) & 0xff; + p[16] = len & 0xff; + p[17] = (len >> 8) & 0xff; + p[18] = (len >> 16) & 0xff; + p[19] = (len >> 24) & 0xff; return; } static void write_fixed_mem32(unsigned char *p, struct resource * res) { unsigned long base = res->start; unsigned long len = res->end - res->start + 1; - p[2] = base & 0xff; - p[3] = (base >> 8) & 0xff; - p[4] = (base >> 16) & 0xff; - p[5] = (base >> 24) & 0xff; - p[6] = len & 0xff; - p[7] = (len >> 8) & 0xff; - p[8] = (len >> 16) & 0xff; - p[9] = (len >> 24) & 0xff; + p[4] = base & 0xff; + p[5] = (base >> 8) & 0xff; + p[6] = (base >> 16) & 0xff; + p[7] = (base >> 24) & 0xff; + p[8] = len & 0xff; + p[9] = (len >> 8) & 0xff; + p[10] = (len >> 16) & 0xff; + p[11] = (len >> 24) & 0xff; return; } @@ -630,7 +635,7 @@ { if (len != 2) goto sm_err; - write_dma(p, &res->dma_resource[irq]); + write_dma(p, &res->dma_resource[dma]); dma++; break; } diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c --- a/drivers/scsi/53c700.c Mon May 26 14:44:44 2003 +++ b/drivers/scsi/53c700.c Sun Jun 8 15:37:49 2003 @@ -168,7 +168,6 @@ STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt); -STATIC int NCR_700_proc_directory_info(struct Scsi_Host *, char *, char **, off_t, int, int); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt); @@ -281,7 +280,6 @@ tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; tpnt->use_clustering = DISABLE_CLUSTERING; - tpnt->proc_info = NCR_700_proc_directory_info; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; tpnt->use_blk_tcq = 1; @@ -293,7 +291,8 @@ tpnt->proc_name = "53c700"; - if((host = scsi_register(tpnt, 4)) == NULL) + host = scsi_host_alloc(tpnt, 4); + if (!host) return NULL; memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST); @@ -1707,35 +1706,6 @@ out_unlock: spin_unlock_irqrestore(host->host_lock, flags); return IRQ_RETVAL(handled); -} - -STATIC int -NCR_700_proc_directory_info(struct Scsi_Host *host, char *proc_buf, char **startp, - off_t offset, int bytes_available, int write) -{ - static char buf[4096]; /* 1 page should be sufficient */ - int len = 0; - struct NCR_700_Host_Parameters *hostdata; - Scsi_Device *SDp; - - if(write) { - /* FIXME: Clear internal statistics here */ - return 0; - } - hostdata = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - len += sprintf(&buf[len], "Total commands outstanding: %d\n", hostdata->command_slot_count); - len += sprintf(&buf[len],"\ -Target Active Next Tag\n\ -====== ====== ========\n"); - list_for_each_entry(SDp, &host->my_devices, siblings) { - len += sprintf(&buf[len]," %2d:%2d %4d %4d\n", SDp->id, SDp->lun, NCR_700_get_depth(SDp), SDp->current_tag); - } - if((len -= offset) <= 0) - return 0; - if(len > bytes_available) - len = bytes_available; - memcpy(proc_buf, buf + offset, len); - return len; } STATIC int diff -Nru a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h --- a/drivers/scsi/53c700.h Sat Apr 26 07:28:12 2003 +++ b/drivers/scsi/53c700.h Tue Jun 17 13:27:44 2003 @@ -12,6 +12,10 @@ #include +#if defined(CONFIG_53C700_MEM_MAPPED) && defined(CONFIG_53C700_IO_MAPPED) +#define CONFIG_53C700_BOTH_MAPPED +#endif + /* Turn on for general debugging---too verbose for normal use */ #undef NCR_700_DEBUG /* Debug the tag queues, checking hash queue allocation and deallocation @@ -178,6 +182,9 @@ /* NOTHING BELOW HERE NEEDS ALTERING */ __u32 fast:1; /* if we can alter the SCSI bus clock speed (so can negiotiate sync) */ +#ifdef CONFIG_53C700_BOTH_MAPPED + __u32 mem_mapped; /* set if memory mapped */ +#endif int sync_clock; /* The speed of the SYNC core */ __u32 *script; /* pointer to script location */ @@ -428,11 +435,8 @@ } \ } -#endif - -#ifdef CONFIG_53C700_MEM_MAPPED static inline __u8 -NCR_700_readb(struct Scsi_Host *host, __u32 reg) +NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -441,7 +445,7 @@ } static inline __u32 -NCR_700_readl(struct Scsi_Host *host, __u32 reg) +NCR_700_mem_readl(struct Scsi_Host *host, __u32 reg) { __u32 value = __raw_readl(host->base + reg); const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) @@ -456,7 +460,7 @@ } static inline void -NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +NCR_700_mem_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -465,7 +469,7 @@ } static inline void -NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +NCR_700_mem_writel(__u32 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -478,9 +482,9 @@ __raw_writel(bS_to_host(value), host->base + reg); } -#elif defined(CONFIG_53C700_IO_MAPPED) + static inline __u8 -NCR_700_readb(struct Scsi_Host *host, __u32 reg) +NCR_700_io_readb(struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -489,7 +493,7 @@ } static inline __u32 -NCR_700_readl(struct Scsi_Host *host, __u32 reg) +NCR_700_io_readl(struct Scsi_Host *host, __u32 reg) { __u32 value = inl(host->base + reg); const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) @@ -505,7 +509,7 @@ } static inline void -NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +NCR_700_io_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -514,7 +518,7 @@ } static inline void -NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +NCR_700_io_writel(__u32 value, struct Scsi_Host *host, __u32 reg) { const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) = (struct NCR_700_Host_Parameters *)host->hostdata[0]; @@ -527,4 +531,100 @@ outl(bS_to_host(value), host->base + reg); } + +#ifdef CONFIG_53C700_BOTH_MAPPED + +static inline __u8 +NCR_700_readb(struct Scsi_Host *host, __u32 reg) +{ + __u8 val; + + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + val = NCR_700_mem_readb(host, reg); + else + val = NCR_700_io_readb(host, reg); + + return val; +} + +static inline __u32 +NCR_700_readl(struct Scsi_Host *host, __u32 reg) +{ + __u32 val; + + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + val = NCR_700_mem_readl(host, reg); + else + val = NCR_700_io_readl(host, reg); + + return val; +} + +static inline void +NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + NCR_700_mem_writeb(value, host, reg); + else + NCR_700_io_writeb(value, host, reg); +} + +static inline void +NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) +{ + const struct NCR_700_Host_Parameters *hostdata __attribute__((unused)) + = (struct NCR_700_Host_Parameters *)host->hostdata[0]; + + if(hostdata->mem_mapped) + NCR_700_mem_writel(value, host, reg); + else + NCR_700_io_writel(value, host, reg); +} + +static inline void +NCR_700_set_mem_mapped(struct NCR_700_Host_Parameters *hostdata) +{ + hostdata->mem_mapped = 1; +} + +static inline void +NCR_700_set_io_mapped(struct NCR_700_Host_Parameters *hostdata) +{ + hostdata->mem_mapped = 0; +} + + +#elif defined(CONFIG_53C700_IO_MAPPED) + +#define NCR_700_readb NCR_700_io_readb +#define NCR_700_readl NCR_700_io_readl +#define NCR_700_writeb NCR_700_io_writeb +#define NCR_700_writel NCR_700_io_writel + +#define NCR_700_set_io_mapped(x) +#define NCR_700_set_mem_mapped(x) error I/O mapped only + +#elif defined(CONFIG_53C700_MEM_MAPPED) + +#define NCR_700_readb NCR_700_mem_readb +#define NCR_700_readl NCR_700_mem_readl +#define NCR_700_writeb NCR_700_mem_writeb +#define NCR_700_writel NCR_700_mem_writel + +#define NCR_700_set_io_mapped(x) error MEM mapped only +#define NCR_700_set_mem_mapped(x) + +#else +#error neither CONFIG_53C700_MEM_MAPPED nor CONFIG_53C700_IO_MAPPED is set +#endif + #endif diff -Nru a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c --- a/drivers/scsi/AM53C974.c Tue May 13 03:59:32 2003 +++ b/drivers/scsi/AM53C974.c Sun Jun 8 12:18:41 2003 @@ -817,22 +817,6 @@ return (info); } -/************************************************************************** -* Function : int AM53C974_command (Scsi_Cmnd *SCpnt) * -* * -* Purpose : the unqueued SCSI command function, replaced by the * -* AM53C974_queue_command function * -* * -* Inputs : SCpnt - pointer to command structure * -* * -* Returns :status, see hosts.h for details * -***************************************************************************/ -static int AM53C974_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("AM53C974_command called\n")); - return 0; -} - /************************************************************************** * Function : void initialize_SCp(Scsi_Cmnd *cmd) * * * @@ -2466,7 +2450,6 @@ .detect = AM53C974_pci_detect, .release = AM53C974_release, .info = AM53C974_info, - .command = AM53C974_command, .queuecommand = AM53C974_queue_command, .abort = AM53C974_abort, .reset = AM53C974_reset, diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Wed Jun 4 22:53:09 2003 +++ b/drivers/scsi/Kconfig Thu Jun 5 16:09:41 2003 @@ -27,8 +27,8 @@ If you want to use a SCSI tape drive under Linux, say Y and read the SCSI-HOWTO, available from , and - in the kernel source. This is NOT for - SCSI CD-ROMs. + in the kernel source. This is NOT + for SCSI CD-ROMs. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -131,11 +131,11 @@ depends on SCSI default y help - If you want to build with SCSI REPORT LUNS support in the kernel, say Y here. - The REPORT LUNS command is useful for devices (such as disk arrays) with - large numbers of LUNs where the LUN values are not contiguous (sparse LUN). - REPORT LUNS scanning is done only for SCSI-3 devices. Most users can safely - answer N here. + If you want support for SCSI REPORT LUNS, say Y here. + The REPORT LUNS command is useful for devices (such as disk arrays) + with large numbers of LUNs where the LUN values are not contiguous + (sparse LUN). REPORT LUNS scanning is done only for SCSI-3 devices. + Most users can safely answer N here. config SCSI_CONSTANTS bool "Verbose SCSI error reporting (kernel size +=12K)" @@ -207,7 +207,7 @@ config SCSI_7000FASST tristate "7000FASST SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This driver supports the Western Digital 7000 SCSI host adapter family. Some information is in the source: @@ -220,7 +220,7 @@ config SCSI_ACARD tristate "ACARD SCSI support" - depends on SCSI + depends on PCI && SCSI help This driver supports the ACARD 870U/W SCSI host adapter. @@ -285,6 +285,7 @@ config SCSI_AIC7XXX_OLD tristate "Adaptec AIC7xxx support (old driver)" + depends on SCSI help WARNING This driver is an older aic7xxx driver and is no longer under active development. Adaptec, Inc. is writing a new driver to @@ -343,7 +344,7 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in @@ -357,7 +358,7 @@ config SCSI_IN2000 tristate "Always IN2000 SCSI support" - depends on SCSI + depends on ISA && SCSI help This is support for an ISA bus SCSI host adapter. You'll find more information in . If it doesn't work @@ -369,10 +370,10 @@ say M here and read . The module will be called in2000. -# does not use pci dma and seems to be isa/onboard only for old machines +# does not use pci dma and seems to be onboard only for old machines config SCSI_AM53C974 tristate "AM53/79C974 PCI SCSI support" - depends on !X86_64 && SCSI && PCI + depends on X86 && PCI && SCSI ---help--- This is support for the AM53/79C974 SCSI host adapters. Please read for details. Also, the @@ -390,7 +391,7 @@ config SCSI_MEGARAID tristate "AMI MegaRAID support" - depends on SCSI + depends on PCI && SCSI help This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490 and 467 SCSI host adapters. @@ -402,7 +403,7 @@ config SCSI_BUSLOGIC tristate "BusLogic SCSI support" - depends on SCSI + depends on (PCI || ISA) && SCSI ---help--- This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from @@ -436,7 +437,7 @@ config SCSI_DMX3191D tristate "DMX3191D SCSI support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for Domex DMX3191D SCSI Host Adapters. @@ -447,7 +448,7 @@ config SCSI_DTC3280 tristate "DTC3180/3280 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for DTC 3180/3280 SCSI Host Adapters. Please read the SCSI-HOWTO, available from @@ -461,7 +462,7 @@ config SCSI_EATA tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- This driver supports all EATA/DMA-compliant SCSI host adapters. DPT ISA and all EISA I/O addresses are probed looking for the "EATA" @@ -527,7 +528,7 @@ config SCSI_FUTURE_DOMAIN tristate "Future Domain 16xx SCSI/AHA-2920A support" - depends on SCSI + depends on (ISA || PCI) && SCSI ---help--- This is support for Future Domain's 16-bit SCSI host adapters (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and @@ -563,7 +564,7 @@ config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on SCSI + depends on (ISA || EISA || PCI) && SCSI ---help--- Formerly called GDT SCSI Disk Array Controller Support. @@ -579,7 +580,7 @@ config SCSI_GENERIC_NCR5380 tristate "Generic NCR5380/53c400 SCSI PIO support" - depends on SCSI + depends on ISA && SCSI ---help--- This is a driver for the old NCR 53c80 series of SCSI controllers on boards using PIO. Most boards such as the Trantor T130 fit this @@ -600,7 +601,7 @@ config SCSI_GENERIC_NCR5380_MMIO tristate "Generic NCR5380/53c400 SCSI MMIO support" - depends on SCSI + depends on ISA && SCSI ---help--- This is a driver for the old NCR 53c80 series of SCSI controllers on boards using memory mapped I/O. @@ -609,10 +610,11 @@ of the box, you may have to change some settings in . - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called g_NCR5380. If you want to compile it as - a module, say M here and read . + This driver is also available as a module ( = code which can + be inserted in and removed from the running kernel whenever + you want). The module will be called g_NCR5380_mmio. + If you want to compile it as a module, say M here and read + . config SCSI_GENERIC_NCR53C400 bool "Enable NCR53c400 extensions" @@ -699,7 +701,7 @@ config SCSI_IPS tristate "IBM ServeRAID support" - depends on X86 && SCSI && PCI + depends on X86 && PCI && SCSI ---help--- This is support for the IBM ServeRAID hardware RAID controllers. See @@ -715,7 +717,7 @@ config SCSI_INITIO tristate "Initio 9100U(W) support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for the Initio 91XXU(W) SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -728,7 +730,7 @@ config SCSI_INIA100 tristate "Initio INI-A100U2W support" - depends on SCSI && PCI + depends on PCI && SCSI help This is support for the Initio INI-A100U2W SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -828,7 +830,7 @@ config SCSI_NCR53C406A tristate "NCR53c406a SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for the NCR53c406a SCSI host adapter. For user configurable parameters, check out @@ -857,14 +859,12 @@ default y config SCSI_LASI700 - tristate "HP LASI SCSI support for 53c700/710" - depends on PARISC && SCSI + tristate "HP Lasi SCSI support for 53c700/710" + depends on GSC && SCSI help - This is a driver for the lasi baseboard in some parisc machines - which is based on the 53c700 chip. Will also support LASI subsystems - based on the 710 chip using 700 emulation mode. - - Unless you know you have a 53c700 or 53c710 based lasi, say N here + This is a driver for the SCSI controller in the Lasi chip found in + many PA-RISC workstations & servers. If you do not know whether you + have a Lasi chip, it is safe to say "Y" here. config 53C700_MEM_MAPPED bool @@ -876,72 +876,15 @@ depends on SCSI_LASI700 default y -config SCSI_NCR53C7xx - tristate "NCR53c7,8xx SCSI support" - depends on SCSI && PCI - ---help--- - This is a driver for the 53c7 and 8xx NCR family of SCSI - controllers, not to be confused with the NCR 5380 controllers. It - is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . Please read - for the available boot time - command line options. - - Note: there is another driver for the 53c8xx family of controllers - ("NCR53C8XX SCSI support" below). If you want to use them both, you - need to say M to both and build them as modules, but only one may be - active at a time. If you have a 53c8xx board, it's better to use the - other driver. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called 53c7,8xx. If you want to compile it as - a module, say M here and read . - -config SCSI_NCR53C7xx_sync - bool "always negotiate synchronous transfers" - depends on SCSI_NCR53C7xx - help - In general, this is good; however, it is a bit dangerous since there - are some broken SCSI devices out there. Take your chances. Safe bet - is N. - -config SCSI_NCR53C7xx_FAST - bool "allow FAST-SCSI [10MHz]" - depends on SCSI_NCR53C7xx - help - This will enable 10MHz FAST-SCSI transfers with your host - adapter. Some systems have problems with that speed, so it's safest - to say N here. - -config SCSI_NCR53C7xx_DISCONNECT - bool "allow DISCONNECT" - depends on SCSI_NCR53C7xx - help - This enables the disconnect/reconnect feature of the NCR SCSI - controller. When you say Y here, a slow SCSI device will not lock - the SCSI bus while processing a request, allowing simultaneous use - of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and - providing much better performance when using slow and fast SCSI - devices at the same time. Some devices, however, do not operate - properly with this option enabled, and will cause your SCSI system - to hang, which might cause a system crash. The safe answer - therefore is to say N. - config SCSI_SYM53C8XX_2 tristate "SYM53C8XX Version 2 SCSI support" depends on PCI && SCSI ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers. - - If your system has problems using this new major version of the - SYM53C8XX driver, you may switch back to driver version 1. + This driver supports the whole NCR53C8XX/SYM53C8XX family of + PCI-SCSI controllers. It also supports the subset of LSI53C10XX + Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS + language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI + controllers; you need to use the Fusion MPT driver for that. Please read for more information. @@ -1216,7 +1159,7 @@ config SCSI_PAS16 tristate "PAS16 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for a SCSI host adapter. It is explained in section 3.10 of the SCSI-HOWTO, available from @@ -1231,7 +1174,7 @@ config SCSI_PCI2000 tristate "PCI2000 support" - depends on SCSI + depends on PCI && SCSI help This is support for the PCI2000I EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1244,7 +1187,7 @@ config SCSI_PCI2220I tristate "PCI2220i support" - depends on SCSI + depends on PCI && SCSI help This is support for the PCI2220i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1257,7 +1200,7 @@ config SCSI_PSI240I tristate "PSI240i support" - depends on SCSI && ISA + depends on ISA && SCSI help This is support for the PSI240i EIDE interface card which acts as a SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1270,7 +1213,7 @@ config SCSI_QLOGIC_FAS tristate "Qlogic FAS SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic FastSCSI! cards as well as any other card based on the FASXX chip @@ -1340,6 +1283,20 @@ The module will be called qla1280. If you want to compile it as a module, say M here and read . +config SCSI_QLOGICPTI + tristate "PTI Qlogic, ISP Driver" + depends on SBUS && SCSI + help + This driver supports SBUS SCSI controllers from PTI or QLogic. These + controllers are known under Solaris as qpti and in the openprom as + PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are + driven by a different driver. + + This support is also available as a module called qlogicpti ( = + code which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . + config SCSI_SEAGATE tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" depends on X86 && ISA && SCSI @@ -1355,10 +1312,10 @@ The module will be called seagate. If you want to compile it as a module, say M here and read . -# definitely looks note 64bit safe: +# definitely looks not 64bit safe: config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" - depends on (EISA || MCA && !X86_64) && SCSI + depends on (EISA || MCA) && SCSI ---help--- This driver for NCR53c710 based SCSI host adapters. @@ -1371,7 +1328,7 @@ config SCSI_SYM53C416 tristate "Symbios 53c416 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for the sym53c416 SCSI host adapter, the SCSI adapter that comes with some HP scanners. This driver requires that @@ -1392,7 +1349,7 @@ config SCSI_DC395x tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support (EXPERIMENTAL)" - depends on EXPERIMENTAL && PCI && SCSI + depends on PCI && SCSI && EXPERIMENTAL ---help--- This driver supports PCI SCSI host adapters based on the ASIC TRM-S1040 chip, e.g Tekram DC395(U/UW/F) and DC315(U) variants. @@ -1446,7 +1403,7 @@ config SCSI_T128 tristate "Trantor T128/T128F/T228 SCSI support" - depends on SCSI && ISA + depends on ISA && SCSI ---help--- This is support for a SCSI host adapter. It is explained in section 3.11 of the SCSI-HOWTO, available from @@ -1463,7 +1420,7 @@ config SCSI_U14_34F tristate "UltraStor 14F/34F support" - depends on SCSI + depends on ISA && SCSI ---help--- This is support for the UltraStor 14F and 34F SCSI-2 host adapters. The source at contains some @@ -1533,7 +1490,7 @@ config SCSI_NSP32 tristate "Workbit NinjaSCSI-32Bi/UDE support" - depends on SCSI + depends on PCI && SCSI help This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI host adapter. Please read the SCSI-HOWTO, available from @@ -1606,7 +1563,7 @@ config JAZZ_ESP bool "MIPS JAZZ FAS216 SCSI support" - depends on MIPS_JAZZ + depends on MIPS_JAZZ && SCSI help This is the driver for the onboard SCSI host adapter of MIPS Magnum 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM @@ -1625,7 +1582,7 @@ config A4000T_SCSI bool "A4000T SCSI support (EXPERIMENTAL)" - depends on AMIGA && EXPERIMENTAL + depends on AMIGA && SCSI && EXPERIMENTAL help Support for the NCR53C710 SCSI controller on the Amiga 4000T. @@ -1695,7 +1652,7 @@ config A4091_SCSI bool "A4091 SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help Support for the NCR53C710 chip on the Amiga 4091 Z3 SCSI2 controller (1993). Very obscure -- the 4091 was part of an Amiga 4000 upgrade @@ -1703,7 +1660,7 @@ config WARPENGINE_SCSI bool "WarpEngine SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help Support for MacroSystem Development's WarpEngine Amiga SCSI-2 controller. Info at @@ -1711,19 +1668,142 @@ config BLZ603EPLUS_SCSI bool "Blizzard PowerUP 603e+ SCSI (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL + depends on ZORRO && SCSI && EXPERIMENTAL help If you have an Amiga 1200 with a Phase5 Blizzard PowerUP 603e+ accelerator, say Y. Otherwise, say N. config OKTAGON_SCSI tristate "BSC Oktagon SCSI support (EXPERIMENTAL)" - depends on ZORRO && EXPERIMENTAL && SCSI + depends on ZORRO && SCSI && EXPERIMENTAL help If you have the BSC Oktagon SCSI disk controller for the Amiga, say Y to this question. If you're in doubt about whether you have one, see the picture at . + +config ATARI_SCSI + tristate "Atari native SCSI support" + depends on ATARI && SCSI + ---help--- + If you have an Atari with built-in NCR5380 SCSI controller (TT, + Falcon, ...) say Y to get it supported. Of course also, if you have + a compatible SCSI controller (e.g. for Medusa). This driver is also + available as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). The module is called + atari_scsi. If you want to compile it as a module, say M here and + read . This driver supports both + styles of NCR integration into the system: the TT style (separate + DMA), and the Falcon style (via ST-DMA, replacing ACSI). It does + NOT support other schemes, like in the Hades (without DMA). + +config ATARI_SCSI_TOSHIBA_DELAY + bool "Long delays for Toshiba CD-ROMs" + depends on ATARI_SCSI + help + This option increases the delay after a SCSI arbitration to + accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to + use a Toshiba CD-ROM drive; otherwise, the option is not needed and + would impact performance a bit, so say N. + +config ATARI_SCSI_RESET_BOOT + bool "Reset SCSI-devices at boottime" + depends on ATARI_SCSI + help + Reset the devices on your Atari whenever it boots. This makes the + boot process fractionally longer but may assist recovery from errors + that leave the devices with SCSI operations partway completed. + +config TT_DMA_EMUL + bool "Hades SCSI DMA emulator" + depends on ATARI_SCSI && HADES + help + This option enables code which emulates the TT SCSI DMA chip on the + Hades. This increases the SCSI transfer rates at least ten times + compared to PIO transfers. + +config MAC_SCSI + bool "Macintosh NCR5380 SCSI" + depends on MAC && SCSI + help + This is the NCR 5380 SCSI controller included on most of the 68030 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + +config SCSI_MAC_ESP + tristate "Macintosh NCR53c9[46] SCSI" + depends on MAC && SCSI + help + This is the NCR 53c9x SCSI controller found on most of the 68040 + based Macintoshes. If you have one of these say Y and read the + SCSI-HOWTO, available from + . + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called mac_esp. If you want to compile it as + a module, say M here and read . + +config MVME147_SCSI + bool "WD33C93 SCSI driver for MVME147" + depends on MVME147 && SCSI + help + Support for the on-board SCSI controller on the Motorola MVME147 + single-board computer. + +config MVME16x_SCSI + bool "NCR53C710 SCSI driver for MVME16x" + depends on MVME16x && SCSI + help + The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +config BVME6000_SCSI + bool "NCR53C710 SCSI driver for BVME6000" + depends on BVME6000 && SCSI + help + The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +config SCSI_NCR53C7xx_FAST + bool "allow FAST-SCSI [10MHz]" + depends on A4000T_SCSI || A4091_SCSI || BLZ603EPLUS_SCSI || WARPENGINE_SCSI || MVME16x_SCSI || BVME6000_SCSI + help + This will enable 10MHz FAST-SCSI transfers with your host + adapter. Some systems have problems with that speed, so it's safest + to say N here. + +config SUN3_SCSI + tristate "Sun3 NCR5380 SCSI" + depends on SUN3 && SCSI + help + This option will enable support for the OBIO (onboard io) NCR5380 + SCSI controller found in the Sun 3/50 and 3/60, as well as for + "Sun3" type VME scsi controllers also based on the NCR5380. + General Linux information on the Sun 3 series (now discontinued) + is at . + +config SUN3X_ESP + bool "Sun3x ESP SCSI" + depends on SUN3X && SCSI + help + The ESP was an on-board SCSI controller used on Sun 3/80 + machines. Say Y here to compile in support for it. + +config SCSI_SUNESP + tristate "Sparc ESP Scsi Driver" + depends on SBUS && SCSI + help + This is the driver for the Sun ESP SCSI host adapter. The ESP + chipset is present in most SPARC SBUS-based computers. + + This support is also available as a module called esp ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . config SCSI_PC980155 tristate "NEC PC-9801-55 SCSI support" diff -Nru a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c --- a/drivers/scsi/NCR53c406a.c Sat Apr 26 07:28:14 2003 +++ b/drivers/scsi/NCR53c406a.c Sat Jun 14 08:39:19 2003 @@ -170,7 +170,6 @@ /* Static function prototypes */ static void NCR53c406a_intr(int, void *, struct pt_regs *); static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *); -static void internal_done(Scsi_Cmnd *); static void wait_intr(void); static void chip_init(void); static void calc_port_addr(void); @@ -205,8 +204,6 @@ #endif static Scsi_Cmnd *current_SC; -static volatile int internal_done_flag; -static volatile int internal_done_errcode; static char info_msg[256]; /* ================================================================= */ @@ -544,10 +541,13 @@ } else if (irq_level == 0) { tpnt->can_queue = 0; DEB(printk("NCR53c406a: No interrupts detected\n")); + printk("NCR53c406a driver no longer supports polling interface\n"); + printk("Please email linux-scsi@vger.kernel.org\n"); + #if USE_DMA printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); - goto err_free_scsi; #endif /* USE_DMA */ + goto err_free_scsi; } else { DEB(printk("NCR53c406a: Shouldn't get here!\n")); goto err_free_scsi; @@ -590,6 +590,21 @@ return 0; } +static int NCR53c406a_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); +#ifdef USE_DMA + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); +#endif + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + + scsi_unregister(shost); + return 0; +} + /* called from init/main.c */ static void __init NCR53c406a_setup(char *str, int *ints) { @@ -649,13 +664,6 @@ return (info_msg); } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - internal_done_errcode = SCpnt->result; - ++internal_done_flag; -} - - static void wait_intr(void) { unsigned long i = jiffies + WATCHDOG; @@ -709,21 +717,6 @@ return 0; } -static int NCR53c406a_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("NCR53c406a_command called\n")); - NCR53c406a_queue(SCpnt, internal_done); - if (irq_level) - while (!internal_done_flag) - cpu_relax(); - else /* interrupts not supported */ - while (!internal_done_flag) - wait_intr(); - - internal_done_flag = 0; - return internal_done_errcode; -} - static int NCR53c406a_abort(Scsi_Cmnd * SCpnt) { DEB(printk("NCR53c406a_abort called\n")); @@ -1074,8 +1067,8 @@ .proc_name = "NCR53c406a" /* proc_name */, .name = "NCR53c406a" /* name */, .detect = NCR53c406a_detect /* detect */, + .release = NCR53c406a_release, .info = NCR53c406a_info /* info */, - .command = NCR53c406a_command /* command */, .queuecommand = NCR53c406a_queue /* queuecommand */, .eh_abort_handler = NCR53c406a_abort /* abort */, .eh_bus_reset_handler = NCR53c406a_bus_reset /* reset */, diff -Nru a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c --- a/drivers/scsi/NCR_D700.c Fri May 30 10:45:36 2003 +++ b/drivers/scsi/NCR_D700.c Tue Jun 17 13:27:44 2003 @@ -197,6 +197,8 @@ hostdata->differential = (((1<clock = NCR_D700_CLOCK_MHZ; + NCR_700_set_io_mapped(hostdata); + /* and register the siop */ host = NCR_700_detect(&NCR_D700_driver_template, hostdata); if (!host) { @@ -223,7 +225,7 @@ return 0; irq_failed: - scsi_unregister(host); + scsi_host_put(host); NCR_700_release(host); detect_failed: release_region(host->base, 64); diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c Sat Jun 14 16:16:14 2003 +++ b/drivers/scsi/aacraid/aachba.c Thu Jun 19 17:06:21 2003 @@ -1518,7 +1518,7 @@ dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = cpu_to_le32(0); - psg->sg[0].addr = cpu_to_le32(NULL); + psg->sg[0].addr = cpu_to_le32(0); psg->sg[0].count = cpu_to_le32(0); if (scsicmd->use_sg) { struct scatterlist *sg; @@ -1558,7 +1558,7 @@ psg->count = cpu_to_le32(1); psg->sg[0].addr = cpu_to_le32(addr); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)addr; + scsicmd->SCp.ptr = (char *)(ulong)addr; byte_count = scsicmd->request_bufflen; } return byte_count; @@ -1574,8 +1574,8 @@ dev = (struct aac_dev *)scsicmd->device->host->hostdata; // Get rid of old data psg->count = cpu_to_le32(0); - psg->sg[0].addr[0] = cpu_to_le32(NULL); - psg->sg[0].addr[1] = cpu_to_le32(NULL); + psg->sg[0].addr[0] = cpu_to_le32(0); + psg->sg[0].addr[1] = cpu_to_le32(0); psg->sg[0].count = cpu_to_le32(0); if (scsicmd->use_sg) { struct scatterlist *sg; @@ -1619,7 +1619,7 @@ psg->sg[0].addr[1] = (u32)(le_addr>>32); psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.ptr = (char *)addr; + scsicmd->SCp.ptr = (char *)(ulong)addr; byte_count = scsicmd->request_bufflen; } return byte_count; diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c --- a/drivers/scsi/aha152x.c Mon May 12 07:26:11 2003 +++ b/drivers/scsi/aha152x.c Sun Jun 8 12:18:41 2003 @@ -1515,16 +1515,6 @@ up(SCSEM(SCpnt)); } -static int aha152x_command(Scsi_Cmnd * SCpnt) -{ - DECLARE_MUTEX_LOCKED(sem); - - aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done); - down(&sem); - - return SUCCESS; -} - /* * Abort a command * @@ -3876,7 +3866,6 @@ .proc_name = "aha152x", .proc_info = aha152x_proc_info, .detect = aha152x_detect, - .command = aha152x_command, .queuecommand = aha152x_queue, .eh_abort_handler = aha152x_abort, .eh_device_reset_handler = aha152x_device_reset, diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c --- a/drivers/scsi/aha1542.c Thu May 8 11:24:14 2003 +++ b/drivers/scsi/aha1542.c Sun Jun 8 12:18:41 2003 @@ -774,23 +774,6 @@ return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int aha1542_command(Scsi_Cmnd * SCpnt) -{ - DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n")); - - aha1542_queuecommand(SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - /* Initialize mailboxes */ static void setup_mailboxes(int bse, struct Scsi_Host *shpnt) { @@ -1325,6 +1308,18 @@ return count; } +static int aha1542_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static int aha1542_restart(struct Scsi_Host *shost) { int i; @@ -1817,7 +1812,7 @@ .proc_name = "aha1542", .name = "Adaptec 1542", .detect = aha1542_detect, - .command = aha1542_command, + .release = aha1542_release, .queuecommand = aha1542_queuecommand, .eh_abort_handler = aha1542_abort, .eh_device_reset_handler= aha1542_dev_reset, diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c --- a/drivers/scsi/aha1740.c Mon May 12 07:26:11 2003 +++ b/drivers/scsi/aha1740.c Tue Jun 17 15:36:55 2003 @@ -102,6 +102,7 @@ if (len > length) len = length; return len; +} static int aha1740_makecode(unchar *sense, unchar *status) @@ -476,23 +477,6 @@ return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int aha1740_command(Scsi_Cmnd * SCpnt) -{ - aha1740_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - /* Query the board for its irq_level. Nothing else matters in enhanced mode on an EISA bus. */ @@ -567,6 +551,16 @@ return count; } +static int aha1740_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static int aha1740_biosparam(struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int* ip) { @@ -596,7 +590,7 @@ .proc_info = aha1740_proc_info, .name = "Adaptec 174x (EISA)", .detect = aha1740_detect, - .command = aha1740_command, + .release = aha1740_release, .queuecommand = aha1740_queuecommand, .bios_param = aha1740_biosparam, .can_queue = AHA1740_ECBS, diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c --- a/drivers/scsi/aic7xxx/aic79xx_osm.c Fri May 23 10:58:23 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c Mon Jun 2 17:42:21 2003 @@ -2098,7 +2098,7 @@ u_long target; template->name = ahd->description; - host = scsi_register(template, sizeof(struct ahd_softc *)); + host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); if (host == NULL) return (ENOMEM); @@ -2308,7 +2308,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); #endif - scsi_unregister(ahd->platform_data->host); + scsi_host_put(ahd->platform_data->host); } /* destroy all of the device and target objects */ diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c Wed May 14 15:00:40 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c Thu Jun 19 16:46:06 2003 @@ -52,9 +52,11 @@ const struct pci_device_id *ent); static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, u_long *base2); +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, uint8_t **maddr); +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); @@ -271,6 +273,7 @@ return (0); } +#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, @@ -318,6 +321,7 @@ error = ENOMEM; return (error); } +#endif int ahd_pci_map_registers(struct ahd_softc *ahd) diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c Fri May 23 12:29:22 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Jun 2 17:42:21 2003 @@ -1725,7 +1725,7 @@ u_int targ_offset; template->name = ahc->description; - host = scsi_register(template, sizeof(struct ahc_softc *)); + host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); if (host == NULL) return (ENOMEM); @@ -1978,7 +1978,7 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); #endif - scsi_unregister(ahc->platform_data->host); + scsi_host_put(ahc->platform_data->host); } /* destroy all of the device and target objects */ diff -Nru a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c --- a/drivers/scsi/amiga7xx.c Sun Feb 9 07:21:12 2003 +++ b/drivers/scsi/amiga7xx.c Mon Jun 2 17:27:44 2003 @@ -134,9 +134,22 @@ return num; } +static int amiga7xx_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "Amiga NCR53c710 SCSI", .detect = amiga7xx_detect, + .release = amiga7xx_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff -Nru a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c --- a/drivers/scsi/arm/acornscsi.c Mon May 19 19:40:43 2003 +++ b/drivers/scsi/arm/acornscsi.c Mon Jun 2 17:42:21 2003 @@ -2993,7 +2993,7 @@ AS_Host *ashost; int ret = -ENOMEM; - host = scsi_register(&acornscsi_template, sizeof(AS_Host)); + host = scsi_host_alloc(&acornscsi_template, sizeof(AS_Host)); if (!host) goto out; @@ -3060,7 +3060,7 @@ err_2: release_region(host->io_port + 0x800, 2); err_1: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -3089,6 +3089,7 @@ msgqueue_free(&ashost->scsi.msgs); queue_free(&ashost->queues.disconnected); queue_free(&ashost->queues.issue); + scsi_host_put(host); } static const struct ecard_id acornscsi_cids[] = { diff -Nru a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c --- a/drivers/scsi/arm/arxescsi.c Mon May 19 19:40:44 2003 +++ b/drivers/scsi/arm/arxescsi.c Sun Jun 8 12:18:41 2003 @@ -264,7 +264,6 @@ .proc_info = arxescsi_proc_info, .name = "ARXE SCSI card", .info = arxescsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c --- a/drivers/scsi/arm/cumana_1.c Mon May 19 19:40:44 2003 +++ b/drivers/scsi/arm/cumana_1.c Mon Jun 2 17:42:21 2003 @@ -262,7 +262,7 @@ struct Scsi_Host *host; int ret = -ENOMEM; - host = scsi_register(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); if (!host) goto out; @@ -304,7 +304,7 @@ out_release: release_region(host->io_port, host->n_io_port); out_free: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -318,7 +318,7 @@ scsi_remove_host(host); free_irq(host->irq, host); release_region(host->io_port, host->n_io_port); - scsi_unregister(host); + scsi_host_put(host); } static const struct ecard_id cumanascsi1_cids[] = { diff -Nru a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c --- a/drivers/scsi/arm/cumana_2.c Mon May 19 19:40:45 2003 +++ b/drivers/scsi/arm/cumana_2.c Sun Jun 8 12:18:41 2003 @@ -386,7 +386,6 @@ .proc_info = cumanascsi_2_proc_info, .name = "Cumana SCSI II", .info = cumanascsi_2_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c --- a/drivers/scsi/arm/ecoscsi.c Tue May 27 07:52:55 2003 +++ b/drivers/scsi/arm/ecoscsi.c Mon Jun 2 17:42:21 2003 @@ -177,7 +177,7 @@ static int __init ecoscsi_init(void) { - host = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata)); if (!host) return 0; @@ -211,7 +211,7 @@ release_reg: release_region(host->io_port, host->n_io_port); unregister_scsi: - scsi_unregister(host); + scsi_host_put(host); return -ENODEV; } @@ -224,7 +224,7 @@ if (shpnt->io_port) release_region(shpnt->io_port, shpnt->n_io_port); - scsi_unregister(host); + scsi_host_put(host); return 0; } diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c --- a/drivers/scsi/arm/eesox.c Mon May 19 19:40:46 2003 +++ b/drivers/scsi/arm/eesox.c Sun Jun 8 12:18:41 2003 @@ -492,7 +492,6 @@ .proc_info = eesoxscsi_proc_info, .name = "EESOX SCSI", .info = eesoxscsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff -Nru a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c --- a/drivers/scsi/arm/fas216.c Sat May 17 06:52:33 2003 +++ b/drivers/scsi/arm/fas216.c Sun Jun 8 12:18:41 2003 @@ -225,8 +225,7 @@ printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", info->dma.transfer_type, info->dma.setup, info->dma.pseudo, info->dma.stop); - printk(" internal_done=%X magic_end=%lX }\n", - info->internal_done, info->magic_end); + printk(" magic_end=%lX }\n", info->magic_end); } #ifdef CHECK_STRUCTURE @@ -2253,74 +2252,6 @@ return result; } -/** - * fas216_internal_done - trigger restart of a waiting thread in fas216_command - * @SCpnt: Command to wake - * - * Trigger restart of a waiting thread in fas216_command - */ -static void fas216_internal_done(Scsi_Cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - info->internal_done = 1; -} - -/** - * fas216_command - queue a command for adapter to process. - * @SCpnt: Command to queue - * - * Queue a command for adapter to process. - * Returns: scsi result code. - * Notes: io_request_lock is held, interrupts are disabled. - */ -int fas216_command(Scsi_Cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - /* - * We should only be using this if we don't have an interrupt. - * Provide some "incentive" to use the queueing code. - */ - if (info->scsi.irq != NO_IRQ) - BUG(); - - info->internal_done = 0; - fas216_queue_command(SCpnt, fas216_internal_done); - - /* - * This wastes time, since we can't return until the command is - * complete. We can't sleep either since we may get re-entered! - * However, we must re-enable interrupts, or else we'll be - * waiting forever. - */ - spin_unlock_irq(info->host->host_lock); - - while (!info->internal_done) { - /* - * If we don't have an IRQ, then we must poll the card for - * it's interrupt, and use that to call this driver's - * interrupt routine. That way, we keep the command - * progressing. Maybe we can add some inteligence here - * and go to sleep if we know that the device is going - * to be some time (eg, disconnected). - */ - if (fas216_readb(info, REG_STAT) & STAT_INT) { - spin_lock_irq(info->host->host_lock); - fas216_intr(info); - spin_unlock_irq(info->host->host_lock); - } - } - - spin_lock_irq(info->host->host_lock); - - return SCpnt->result; -} - /* * Error handler timeout function. Indicate that we timed out, * and wake up any error handler process so it can continue. @@ -2942,6 +2873,7 @@ scsi_remove_host(host); fas216_writeb(info, REG_CMD, CMD_RESETCHIP); + scsi_host_put(host); } /** diff -Nru a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h --- a/drivers/scsi/arm/fas216.h Thu May 15 17:33:17 2003 +++ b/drivers/scsi/arm/fas216.h Sun Jun 8 12:18:41 2003 @@ -310,8 +310,6 @@ } dma; /* miscellaneous */ - int internal_done; /* flag to indicate request done */ - unsigned long magic_end; } FAS216_Info; @@ -336,13 +334,6 @@ * Returns : 0 - success, else error */ extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - -/* Function: int fas216_command (Scsi_Cmnd *SCpnt) - * Purpose : queue a command for adapter to process. - * Params : SCpnt - Command to queue - * Returns : scsi result code - */ -extern int fas216_command (Scsi_Cmnd *); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c --- a/drivers/scsi/arm/oak.c Mon May 19 19:40:46 2003 +++ b/drivers/scsi/arm/oak.c Mon Jun 2 17:42:21 2003 @@ -135,7 +135,7 @@ struct Scsi_Host *host; int ret = -ENOMEM; - host = scsi_register(&oakscsi_template, sizeof(struct NCR5380_hostdata)); + host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata)); if (!host) goto out; @@ -163,7 +163,7 @@ release_region(host->io_port, host->n_io_port); unreg: - scsi_unregister(host); + scsi_host_put(host); out: return ret; } @@ -176,7 +176,7 @@ scsi_remove_host(host); release_region(host->io_port, host->n_io_port); - scsi_unregister(host); + scsi_host_put(host); } static const struct ecard_id oakscsi_cids[] = { diff -Nru a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c --- a/drivers/scsi/arm/powertec.c Mon May 19 19:40:47 2003 +++ b/drivers/scsi/arm/powertec.c Sun Jun 8 12:18:41 2003 @@ -296,7 +296,6 @@ .proc_info = powertecscsi_proc_info, .name = "PowerTec SCSI", .info = powertecscsi_info, - .command = fas216_command, .queuecommand = fas216_queue_command, .eh_host_reset_handler = fas216_eh_host_reset, .eh_bus_reset_handler = fas216_eh_bus_reset, diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c Mon Jun 9 16:02:25 2003 +++ b/drivers/scsi/atp870u.c Wed Jun 11 20:06:30 2003 @@ -829,25 +829,6 @@ } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int atp870u_command(Scsi_Cmnd * SCpnt) -{ - - atp870u_queuecommand(SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) { unsigned int tmport; @@ -2728,7 +2709,6 @@ .detect = atp870u_detect, .release = atp870u_release, .info = atp870u_info, - .command = atp870u_command, .queuecommand = atp870u_queuecommand, .eh_abort_handler = atp870u_abort, .bios_param = atp870u_biosparam, diff -Nru a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h --- a/drivers/scsi/atp870u.h Mon May 12 07:26:11 2003 +++ b/drivers/scsi/atp870u.h Sun Jun 8 12:18:41 2003 @@ -18,7 +18,6 @@ #define MAX_SENSE 14 static int atp870u_detect(Scsi_Host_Template *); -static int atp870u_command(Scsi_Cmnd *); static int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int atp870u_abort(Scsi_Cmnd *); static int atp870u_biosparam(struct scsi_device *, struct block_device *, diff -Nru a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c --- a/drivers/scsi/blz1230.c Wed Feb 5 09:05:18 2003 +++ b/drivers/scsi/blz1230.c Sun Jun 8 12:18:41 2003 @@ -334,7 +334,6 @@ .name = "Blizzard1230 SCSI IV", .detect = blz1230_esp_detect, .release = blz1230_esp_release, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c --- a/drivers/scsi/bvme6000.c Wed Nov 20 03:36:29 2002 +++ b/drivers/scsi/bvme6000.c Mon Jun 2 17:27:44 2003 @@ -51,9 +51,22 @@ return 1; } +static int mvme6000_scsi_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "BVME6000 NCR53c710 SCSI", .detect = bvme6000_scsi_detect, + .release = bvme6000_scsi_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c Fri Jan 3 10:58:49 2003 +++ b/drivers/scsi/constants.c Sun Jun 1 14:27:22 2003 @@ -1004,16 +1004,14 @@ #endif } -void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) +void print_sense(const char *devclass, struct scsi_cmnd *cmd) { - print_sense_internal(devclass, SCpnt->sense_buffer, - SCpnt->request); + print_sense_internal(devclass, cmd->sense_buffer, cmd->request); } -void print_req_sense(const char * devclass, Scsi_Request * SRpnt) +void print_req_sense(const char *devclass, struct scsi_request *sreq) { - print_sense_internal(devclass, SRpnt->sr_sense_buffer, - SRpnt->sr_request); + print_sense_internal(devclass, sreq->sr_sense_buffer, sreq->sr_request); } #if (CONSTANTS & CONST_MSG) @@ -1116,13 +1114,13 @@ return len; } -void print_Scsi_Cmnd (Scsi_Cmnd *cmd) { +void print_Scsi_Cmnd(struct scsi_cmnd *cmd) { printk("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun); printk(" command = "); - print_command (cmd->cmnd); + print_command(cmd->cmnd); } #if (CONSTANTS & CONST_HOST) diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c Wed May 28 03:05:43 2003 +++ b/drivers/scsi/dc395x.c Fri Jun 6 04:28:47 2003 @@ -5726,9 +5726,9 @@ /* *$$$$$$$$$$$ MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$ */ - host = scsi_register(host_template, sizeof(struct AdapterCtlBlk)); + host = scsi_host_alloc(host_template, sizeof(struct AdapterCtlBlk)); if (!host) { - dprintkl(KERN_INFO, "pSH scsi_register ERROR\n"); + dprintkl(KERN_INFO, "pSH scsi_host_alloc ERROR\n"); return 0; } DC395x_print_eeprom_settings(index); @@ -5736,7 +5736,7 @@ pACB = (struct AdapterCtlBlk *) host->hostdata; if (DC395x_initACB(host, io_port, irq, index)) { - scsi_unregister(host); + scsi_host_put(host); return 0; } DC395x_print_config(pACB); @@ -5755,7 +5755,7 @@ } else { dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n"); - scsi_unregister(host); + scsi_host_put(host); host = NULL; } return host; diff -Nru a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c --- a/drivers/scsi/dec_esp.c Sun Dec 22 02:33:54 2002 +++ b/drivers/scsi/dec_esp.c Sun Jun 8 12:18:41 2003 @@ -109,13 +109,23 @@ int dec_esp_detect(Scsi_Host_Template * tpnt); +static int dec_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .proc_name = "esp", .proc_info = &esp_proc_info, .name = "NCR53C94", .detect = dec_esp_detect, + .release = dec_esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Sat Jun 14 16:16:14 2003 +++ b/drivers/scsi/dpt_i2o.c Mon Jun 16 17:22:17 2003 @@ -1949,26 +1949,6 @@ case I2ORESCANCMD: adpt_rescan(pHba); break; - case DPT_TARGET_BUSY & 0xFFFF: - case DPT_TARGET_BUSY: - { - TARGET_BUSY_T busy; - struct adpt_device* d; - - if (copy_from_user((void*)&busy, (void*)arg, sizeof(TARGET_BUSY_T))) { - return -EFAULT; - } - - d = adpt_find_device(pHba, busy.channel, busy.id, busy.lun); - if(d == NULL){ - return -ENODEV; - } - busy.isBusy = ((d->pScsi_dev) && (0 != d->pScsi_dev->access_count)) ? 1 : 0; - if (copy_to_user ((char*)arg, &busy, sizeof(busy))) { - return -EFAULT; - } - break; - } default: return -EINVAL; } @@ -2492,10 +2472,6 @@ printk(KERN_WARNING"%s: Device (%d,%d,%d) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun); if (pDev->pScsi_dev) { pDev->pScsi_dev->online = FALSE; - if (pDev->pScsi_dev->access_count) { - // A drive that was mounted is no longer there... bad! - printk(KERN_WARNING"%s:Mounted drive taken offline\n",pHba->name); - } } } } diff -Nru a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c --- a/drivers/scsi/dtc.c Sun May 4 02:56:43 2003 +++ b/drivers/scsi/dtc.c Mon Jun 2 17:27:45 2003 @@ -447,9 +447,20 @@ #include "NCR5380.c" +static int dtc_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "DTC 3180/3280 ", .detect = dtc_detect, + .release = dtc_release, .queuecommand = dtc_queue_command, .eh_abort_handler = dtc_abort, .eh_bus_reset_handler = dtc_bus_reset, diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Mon Jun 9 16:03:59 2003 +++ b/drivers/scsi/eata.c Tue Jun 3 10:54:22 2003 @@ -1,6 +1,36 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 + * + Update for new IRQ API. + * + Use "goto" when appropriate. + * + Drop eata.h. + * + Update for new module_param API. + * + Module parameters can now be specified only in the + * same format as the kernel boot options. + * + * boot option old module param + * ----------- ------------------ + * addr,... io_port=addr,... + * lc:[y|n] linked_comm=[1|0] + * mq:xx max_queue_depth=xx + * tm:[0|1|2] tag_mode=[0|1|2] + * et:[y|n] ext_tran=[1|0] + * rs:[y|n] rev_scan=[1|0] + * ip:[y|n] isa_probe=[1|0] + * ep:[y|n] eisa_probe=[1|0] + * pp:[y|n] pci_probe=[1|0] + * + * A valid example using the new parameter format is: + * modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n" + * + * which is equivalent to the old format: + * modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \ + * max_queue_depth=4 eisa_probe=0 + * + * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 + * + Release irq before calling scsi_register. + * * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 * + Release driver_lock before calling scsi_register. * @@ -279,7 +309,7 @@ * This driver is based on the CAM (Common Access Method Committee) * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. * - * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -447,31 +477,8 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#include - -#define MAX_INT_PARAM 10 - -#if defined(MODULE) -#include - -MODULE_PARM(boot_options, "s"); -MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); -MODULE_PARM(linked_comm, "i"); -MODULE_PARM(link_statistics, "i"); -MODULE_PARM(max_queue_depth, "i"); -MODULE_PARM(tag_mode, "i"); -MODULE_PARM(ext_tran, "i"); -MODULE_PARM(rev_scan, "i"); -MODULE_PARM(isa_probe, "i"); -MODULE_PARM(eisa_probe, "i"); -MODULE_PARM(pci_probe, "i"); -MODULE_AUTHOR("Dario Ballabio"); - -#endif - #include #include -#include #include #include #include @@ -491,8 +498,31 @@ #include "hosts.h" #include #include -#include "eata.h" +static int eata2x_detect(Scsi_Host_Template *); +static int eata2x_release(struct Scsi_Host *); +static int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int eata2x_eh_abort(Scsi_Cmnd *); +static int eata2x_eh_host_reset(Scsi_Cmnd *); +static int eata2x_bios_param(struct scsi_device *, struct block_device *, + sector_t, int *); +static int eata2x_slave_configure(Scsi_Device *); + +static Scsi_Host_Template driver_template = { + .name = "EATA/DMA 2.0x rev. 8.10.00 ", + .detect = eata2x_detect, + .release = eata2x_release, + .queuecommand = eata2x_queuecommand, + .eh_abort_handler = eata2x_eh_abort, + .eh_device_reset_handler = NULL, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = eata2x_eh_host_reset, + .bios_param = eata2x_bios_param, + .slave_configure = eata2x_slave_configure, + .this_id = 7, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING + }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" #endif @@ -818,7 +848,6 @@ static int link_statistics; static int ext_tran = FALSE; static int rev_scan = TRUE; -static char *boot_options; #if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) static int tag_mode = TAG_SIMPLE; @@ -856,6 +885,23 @@ static int pci_probe = FALSE; #endif +#define MAX_INT_PARAM 10 +#define MAX_BOOT_OPTIONS_SIZE 256 +static char boot_options[MAX_BOOT_OPTIONS_SIZE]; + +#if defined(MODULE) +#include +#include + +module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); +MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." \ +" Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); +MODULE_AUTHOR("Dario Ballabio"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EATA/DMA SCSI Driver"); + +#endif + static int eata2x_slave_configure(Scsi_Device *dev) { int j, tqd, utqd; char *tag_suffix, *link_suffix; @@ -1011,19 +1057,20 @@ sprintf(name, "%s%d", driver_name, j); - if(!request_region(port_base, REGION_SIZE, driver_name)) { + if (!request_region(port_base, REGION_SIZE, driver_name)) { #if defined(DEBUG_DETECT) printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); #endif - return FALSE; + goto fail; } + spin_lock_irq(&driver_lock); + if (do_dma(port_base, 0, READ_CONFIG_PIO)) { #if defined(DEBUG_DETECT) printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } /* Read the info structure */ @@ -1031,8 +1078,7 @@ #if defined(DEBUG_DETECT) printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } info.data_len = DEV2H(info.data_len); @@ -1048,15 +1094,13 @@ #if defined(DEBUG_DETECT) printk("%s: signature 0x%04x discarded.\n", name, info.sign); #endif - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (info.data_len < EATA_2_0A_SIZE) { printk("%s: config structure size (%d bytes) too short, detaching.\n", name, info.data_len); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } else if (info.data_len == EATA_2_0A_SIZE) protocol_rev = 'A'; @@ -1097,8 +1141,7 @@ if (!info.haaval || info.ata) { printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", name, port_base, bus_type, info.haaval, info.ata); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (info.drqvld) { @@ -1145,16 +1188,13 @@ SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), driver_name, (void *) &sha[j])) { printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (subversion == ISA && request_dma(dma_channel, driver_name)) { printk("%s: unable to allocate DMA channel %u, detaching.\n", name, dma_channel); - free_irq(irq, &sha[j]); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freeirq; } #if defined(FORCE_CONFIG) @@ -1166,8 +1206,7 @@ if (!cf) { printk("%s: config, pci_alloc_consistent failed, detaching.\n", name); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } /* Set board configuration */ @@ -1178,8 +1217,7 @@ if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { printk("%s: busy timeout sending configuration, detaching.\n", name); pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } } @@ -1191,13 +1229,7 @@ if (sh[j] == NULL) { printk("%s: unable to register host, detaching.\n", name); - - free_irq(irq, &sha[j]); - - if (subversion == ISA) free_dma(dma_channel); - - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } sh[j]->io_port = port_base; @@ -1268,6 +1300,8 @@ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); else sprintf(dma_name, "DMA %u", dma_channel); + spin_unlock_irq(&driver_lock); + for (i = 0; i < sh[j]->can_queue; i++) HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); @@ -1277,15 +1311,13 @@ sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - eata2x_release(sh[j]); - return FALSE; + goto release; } if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, sizeof(struct mssp), &HD(j)->sp_dma_addr))) { printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); - eata2x_release(sh[j]); - return FALSE; + goto release; } if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) @@ -1297,7 +1329,7 @@ tag_mode = TAG_ORDERED; if (j == 0) { - printk("EATA/DMA 2.0x: Copyright (C) 1994-2002 Dario Ballabio.\n"); + printk("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); printk("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "\ "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), @@ -1342,6 +1374,20 @@ } return TRUE; + +freedma: + if (subversion == ISA) free_dma(dma_channel); +freeirq: + free_irq(irq, &sha[j]); +freelock: + spin_unlock_irq(&driver_lock); + release_region(port_base, REGION_SIZE); +fail: + return FALSE; + +release: + eata2x_release(sh[j]); + return FALSE; } static void internal_setup(char *str, int *ints) { @@ -1440,11 +1486,9 @@ static int eata2x_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; - spin_lock_irq(&driver_lock); - tpnt->proc_name = "eata2x"; - if(boot_options) option_setup(boot_options); + if(strlen(boot_options)) option_setup(boot_options); #if defined(MODULE) /* io_port could have been modified when loading as a module */ @@ -1478,7 +1522,6 @@ } num_boards = j; - spin_unlock_irq(&driver_lock); return j; } @@ -2091,7 +2134,7 @@ } -static void ihdlr(int irq, unsigned int j) { +static irqreturn_t ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg; struct mssp *spp; @@ -2101,7 +2144,7 @@ panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq); /* Check if this board need to be serviced */ - if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) return; + if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) goto none; HD(j)->iocount++; @@ -2113,7 +2156,7 @@ reg = inb(sh[j]->io_port + REG_STATUS); printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); - return; + goto none; } spp = &HD(j)->sp; @@ -2148,7 +2191,7 @@ printk("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", BN(j), spp->cpp_index, irq, reg, HD(j)->iocount); if (spp->eoc == FALSE || spp->cpp_index < 0 - || spp->cpp_index >= sh[j]->can_queue) return; + || spp->cpp_index >= sh[j]->can_queue) goto handled; /* Find the mailbox to be serviced on this board */ i = spp->cpp_index; @@ -2156,23 +2199,23 @@ cpp = &(HD(j)->cp[i]); #if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; #endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; - return; + goto handled; } else if (HD(j)->cp_stat[i] == LOCKED) { HD(j)->cp_stat[i] = FREE; printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == FREE) { printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == IN_RESET) printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); @@ -2319,22 +2362,25 @@ if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, HD(j)->iocount); - return; +handled: + return IRQ_HANDLED; +none: + return IRQ_NONE; } static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) { + struct pt_regs *regs) { unsigned int j; unsigned long spin_flags; + irqreturn_t ret; /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; + if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ihdlr(irq, j); + ret = ihdlr(irq, j); spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return IRQ_HANDLED; + return ret; } static int eata2x_release(struct Scsi_Host *shpnt) { @@ -2365,22 +2411,8 @@ return FALSE; } -static Scsi_Host_Template driver_template = { - .name = "EATA/DMA 2.0x rev. " EATA_VERSION " ", - .detect = eata2x_detect, - .release = eata2x_release, - .queuecommand = eata2x_queuecommand, - .eh_abort_handler = eata2x_eh_abort, - .eh_host_reset_handler = eata2x_eh_host_reset, - .bios_param = eata2x_bios_param, - .slave_configure = eata2x_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; #include "scsi_module.c" #ifndef MODULE __setup("eata=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h --- a/drivers/scsi/eata.h Sun May 4 02:56:43 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,15 +0,0 @@ -/* - * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters. - */ - -static int eata2x_detect(Scsi_Host_Template *); -static int eata2x_release(struct Scsi_Host *); -static int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int eata2x_eh_abort(Scsi_Cmnd *); -static int eata2x_eh_host_reset(Scsi_Cmnd *); -static int eata2x_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int eata2x_slave_configure(Scsi_Device *); - -#define EATA_VERSION "8.03.00" - diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c Mon May 26 18:54:35 2003 +++ b/drivers/scsi/esp.c Wed Jun 18 16:15:58 2003 @@ -1871,15 +1871,6 @@ return 0; } -/* Only queuing supported in this ESP driver. */ -static int esp_command(Scsi_Cmnd *SCpnt) -{ - struct esp *esp = (struct esp *) SCpnt->device->host->hostdata; - - ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id)); - return -1; -} - /* Dump driver state. */ static void esp_dump_cmd(Scsi_Cmnd *SCptr) { @@ -4384,7 +4375,6 @@ SDptr->hostdata = NULL; } - static Scsi_Host_Template driver_template = { .proc_name = "esp", .proc_info = esp_proc_info, @@ -4394,7 +4384,6 @@ .slave_destroy = esp_slave_destroy, .release = esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c --- a/drivers/scsi/fd_mcs.c Mon May 12 07:26:12 2003 +++ b/drivers/scsi/fd_mcs.c Sun Jun 8 12:18:41 2003 @@ -1186,24 +1186,6 @@ return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) -{ - /* flag it done */ - SCpnt->host_scribble = (unsigned char *) 1; -} - -int fd_mcs_command(Scsi_Cmnd * SCpnt) -{ - fd_mcs_queue(SCpnt, internal_done); - /* host_scribble is used for status here */ - SCpnt->host_scribble = NULL; - while (!SCpnt->host_scribble) { - cpu_relax(); - barrier(); - } - return SCpnt->result; -} - #if DEBUG_ABORT || DEBUG_RESET static void fd_mcs_print_info(Scsi_Cmnd * SCpnt) { @@ -1431,7 +1413,6 @@ .detect = fd_mcs_detect, .release = fd_mcs_release, .info = fd_mcs_info, - .command = fd_mcs_command, .queuecommand = fd_mcs_queue, .eh_abort_handler = fd_mcs_abort, .eh_bus_reset_handler = fd_mcs_bus_reset, diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c Mon May 12 07:26:12 2003 +++ b/drivers/scsi/fdomain.c Sun Jun 8 12:18:41 2003 @@ -255,11 +255,6 @@ be increased by changing this value to values which are close to 2. Please let me know if you try any different values. - DO_DETECT: This activates some old scan code which was needed before the - high level drivers got fixed. If you are having trouble with the driver, - turning this on should not hurt, and might help. Please let me know if - this is the case, since this code will be removed from future drivers. - RESELECTION: This is no longer an option, since I gave up trying to implement it in version 4.x of this driver. It did not improve performance at all and made the driver unstable (because I never found one @@ -303,7 +298,6 @@ #define DEBUG 0 /* Enable debugging output */ #define ENABLE_PARITY 1 /* Enable SCSI Parity */ #define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ -#define DO_DETECT 0 /* Do device detection here (see scsi.c) */ /* END OF USER DEFINABLE OPTIONS */ @@ -863,17 +857,6 @@ int retcode; struct Scsi_Host *shpnt; struct pci_dev *pdev = NULL; -#if DO_DETECT - int i = 0; - int j = 0; - const int buflen = 255; - Scsi_Cmnd SCinit; - unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 }; - unsigned char do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 }; - unsigned char do_read_capacity[] = { READ_CAPACITY, - 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - unsigned char buf[buflen]; -#endif if (setup_called) { #if DEBUG_DETECT @@ -984,59 +967,6 @@ /* Log I/O ports with kernel */ request_region( port_base, 0x10, "fdomain" ); -#if DO_DETECT - - /* These routines are here because of the way the SCSI bus behaves after - a reset. This appropriate behavior was not handled correctly by the - higher level SCSI routines when I first wrote this driver. Now, - however, correct scan routines are part of scsi.c and these routines - are no longer needed. However, this code is still good for - debugging. */ - - SCinit.request_buffer = SCinit.buffer = buf; - SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; - SCinit.use_sg = 0; - SCinit.lun = 0; - - printk( "scsi: detection routine scanning for devices:\n" ); - for (i = 0; i < 8; i++) { - SCinit.target = i; - if (i == tpnt->this_id) /* Skip host adapter */ - continue; - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - printk( " SCSI ID %d: ", i ); - for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) - printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); - memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity)); - retcode = fdomain_16x0_command(&SCinit); - if (!retcode) { - unsigned long blocks, size, capacity; - - blocks = (buf[0] << 24) | (buf[1] << 16) - | (buf[2] << 8) | buf[3]; - size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; - capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; - - printk( "%lu MB (%lu byte blocks)", - ((capacity + 5L) / 10L), size ); - } else { - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - } - printk ("\n" ); - } else { - memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); - retcode = fdomain_16x0_command(&SCinit); - } - } - } -#endif - return shpnt; } @@ -1508,31 +1438,6 @@ return 0; } -/* The following code, which simulates the old-style command function, was - taken from Tommy Thorn's aha1542.c file. This code is Copyright (C) - 1992 Tommy Thorn. */ - -static volatile int internal_done_flag = 0; -static volatile int internal_done_errcode = 0; - -static void internal_done(Scsi_Cmnd *SCpnt) -{ - internal_done_errcode = SCpnt->result; - ++internal_done_flag; -} - -static int fdomain_16x0_command(Scsi_Cmnd *SCpnt) -{ - fdomain_16x0_queue(SCpnt, internal_done); - - while (!internal_done_flag) - cpu_relax(); - internal_done_flag = 0; - return internal_done_errcode; -} - -/* End of code derived from Tommy Thorn's work. */ - #if DEBUG_ABORT static void print_info(Scsi_Cmnd *SCpnt) { @@ -1833,7 +1738,6 @@ .proc_name = "fdomain", .detect = fdomain_16x0_detect, .info = fdomain_16x0_info, - .command = fdomain_16x0_command, .queuecommand = fdomain_16x0_queue, .eh_abort_handler = fdomain_16x0_abort, .eh_bus_reset_handler = fdomain_16x0_bus_reset, diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Mon May 26 09:10:33 2003 +++ b/drivers/scsi/hosts.c Thu Jun 5 11:52:51 2003 @@ -20,25 +20,15 @@ * September 04, 2002 Mike Anderson (andmike@us.ibm.com) */ - -/* - * This file contains the medium level SCSI - * host interface initialization, as well as the scsi_hosts list of SCSI - * hosts currently present in the system. - */ - -#include #include -#include +#include #include #include #include #include -#include #include #include #include -#include #include "scsi.h" #include "hosts.h" @@ -47,152 +37,7 @@ #include "scsi_logging.h" -static LIST_HEAD(scsi_host_list); -static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED; - static int scsi_host_next_hn; /* host_no for next new host */ -static char *scsihosts; - -MODULE_PARM(scsihosts, "s"); -MODULE_PARM_DESC(scsihosts, "scsihosts=driver1,driver2,driver3"); -#ifndef MODULE -int __init scsi_setup(char *str) -{ - scsihosts = str; - return 1; -} - -__setup("scsihosts=", scsi_setup); -#endif - -/** - * scsi_find_host_by_num - get a Scsi_Host by host no - * - * @host_no: host number to locate - * - * Return value: - * A pointer to located Scsi_Host or NULL. - **/ -static struct Scsi_Host *scsi_find_host_by_num(unsigned short host_no) -{ - struct Scsi_Host *shost, *shost_found = NULL; - - spin_lock(&scsi_host_list_lock); - list_for_each_entry(shost, &scsi_host_list, sh_list) { - if (shost->host_no > host_no) { - /* - * The list is sorted. - */ - break; - } else if (shost->host_no == host_no) { - shost_found = shost; - break; - } - } - spin_unlock(&scsi_host_list_lock); - return shost_found; -} - -/** - * scsi_alloc_hostnum - choose new SCSI host number based on host name. - * @name: String to store in name field - * - * Return value: - * Pointer to a new Scsi_Host_Name - **/ -static int scsi_alloc_host_num(const char *name) -{ - int hostnum; - int namelen; - const char *start, *end; - - if (name) { - hostnum = 0; - namelen = strlen(name); - start = scsihosts; - while (1) { - int hostlen; - - if (start && start[0] != '\0') { - end = strpbrk(start, ",:"); - if (end) { - hostlen = (end - start); - end++; - } else - hostlen = strlen(start); - /* - * Look for a match on the scsihosts list. - */ - if ((hostlen == namelen) && - (strncmp(name, start, hostlen) == 0) && - (!scsi_find_host_by_num(hostnum))) - return hostnum; - start = end; - } else { - /* - * Look for any unused numbers. - */ - if (!scsi_find_host_by_num(hostnum)) - return hostnum; - } - hostnum++; - } - } else - return scsi_host_next_hn++; -} - - -/** - * scsi_tp_for_each_host - call function for each scsi host off a template - * @shost_tp: a pointer to a scsi host template - * @callback: a pointer to callback function - * - * Return value: - * 0 on Success / 1 on Failure - **/ -int scsi_tp_for_each_host(Scsi_Host_Template *shost_tp, int - (*callback)(struct Scsi_Host *shost)) -{ - struct list_head *lh, *lh_sf; - struct Scsi_Host *shost; - - spin_lock(&scsi_host_list_lock); - - list_for_each_safe(lh, lh_sf, &scsi_host_list) { - shost = list_entry(lh, struct Scsi_Host, sh_list); - if (shost->hostt == shost_tp) { - spin_unlock(&scsi_host_list_lock); - callback(shost); - spin_lock(&scsi_host_list_lock); - } - } - - spin_unlock(&scsi_host_list_lock); - - return 0; -} - -/** - * scsi_host_legacy_release - default release function for hosts - * @shost: - * - * Description: - * This is the default case for the release function. Its completely - * useless for anything but old ISA adapters - **/ -static int scsi_host_legacy_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); -#ifdef CONFIG_GENERIC_ISA_DMA - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); -#endif - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - - return 0; -} /** * scsi_remove_host - check a scsi host for release and release @@ -217,9 +62,6 @@ scsi_forget_host(shost); scsi_sysfs_remove_host(shost); - if (shost->hostt->release) - (*shost->hostt->release)(shost); - return 0; } @@ -233,7 +75,7 @@ **/ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) { - Scsi_Host_Template *sht = shost->hostt; + struct scsi_host_template *sht = shost->hostt; int error; printk(KERN_INFO "scsi%d : %s\n", shost->host_no, @@ -243,34 +85,17 @@ if (!error) { scsi_proc_host_add(shost); scsi_scan_host(shost); - }; + } return error; } /** - * scsi_unregister - unregister a scsi host - * @shost: scsi host to be unregistered - **/ -void scsi_unregister(struct Scsi_Host *shost) -{ - scsi_host_put(shost); -} - -/** * scsi_free_sdev - free a scsi hosts resources * @shost: scsi host to free **/ void scsi_free_shost(struct Scsi_Host *shost) { - /* Remove shost from scsi_host_list */ - spin_lock(&scsi_host_list_lock); - list_del(&shost->sh_list); - spin_unlock(&scsi_host_list_lock); - - /* - * Next, kill the kernel error recovery thread for this host. - */ if (shost->ehandler) { DECLARE_COMPLETION(sem); shost->eh_notify = &sem; @@ -286,60 +111,58 @@ } /** - * scsi_register - register a scsi host adapter instance. - * @shost_tp: pointer to scsi host template - * @xtr_bytes: extra bytes to allocate for driver + * scsi_host_alloc - register a scsi host adapter instance. + * @sht: pointer to scsi host template + * @privsize: extra bytes to allocate for driver * * Note: - * We call this when we come across a new host adapter. We only do - * this once we are 100% sure that we want to use this host adapter - - * it is a pain to reverse this, so we try to avoid it + * Allocate a new Scsi_Host and perform basic initialization. + * The host is not published to the scsi midlayer until scsi_add_host + * is called. * * Return value: * Pointer to a new Scsi_Host **/ -extern int blk_nohighio; -struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes) +struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { - struct Scsi_Host *shost, *shost_scr; - int gfp_mask, rval; - DECLARE_COMPLETION(sem); + struct Scsi_Host *shost; + int gfp_mask = GFP_KERNEL, rval; + DECLARE_COMPLETION(complete); + + if (sht->unchecked_isa_dma && privsize) + gfp_mask |= __GFP_DMA; /* Check to see if this host has any error handling facilities */ - if(shost_tp->eh_strategy_handler == NULL && - shost_tp->eh_abort_handler == NULL && - shost_tp->eh_device_reset_handler == NULL && - shost_tp->eh_bus_reset_handler == NULL && - shost_tp->eh_host_reset_handler == NULL) { - printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", shost_tp->proc_name); + if (!sht->eh_strategy_handler && !sht->eh_abort_handler && + !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler && + !sht->eh_host_reset_handler) { + printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n" + "ERROR: This is not a safe way to run your " + "SCSI host\n" + "ERROR: The error handling must be added to " + "this driver\n", sht->proc_name); dump_stack(); } - if(shost_tp->shost_attrs == NULL) - /* if its not set in the template, use the default */ - shost_tp->shost_attrs = scsi_sysfs_shost_attrs; - if(shost_tp->sdev_attrs == NULL) - shost_tp->sdev_attrs = scsi_sysfs_sdev_attrs; - gfp_mask = GFP_KERNEL; - if (shost_tp->unchecked_isa_dma && xtr_bytes) - gfp_mask |= __GFP_DMA; - - shost = kmalloc(sizeof(struct Scsi_Host) + xtr_bytes, gfp_mask); - if (!shost) { - printk(KERN_ERR "%s: out of memory.\n", __FUNCTION__); - return NULL; - } - memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes); + /* if its not set in the template, use the default */ + if (!sht->shost_attrs) + sht->shost_attrs = scsi_sysfs_shost_attrs; + if (!sht->sdev_attrs) + sht->sdev_attrs = scsi_sysfs_sdev_attrs; - shost->host_no = scsi_alloc_host_num(shost_tp->proc_name); + shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); + if (!shost) + return NULL; + memset(shost, 0, sizeof(struct Scsi_Host) + privsize); spin_lock_init(&shost->default_lock); scsi_assign_lock(shost, &shost->default_lock); INIT_LIST_HEAD(&shost->my_devices); INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->starved_list); - init_waitqueue_head(&shost->host_wait); + + shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */ shost->dma_channel = 0xff; /* These three are default values which can be overridden */ @@ -354,54 +177,29 @@ * they actually do something sensible with such commands. */ shost->max_cmd_len = 12; - shost->hostt = shost_tp; - shost->host_blocked = 0; - shost->host_self_blocked = FALSE; - shost->max_host_blocked = shost_tp->max_host_blocked ? shost_tp->max_host_blocked : SCSI_DEFAULT_HOST_BLOCKED; - -#ifdef DEBUG - printk("%s: %x %x: %d\n", __FUNCTION_ (int)shost, - (int)shost->hostt, xtr_bytes); -#endif + shost->hostt = sht; + shost->this_id = sht->this_id; + shost->can_queue = sht->can_queue; + shost->sg_tablesize = sht->sg_tablesize; + shost->cmd_per_lun = sht->cmd_per_lun; + shost->unchecked_isa_dma = sht->unchecked_isa_dma; + shost->use_clustering = sht->use_clustering; + shost->use_blk_tcq = sht->use_blk_tcq; + shost->highmem_io = sht->highmem_io; + + if (!sht->max_host_blocked) + shost->max_host_blocked = sht->max_host_blocked; + else + shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED; /* - * The next six are the default values which can be overridden if - * need be + * If the driver imposes no hard sector transfer limit, start at + * machine infinity initially. */ - shost->this_id = shost_tp->this_id; - shost->can_queue = shost_tp->can_queue; - shost->sg_tablesize = shost_tp->sg_tablesize; - shost->cmd_per_lun = shost_tp->cmd_per_lun; - shost->unchecked_isa_dma = shost_tp->unchecked_isa_dma; - shost->use_clustering = shost_tp->use_clustering; - if (!blk_nohighio) - shost->highmem_io = shost_tp->highmem_io; - if (!shost_tp->max_sectors) { - /* - * Driver imposes no hard sector transfer limit. - * start at machine infinity initially. - */ + if (sht->max_sectors) + shost->max_sectors = sht->max_sectors; + else shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; - } else - shost->max_sectors = shost_tp->max_sectors; - shost->use_blk_tcq = shost_tp->use_blk_tcq; - - spin_lock(&scsi_host_list_lock); - /* - * FIXME When device naming is complete remove this step that - * orders the scsi_host_list by host number and just do a - * list_add_tail. - */ - list_for_each_entry(shost_scr, &scsi_host_list, sh_list) { - if (shost->host_no < shost_scr->host_no) { - __list_add(&shost->sh_list, shost_scr->sh_list.prev, - &shost_scr->sh_list); - goto found; - } - } - list_add_tail(&shost->sh_list, &scsi_host_list); -found: - spin_unlock(&scsi_host_list_lock); rval = scsi_setup_command_freelist(shost); if (rval) @@ -409,85 +207,37 @@ scsi_sysfs_init_host(shost); - shost->eh_notify = &sem; - kernel_thread((int (*)(void *)) scsi_error_handler, (void *) shost, 0); - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - wait_for_completion(&sem); + shost->eh_notify = &complete; + /* XXX(hch): handle error return */ + kernel_thread((int (*)(void *))scsi_error_handler, shost, 0); + wait_for_completion(&complete); shost->eh_notify = NULL; shost->hostt->present++; return shost; - -fail: - spin_lock(&scsi_host_list_lock); - list_del(&shost->sh_list); - spin_unlock(&scsi_host_list_lock); + fail: kfree(shost); return NULL; } -/** - * scsi_register_host - register a low level host driver - * @shost_tp: pointer to a scsi host driver template - * - * Return value: - * 0 on Success / 1 on Failure. - **/ -int scsi_register_host(Scsi_Host_Template *shost_tp) +struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize) { - struct Scsi_Host *shost; - - BUG_ON(!shost_tp->detect); + struct Scsi_Host *shost = scsi_host_alloc(sht, privsize); - if (!shost_tp->release) { - printk(KERN_WARNING - "scsi HBA driver %s didn't set a release method, " - "please fix the template\n", shost_tp->name); - shost_tp->release = &scsi_host_legacy_release; + if (!sht->detect) { + printk(KERN_WARNING "scsi_register() called on new-style " + "template for driver %s\n", sht->name); + dump_stack(); } - shost_tp->detect(shost_tp); - if (!shost_tp->present) - return 0; - - /* - * XXX(hch) use scsi_tp_for_each_host() once it propagates - * error returns properly. - */ - list_for_each_entry(shost, &scsi_host_list, sh_list) - if (shost->hostt == shost_tp) - if (scsi_add_host(shost, NULL)) - goto out_of_space; - - return 0; - -out_of_space: - scsi_unregister_host(shost_tp); /* easiest way to clean up?? */ - return 1; + if (shost) + list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts); + return shost; } -/** - * scsi_unregister_host - unregister a low level host adapter driver - * @shost_tp: scsi host template to unregister. - * - * Description: - * Similarly, this entry point should be called by a loadable module - * if it is trying to remove a low level scsi driver from the system. - * - * Return value: - * 0 on Success / 1 on Failure - * - * Notes: - * rmmod does not care what we return here the module will be - * removed. - **/ -int scsi_unregister_host(Scsi_Host_Template *shost_tp) +void scsi_unregister(struct Scsi_Host *shost) { - scsi_tp_for_each_host(shost_tp, scsi_remove_host); - return 0; - + list_del(&shost->sht_legacy_list); + scsi_host_put(shost); } /** @@ -536,50 +286,6 @@ **/ void scsi_host_put(struct Scsi_Host *shost) { - class_device_put(&shost->class_dev); put_device(&shost->host_gendev); -} - -/** - * scsi_host_init - set up the scsi host number list based on any entries - * scsihosts. - **/ -void __init scsi_host_init(void) -{ - char *shost_hn; - - shost_hn = scsihosts; - while (shost_hn) { - scsi_host_next_hn++; - shost_hn = strpbrk(shost_hn, ":,"); - if (shost_hn) - shost_hn++; - } -} - -void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - shost->host_busy++; - sdev->device_busy++; - spin_unlock_irqrestore(shost->host_lock, flags); -} - -void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - shost->host_busy--; - if (shost->in_recovery && shost->host_failed && - (shost->host_busy == shost->host_failed)) - { - up(shost->eh_wait); - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - " thread\n")); - } - spin_unlock_irqrestore(shost->host_lock, flags); } diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h --- a/drivers/scsi/hosts.h Mon May 26 03:02:43 2003 +++ b/drivers/scsi/hosts.h Sun Jun 8 15:03:00 2003 @@ -28,519 +28,7 @@ #include #include -struct scsi_host_cmd_pool; - - -/* It is senseless to set SG_ALL any higher than this - the performance - * does not get any better, and it wastes memory - */ -#define SG_NONE 0 -#define SG_ALL 0xff - -#define DISABLE_CLUSTERING 0 -#define ENABLE_CLUSTERING 1 - -/* The various choices mean: - * NONE: Self evident. Host adapter is not capable of scatter-gather. - * ALL: Means that the host adapter module can do scatter-gather, - * and that there is no limit to the size of the table to which - * we scatter/gather data. - * Anything else: Indicates the maximum number of chains that can be - * used in one scatter-gather request. - */ - -/* - * The Scsi_Host_Template type has all that is needed to interface with a SCSI - * host in a device independent matter. There is one entry for each different - * type of host adapter that is supported on the system. - */ - -typedef struct SHT -{ - /* Used with loadable modules so that we know when it is safe to unload */ - struct module * module; - - /* The pointer to the /proc/scsi directory entry */ - struct proc_dir_entry *proc_dir; - - /* proc-fs info function. - * Can be used to export driver statistics and other infos to the world - * outside the kernel ie. userspace and it also provides an interface - * to feed the driver with information. Check eata_dma_proc.c for reference - */ - int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); - - /* - * The name pointer is a pointer to the name of the SCSI - * device detected. - */ - const char *name; - - /* - * The detect function shall return non zero on detection, - * indicating the number of host adapters of this particular - * type were found. It should also - * initialize all data necessary for this particular - * SCSI driver. It is passed the host number, so this host - * knows where the first entry is in the scsi_hosts[] array. - * - * Note that the detect routine MUST not call any of the mid level - * functions to queue commands because things are not guaranteed - * to be set up yet. The detect routine can send commands to - * the host adapter as long as the program control will not be - * passed to scsi.c in the processing of the command. Note - * especially that scsi_malloc/scsi_free must not be called. - */ - int (* detect)(struct SHT *); - - /* Used with loadable modules to unload the host structures. Note: - * there is a default action built into the modules code which may - * be sufficient for most host adapters. Thus you may not have to supply - * this at all. - */ - int (*release)(struct Scsi_Host *); - - /* - * The info function will return whatever useful - * information the developer sees fit. If not provided, then - * the name field will be used instead. - */ - const char *(* info)(struct Scsi_Host *); - - /* - * ioctl interface - */ - int (*ioctl)(Scsi_Device *dev, int cmd, void *arg); - - /* - * The command function takes a target, a command (this is a SCSI - * command formatted as per the SCSI spec, nothing strange), a - * data buffer pointer, and data buffer length pointer. The return - * is a status int, bit fielded as follows : - * Byte What - * 0 SCSI status code - * 1 SCSI 1 byte message - * 2 host error return. - * 3 mid level error return - */ - int (* command)(Scsi_Cmnd *); - - /* - * The QueueCommand function works in a similar manner - * to the command function. It takes an additional parameter, - * void (* done)(int host, int code) which is passed the host - * # and exit result when the command is complete. - * Host number is the POSITION IN THE hosts array of THIS - * host adapter. - * - * if queuecommand returns 0, then the HBA has accepted the - * command. The done() function must be called on the command - * when the driver has finished with it. (you may call done on the - * command before queuecommand returns, but in this case you - * *must* return 0 from queuecommand). - * - * queuecommand may also reject the command, in which case it may - * not touch the command and must not call done() for it. - * - * There are two possible rejection returns: - * - * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but - * allow commands to other devices serviced by this host. - * - * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this - * host temporarily. - * - * for compatibility, any other non-zero return is treated the - * same as SCSI_MLQUEUE_HOST_BUSY. - * - * NOTE: "temporarily" means either until the next command for - * this device/host completes, or a period of time determined by - * I/O pressure in the system if there are no other outstanding - * commands. - * */ - int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - - /* - * This is an error handling strategy routine. You don't need to - * define one of these if you don't want to - there is a default - * routine that is present that should work in most cases. For those - * driver authors that have the inclination and ability to write their - * own strategy routine, this is where it is specified. Note - the - * strategy routine is *ALWAYS* run in the context of the kernel eh - * thread. Thus you are guaranteed to *NOT* be in an interrupt handler - * when you execute this, and you are also guaranteed to *NOT* have any - * other commands being queued while you are in the strategy routine. - * When you return from this function, operations return to normal. - * - * See scsi_error.c scsi_unjam_host for additional comments about what - * this function should and should not be attempting to do. - */ - int (*eh_strategy_handler)(struct Scsi_Host *); - int (*eh_abort_handler)(Scsi_Cmnd *); - int (*eh_device_reset_handler)(Scsi_Cmnd *); - int (*eh_bus_reset_handler)(Scsi_Cmnd *); - int (*eh_host_reset_handler)(Scsi_Cmnd *); - - /* - * Old EH handlers, no longer used. Make them warn the user of old - * drivers by using a wrong type - */ - int (*abort)(int); - int (*reset)(int,int); - - /* - * slave_alloc() - Optional - * - * Before the mid layer attempts to scan for a new device where none - * currently exists, it will call this entry in your driver. Should - * your driver need to allocate any structs or perform any other init - * items in order to send commands to a currently unused target/lun - * combo, then this is where you can perform those allocations. This - * is specifically so that drivers won't have to perform any kind of - * "is this a new device" checks in their queuecommand routine, - * thereby making the hot path a bit quicker. - * - * Return values: 0 on success, non-0 on failure - * - * Deallocation: If we didn't find any devices at this ID, you will - * get an immediate call to slave_destroy(). If we find something here - * then you will get a call to slave_configure(), then the device will be - * used for however long it is kept around, then when the device is - * removed from the system (or * possibly at reboot time), you will - * then get a call to slave_detach(). This is assuming you implement - * slave_configure and slave_destroy. However, if you allocate memory - * and hang it off the device struct, then you must implement the - * slave_destroy() routine at a minimum in order to avoid leaking memory - * each time a device is tore down. - */ - int (* slave_alloc)(Scsi_Device *); - - /* - * slave_configure() - Optional - * - * Once the device has responded to an INQUIRY and we know the device - * is online, we call into the low level driver with the Scsi_Device * - * If the low level device driver implements this function, it *must* - * perform the task of setting the queue depth on the device. All other - * tasks are optional and depend on what the driver supports and various - * implementation details. - * - * Things currently recommended to be handled at this time include: - * - * 1. Setting the device queue depth. Proper setting of this is - * described in the comments for scsi_adjust_queue_depth. - * 2. Determining if the device supports the various synchronous - * negotiation protocols. The device struct will already have - * responded to INQUIRY and the results of the standard items - * will have been shoved into the various device flag bits, eg. - * device->sdtr will be true if the device supports SDTR messages. - * 3. Allocating command structs that the device will need. - * 4. Setting the default timeout on this device (if needed). - * 5. Anything else the low level driver might want to do on a device - * specific setup basis... - * 6. Return 0 on success, non-0 on error. The device will be marked - * as offline on error so that no access will occur. If you return - * non-0, your slave_detach routine will never get called for this - * device, so don't leave any loose memory hanging around, clean - * up after yourself before returning non-0 - */ - int (* slave_configure)(Scsi_Device *); - - /* - * slave_destroy() - Optional - * - * Immediately prior to deallocating the device and after all activity - * has ceased the mid layer calls this point so that the low level driver - * may completely detach itself from the scsi device and vice versa. - * The low level driver is responsible for freeing any memory it allocated - * in the slave_alloc or slave_configure calls. - */ - void (* slave_destroy)(Scsi_Device *); - - /* - * This function determines the bios parameters for a given - * harddisk. These tend to be numbers that are made up by - * the host adapter. Parameters: - * size, device, list (heads, sectors, cylinders) - */ - int (* bios_param)(struct scsi_device *, struct block_device *, - sector_t, int []); - - /* - * This determines if we will use a non-interrupt driven - * or an interrupt driven scheme, It is set to the maximum number - * of simultaneous commands a given host adapter will accept. - */ - int can_queue; - - /* - * In many instances, especially where disconnect / reconnect are - * supported, our host also has an ID on the SCSI bus. If this is - * the case, then it must be reserved. Please set this_id to -1 if - * your setup is in single initiator mode, and the host lacks an - * ID. - */ - int this_id; - - /* - * This determines the degree to which the host adapter is capable - * of scatter-gather. - */ - short unsigned int sg_tablesize; - - /* - * if the host adapter has limitations beside segment count - */ - short unsigned int max_sectors; - - /* - * True if this host adapter can make good use of linked commands. - * This will allow more than one command to be queued to a given - * unit on a given host. Set this to the maximum number of command - * blocks to be provided for each device. Set this to 1 for one - * command block per lun, 2 for two, etc. Do not set this to 0. - * You should make sure that the host adapter will do the right thing - * before you try setting this above 1. - */ - short cmd_per_lun; - - /* - * present contains counter indicating how many boards of this - * type were found when we did the scan. - */ - unsigned char present; - - /* - * true if this host adapter uses unchecked DMA onto an ISA bus. - */ - unsigned unchecked_isa_dma:1; - - /* - * true if this host adapter can make good use of clustering. - * I originally thought that if the tablesize was large that it - * was a waste of CPU cycles to prepare a cluster list, but - * it works out that the Buslogic is faster if you use a smaller - * number of segments (i.e. use clustering). I guess it is - * inefficient. - */ - unsigned use_clustering:1; - - /* - * True for emulated SCSI host adapters (e.g. ATAPI) - */ - unsigned emulated:1; - - unsigned highmem_io:1; - - /* - * True if the driver wishes to use the generic block layer - * tag queueing functions - */ - unsigned use_blk_tcq:1; - - /* - * Name of proc directory - */ - char *proc_name; - - /* - * countdown for host blocking with no commands outstanding - */ - unsigned int max_host_blocked; - - /* - * Default value for the blocking. If the queue is empty, host_blocked - * counts down in the request_fn until it restarts host operations as - * zero is reached. - * - * FIXME: This should probably be a value in the template */ - #define SCSI_DEFAULT_HOST_BLOCKED 7 - - /* - * pointer to the sysfs class properties for this host - */ - struct class_device_attribute **shost_attrs; - - /* - * Pointer to the SCSI device properties for this host - */ - struct device_attribute **sdev_attrs; - -} Scsi_Host_Template; - -/* - * The scsi_hosts array is the array containing the data for all - * possible scsi hosts. This is similar to the - * Scsi_Host_Template, except that we have one entry for each - * actual physical host adapter on the system, stored as a linked - * list. Note that if there are 2 aha1542 boards, then there will - * be two Scsi_Host entries, but only 1 Scsi_Host_Template entry. - */ - -struct Scsi_Host -{ -/* private: */ - /* - * This information is private to the scsi mid-layer. Wrapping it in a - * struct private is a way of marking it in a sort of C++ type of way. - */ - struct list_head sh_list; - struct list_head my_devices; - - struct scsi_host_cmd_pool *cmd_pool; - spinlock_t free_list_lock; - struct list_head free_list; /* backup store of cmd structs */ - struct list_head starved_list; - - spinlock_t default_lock; - spinlock_t *host_lock; - - struct list_head eh_cmd_q; - struct task_struct * ehandler; /* Error recovery thread. */ - struct semaphore * eh_wait; /* The error recovery thread waits on - this. */ - struct completion * eh_notify; /* wait for eh to begin or end */ - struct semaphore * eh_action; /* Wait for specific actions on the - host. */ - unsigned int eh_active:1; /* Indicates the eh thread is awake and active if - this is true. */ - unsigned int eh_kill:1; /* set when killing the eh thread */ - wait_queue_head_t host_wait; - Scsi_Host_Template * hostt; - volatile unsigned short host_busy; /* commands actually active on low-level */ - volatile unsigned short host_failed; /* commands that failed. */ - -/* public: */ - unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ - int resetting; /* if set, it means that last_reset is a valid value */ - unsigned long last_reset; - - /* - * These three parameters can be used to allow for wide scsi, - * and for host adapters that support multiple busses - * The first two should be set to 1 more than the actual max id - * or lun (i.e. 8 for normal systems). - */ - unsigned int max_id; - unsigned int max_lun; - unsigned int max_channel; - - /* These parameters should be set by the detect routine */ - unsigned long base; - unsigned long io_port; - unsigned char n_io_port; - unsigned char dma_channel; - unsigned int irq; - - /* - * This is a unique identifier that must be assigned so that we - * have some way of identifying each detected host adapter properly - * and uniquely. For hosts that do not support more than one card - * in the system at one time, this does not need to be set. It is - * initialized to 0 in scsi_register. - */ - unsigned int unique_id; - - /* - * The rest can be copied from the template, or specifically - * initialized, as required. - */ - - /* - * The maximum length of SCSI commands that this host can accept. - * Probably 12 for most host adapters, but could be 16 for others. - * For drivers that don't set this field, a value of 12 is - * assumed. I am leaving this as a number rather than a bit - * because you never know what subsequent SCSI standards might do - * (i.e. could there be a 20 byte or a 24-byte command a few years - * down the road?). - */ - unsigned char max_cmd_len; - - int this_id; - int can_queue; - short cmd_per_lun; - short unsigned int sg_tablesize; - short unsigned int max_sectors; - - unsigned in_recovery:1; - unsigned unchecked_isa_dma:1; - unsigned use_clustering:1; - unsigned highmem_io:1; - unsigned use_blk_tcq:1; - - /* - * Host has requested that no further requests come through for the - * time being. - */ - unsigned host_self_blocked:1; - - /* - * Host uses correct SCSI ordering not PC ordering. The bit is - * set for the minority of drivers whose authors actually read the spec ;) - */ - unsigned reverse_ordering:1; - - /* - * Host has rejected a command because it was busy. - */ - unsigned int host_blocked; - - /* - * Value host_blocked counts down from - */ - unsigned int max_host_blocked; - - /* - * Support for sysfs - */ - struct device host_gendev; - struct class_device class_dev; - - /* - * We should ensure that this is aligned, both for better performance - * and also because some compilers (m68k) don't automatically force - * alignment to a long boundary. - */ - unsigned long hostdata[0] /* Used for storage of host specific stuff */ - __attribute__ ((aligned (sizeof(unsigned long)))); -}; - -#define dev_to_shost(d) \ - container_of(d, struct Scsi_Host, host_gendev) -#define class_to_shost(d) \ - container_of(d, struct Scsi_Host, class_dev) - -/* - * These two functions are used to allocate and free a pseudo device - * which will connect to the host adapter itself rather than any - * physical device. You must deallocate when you are done with the - * thing. This physical pseudo-device isn't real and won't be available - * from any high-level drivers. - */ -extern void scsi_free_host_dev(Scsi_Device *); -extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *); - -extern void scsi_unblock_requests(struct Scsi_Host *); -extern void scsi_block_requests(struct Scsi_Host *); -extern void scsi_report_bus_reset(struct Scsi_Host *, int); -extern void scsi_report_device_reset(struct Scsi_Host *, int, int); - -static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) -{ - shost->host_lock = lock; -} - -static inline void scsi_set_device(struct Scsi_Host *shost, - struct device *dev) -{ - shost->host_gendev.parent = dev; -} - -static inline struct device *scsi_get_device(struct Scsi_Host *shost) -{ - return shost->host_gendev.parent; -} +#include struct scsi_driver { struct module *owner; @@ -560,23 +48,6 @@ #define scsi_unregister_interface(intf) \ class_interface_unregister(intf) -/* - * HBA allocation/freeing. - */ -extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int); -extern void scsi_unregister(struct Scsi_Host *); - -/* - * HBA registration/unregistration. - */ -extern int scsi_add_host(struct Scsi_Host *, struct device *); -extern int scsi_remove_host(struct Scsi_Host *); - -/* - * Legacy HBA template registration/unregistration. - */ -extern int scsi_register_host(Scsi_Host_Template *); -extern int scsi_unregister_host(Scsi_Host_Template *); /** * scsi_find_device - find a device given the host @@ -585,9 +56,9 @@ * @pun: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number **/ -static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost, +static inline struct scsi_device *scsi_find_device(struct Scsi_Host *shost, int channel, int pun, int lun) { - Scsi_Device *sdev; + struct scsi_device *sdev; list_for_each_entry (sdev, &shost->my_devices, siblings) if (sdev->channel == channel && sdev->id == pun @@ -595,7 +66,5 @@ return sdev; return NULL; } - -extern void scsi_sysfs_release_attributes(struct SHT *hostt); #endif diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c --- a/drivers/scsi/ibmmca.c Mon May 12 07:26:12 2003 +++ b/drivers/scsi/ibmmca.c Sun Jun 8 12:18:41 2003 @@ -1793,15 +1793,6 @@ return shpnt; } -static int ibmmca_command(Scsi_Cmnd * cmd) -{ - ibmmca_queuecommand(cmd, internal_done); - cmd->SCp.Status = 0; - while (!cmd->SCp.Status) - barrier(); - return cmd->result; -} - static int ibmmca_release(struct Scsi_Host *shpnt) { release_region(shpnt->io_port, shpnt->n_io_port); @@ -2490,7 +2481,6 @@ .name = "IBM SCSI-Subsystem", .detect = ibmmca_detect, .release = ibmmca_release, - .command = ibmmca_command, .queuecommand = ibmmca_queuecommand, .eh_abort_handler = ibmmca_abort, .eh_host_reset_handler = ibmmca_host_reset, diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Mon May 26 03:12:22 2003 +++ b/drivers/scsi/ide-scsi.c Mon Jun 2 17:42:21 2003 @@ -612,7 +612,7 @@ drive->disk->fops = ide_fops; scsi_remove_host(scsihost); - scsi_unregister(scsihost); + scsi_host_put(scsihost); return 0; } @@ -964,7 +964,7 @@ if (!strstr("ide-scsi", drive->driver_req) || !drive->present || drive->media == ide_disk || - !(host = scsi_register(&idescsi_template,sizeof(idescsi_scsi_t)))) + !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t)))) return 1; host->max_id = 1; @@ -984,7 +984,7 @@ ide_unregister_subdriver(drive); } - scsi_unregister(host); + scsi_host_put(host); return err; } diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c Tue May 27 09:05:29 2003 +++ b/drivers/scsi/imm.c Sun Jun 8 12:18:41 2003 @@ -113,7 +113,6 @@ .name = "Iomega VPI2 (imm) interface", .detect = imm_detect, .release = imm_release, - .command = imm_command, .queuecommand = imm_queuecommand, .eh_abort_handler = imm_abort, .eh_bus_reset_handler = imm_reset, @@ -856,39 +855,6 @@ return 0; } return 1; /* FINISH_RETURN */ -} - -/* deprecated synchronous interface */ -int imm_command(Scsi_Cmnd * cmd) -{ - static int first_pass = 1; - int host_no = cmd->device->host->unique_id; - - if (first_pass) { - printk("imm: using non-queuing interface\n"); - first_pass = 0; - } - if (imm_hosts[host_no].cur_cmd) { - printk("IMM: bug in imm_command\n"); - return 0; - } - imm_hosts[host_no].failed = 0; - imm_hosts[host_no].jstart = jiffies; - imm_hosts[host_no].cur_cmd = cmd; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; - - imm_pb_claim(host_no); - - while (imm_engine(&imm_hosts[host_no], cmd)) - schedule(); - - if (cmd->SCp.phase) /* Only disconnect if we have connected */ - imm_disconnect(cmd->device->host->unique_id); - - imm_pb_release(host_no); - imm_hosts[host_no].cur_cmd = 0; - return cmd->result; } /* diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c --- a/drivers/scsi/ini9100u.c Sun May 4 02:56:43 2003 +++ b/drivers/scsi/ini9100u.c Sun Jun 8 12:18:41 2003 @@ -147,7 +147,6 @@ .name = i91u_REVID, .detect = i91u_detect, .release = i91u_release, - .command = i91u_command, .queuecommand = i91u_queue, .abort = i91u_abort, .reset = i91u_reset, @@ -555,15 +554,6 @@ i91uBuildSCB(pHCB, pSCB, SCpnt); tul_exec_scb(pHCB, pSCB); /* Start execute SCB */ return (0); -} - -/* - * We only support command in interrupt-driven fashion - */ -int i91u_command(Scsi_Cmnd * SCpnt) -{ - printk("i91u: interrupt driven driver; use i91u_queue()\n"); - return -1; } /* diff -Nru a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c --- a/drivers/scsi/inia100.c Mon Jun 9 16:05:03 2003 +++ b/drivers/scsi/inia100.c Mon Jun 16 08:48:22 2003 @@ -156,11 +156,11 @@ spin_lock_irqsave(&(pHCB->pSRB_lock), flags); - pSRB->next = NULL; /* Pointer to next */ + pSRB->SCp.ptr = NULL; /* Pointer to next */ if (pHCB->pSRB_head == NULL) pHCB->pSRB_head = pSRB; else - pHCB->pSRB_tail->next = pSRB; /* Pointer to next */ + pHCB->pSRB_tail->SCp.ptr = (char *)pSRB; /* Pointer to next */ pHCB->pSRB_tail = pSRB; spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); return; @@ -179,8 +179,8 @@ ULONG flags; spin_lock_irqsave(&(pHCB->pSRB_lock), flags); if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) { - pHCB->pSRB_head = pHCB->pSRB_head->next; - pSRB->next = NULL; + pHCB->pSRB_head = (Scsi_Cmnd *) pHCB->pSRB_head->SCp.ptr; + pSRB->SCp.ptr = NULL; } spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags); return (pSRB); diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c Mon May 12 07:26:13 2003 +++ b/drivers/scsi/ips.c Thu Jun 5 11:39:39 2003 @@ -725,7 +725,7 @@ free_irq(ha->irq, ha); IPS_REMOVE_HOST(sh); - scsi_unregister(sh); + scsi_host_put(sh); ips_released_controllers++; @@ -6732,7 +6732,7 @@ ips_register_scsi( int index){ struct Scsi_Host *sh; ips_ha_t *ha, *oldha = ips_ha[index]; - sh = scsi_register(&ips_driver_template, sizeof(ips_ha_t)); + sh = scsi_host_alloc(&ips_driver_template, sizeof(ips_ha_t)); if(!sh) { IPS_PRINTK(KERN_WARNING, oldha->pcidev, "Unable to register controller with SCSI subsystem\n"); return -1; @@ -6743,7 +6743,7 @@ /* Install the interrupt handler with the new ha */ if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n" ); - scsi_unregister(sh); + scsi_host_put(sh); return -1; } diff -Nru a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c --- a/drivers/scsi/jazz_esp.c Mon Nov 11 13:23:24 2002 +++ b/drivers/scsi/jazz_esp.c Sun Jun 8 12:18:41 2003 @@ -139,6 +139,18 @@ return 0; } +static int jazz_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /************************************************************* DMA Functions */ static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count) { @@ -278,8 +290,8 @@ .proc_info = &esp_proc_info, .name = "ESP 100/100a/200", .detect = jazz_esp_detect, + .release = jazz_esp_release, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c --- a/drivers/scsi/lasi700.c Sun May 4 02:56:44 2003 +++ b/drivers/scsi/lasi700.c Tue Jun 17 13:27:45 2003 @@ -31,19 +31,14 @@ * machines for me to debug the driver on. */ -#ifndef __hppa__ -#error "lasi700 only compiles on hppa architecture" -#endif - #include +#include #include #include #include #include -#include +#include #include -#include -#include #include #include @@ -54,65 +49,27 @@ #include #include -#include - #include "scsi.h" #include "hosts.h" #include "lasi700.h" #include "53c700.h" -#ifdef MODULE - -char *lasi700; /* command line from insmod */ - MODULE_AUTHOR("James Bottomley"); MODULE_DESCRIPTION("lasi700 SCSI Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(lasi700, "s"); - -#endif -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -static unsigned long __initdata opt_base; -static int __initdata opt_irq; - -static int __init -param_setup(char *string) -{ - char *pos = string, *next; - - while(pos != NULL && (next = strchr(pos, ':')) != NULL) { - int val = (int)simple_strtoul(++next, NULL, 0); - - if(!strncmp(pos, "addr:", 5)) - opt_base = val; - else if(!strncmp(pos, "irq:", 4)) - opt_irq = val; - - if((pos = strchr(pos, ARG_SEP)) != NULL) - pos++; - } - return 1; -} - -#ifndef MODULE -__setup("lasi700=", param_setup); -#endif - -static Scsi_Host_Template __initdata *host_tpnt = NULL; -static int __initdata host_count = 0; static struct parisc_device_id lasi700_scsi_tbl[] = { LASI700_ID_TABLE, LASI710_ID_TABLE, { 0 } }; +static Scsi_Host_Template lasi700_template = { + .name = "LASI SCSI 53c700", + .proc_name = "lasi700", + .this_id = 7, +}; MODULE_DEVICE_TABLE(parisc, lasi700_scsi_tbl); static struct parisc_driver lasi700_driver = { @@ -122,50 +79,36 @@ }; static int __init -lasi700_detect(Scsi_Host_Template *tpnt) -{ - host_tpnt = tpnt; - -#ifdef MODULE - if(lasi700) - param_setup(lasi700); -#endif - - register_parisc_driver(&lasi700_driver); - - return (host_count != 0); -} - -static int __init lasi700_driver_callback(struct parisc_device *dev) { unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET; - char *driver_name; + struct NCR_700_Host_Parameters *hostdata; struct Scsi_Host *host; - struct NCR_700_Host_Parameters *hostdata = - kmalloc(sizeof(struct NCR_700_Host_Parameters), - GFP_KERNEL); - if(dev->id.sversion == LASI_700_SVERSION) { - driver_name = "lasi700"; - } else { - driver_name = "lasi710"; - } - snprintf(dev->dev.name, sizeof(dev->dev.name), "%s", driver_name); - if(hostdata == NULL) { + + snprintf(dev->dev.name, sizeof(dev->dev.name), "%s", + (dev->id.sversion == LASI_700_SVERSION) ? + "lasi700" : "lasi710"); + + hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL); + if (!hostdata) { printk(KERN_ERR "%s: Failed to allocate host data\n", - driver_name); + dev->dev.name); return 1; } memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); - if(request_mem_region(base, 64, driver_name) == NULL) { + + if (!request_mem_region(base, 64, dev->dev.name)) { printk(KERN_ERR "%s: Failed to claim memory region\n", - driver_name); - kfree(hostdata); - return 1; + dev->dev.name); + goto out_kfree; } + + hostdata->dev = &dev->dev; + dma_set_mask(&dev->dev, 0xffffffffUL); hostdata->base = base; hostdata->differential = 0; - if(dev->id.sversion == LASI_700_SVERSION) { + + if (dev->id.sversion == LASI_700_SVERSION) { hostdata->clock = LASI700_CLOCK; hostdata->force_le_on_be = 1; } else { @@ -174,26 +117,34 @@ hostdata->chip710 = 1; hostdata->dmode_extra = DMODE_FC2; } - hostdata->dev = &dev->dev; - dma_set_mask(&dev->dev, 0xffffffffUL); - if((host = NCR_700_detect(host_tpnt, hostdata)) == NULL) { - kfree(hostdata); - release_mem_region(host->base, 64); - return 1; - } - scsi_set_device(host, &dev->dev); + + NCR_700_set_mem_mapped(hostdata); + + host = NCR_700_detect(&lasi700_template, hostdata); + if (!host) + goto out_release_mem_region; + host->irq = dev->irq; - if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, driver_name, host)) { + if (request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, + dev->dev.name, host)) { printk(KERN_ERR "%s: irq problem, detaching\n", - driver_name); - scsi_unregister(host); - NCR_700_release(host); - return 1; + dev->dev.name); + goto out_put_host; } - host_count++; + + scsi_add_host(host, &dev->dev); return 0; + + out_put_host: + scsi_host_put(host); + out_release_mem_region: + release_mem_region(base, 64); + out_kfree: + kfree(hostdata); + return 1; } +#if 0 static int lasi700_release(struct Scsi_Host *host) { @@ -207,12 +158,12 @@ unregister_parisc_driver(&lasi700_driver); return 1; } +#endif + +static int __init +lasi700_init(void) +{ + return register_parisc_driver(&lasi700_driver); +} -static Scsi_Host_Template driver_template = { - .name = "LASI SCSI 53c700", - .proc_name = "lasi700", - .detect = lasi700_detect, - .release = lasi700_release, - .this_id = 7, -}; -#include "scsi_module.c" +module_init(lasi700_init); diff -Nru a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c --- a/drivers/scsi/mac_esp.c Fri May 9 03:21:35 2003 +++ b/drivers/scsi/mac_esp.c Sun Jun 8 12:18:41 2003 @@ -464,6 +464,16 @@ return chipspresent; } +static int mac_esp_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * I've been wondering what this is supposed to do, for some time. Talking * to Allen Briggs: These machines have an extra register someplace where the @@ -717,8 +727,8 @@ .proc_name = "esp", .name = "Mac 53C9x SCSI", .detect = mac_esp_detect, + .release = mac_esp_release, .info = esp_info, - /* .command = esp_command, */ .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c Tue Jun 3 00:25:23 2003 +++ b/drivers/scsi/megaraid.c Fri Jun 6 02:41:26 2003 @@ -723,7 +723,7 @@ { dma_addr_t prod_info_dma_handle; mega_inquiry3 *inquiry3; - u8 raw_mbox[sizeof(mbox_t)]; + u8 raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int retval; @@ -732,14 +732,14 @@ mbox = (mbox_t *)raw_mbox; memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * Try to issue Inquiry3 command * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and * update enquiry3 structure */ - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; inquiry3 = (mega_inquiry3 *)adapter->mega_buffer; @@ -762,10 +762,10 @@ inq = &ext_inq->raid_inq; - mbox->xferaddr = (u32)dma_handle; + mbox->m_out.xferaddr = (u32)dma_handle; /*issue old 0x04 command to adapter */ - mbox->cmd = MEGA_MBOXCMD_ADPEXTINQ; + mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ; issue_scb_block(adapter, raw_mbox); @@ -790,7 +790,7 @@ &adapter->product_info, sizeof(mega_product_info), PCI_DMA_FROMDEVICE); - mbox->xferaddr = prod_info_dma_handle; + mbox->m_out.xferaddr = prod_info_dma_handle; raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ @@ -1141,10 +1141,10 @@ memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); if( adapter->has_64bit_addr ) { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU64; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } scb->dma_direction = PCI_DMA_FROMDEVICE; @@ -1152,7 +1152,7 @@ pthru->numsgelements = mega_build_sglist(adapter, scb, &pthru->dataxferaddr, &pthru->dataxferlen); - mbox->xferaddr = scb->pthru_dma_addr; + mbox->m_out.xferaddr = scb->pthru_dma_addr; return scb; @@ -1175,19 +1175,19 @@ mbox = (mbox_t *)scb->raw_mbox; memset(mbox, 0, sizeof(scb->raw_mbox)); - mbox->logdrv = ldrv_num; + mbox->m_out.logdrv = ldrv_num; /* * A little hack: 2nd bit is zero for all scsi read * commands and is set for all scsi write commands */ if( adapter->has_64bit_addr ) { - mbox->cmd = (*cmd->cmnd & 0x02) ? + mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE64: MEGA_MBOXCMD_LREAD64 ; } else { - mbox->cmd = (*cmd->cmnd & 0x02) ? + mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? MEGA_MBOXCMD_LWRITE: MEGA_MBOXCMD_LREAD ; } @@ -1196,13 +1196,13 @@ * 6-byte READ(0x08) or WRITE(0x0A) cdb */ if( cmd->cmd_len == 6 ) { - mbox->numsectors = (u32) cmd->cmnd[4]; - mbox->lba = + mbox->m_out.numsectors = (u32) cmd->cmnd[4]; + mbox->m_out.lba = ((u32)cmd->cmnd[1] << 16) | ((u32)cmd->cmnd[2] << 8) | (u32)cmd->cmnd[3]; - mbox->lba &= 0x1FFFFF; + mbox->m_out.lba &= 0x1FFFFF; #if MEGA_HAVE_STATS /* @@ -1213,11 +1213,11 @@ if (*cmd->cmnd == READ_6) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1226,10 +1226,10 @@ * 10-byte READ(0x28) or WRITE(0x2A) cdb */ if( cmd->cmd_len == 10 ) { - mbox->numsectors = + mbox->m_out.numsectors = (u32)cmd->cmnd[8] | ((u32)cmd->cmnd[7] << 8); - mbox->lba = + mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | @@ -1239,11 +1239,11 @@ if (*cmd->cmnd == READ_10) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1252,13 +1252,13 @@ * 12-byte READ(0xA8) or WRITE(0xAA) cdb */ if( cmd->cmd_len == 12 ) { - mbox->lba = + mbox->m_out.lba = ((u32)cmd->cmnd[2] << 24) | ((u32)cmd->cmnd[3] << 16) | ((u32)cmd->cmnd[4] << 8) | (u32)cmd->cmnd[5]; - mbox->numsectors = + mbox->m_out.numsectors = ((u32)cmd->cmnd[6] << 24) | ((u32)cmd->cmnd[7] << 16) | ((u32)cmd->cmnd[8] << 8) | @@ -1268,11 +1268,11 @@ if (*cmd->cmnd == READ_12) { adapter->nreads[ldrv_num%0x80]++; adapter->nreadblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } else { adapter->nwrites[ldrv_num%0x80]++; adapter->nwriteblocks[ldrv_num%0x80] += - mbox->numsectors; + mbox->m_out.numsectors; } #endif } @@ -1288,8 +1288,8 @@ } /* Calculate Scatter-Gather info */ - mbox->numsgelements = mega_build_sglist(adapter, scb, - (u32 *)&mbox->xferaddr, (u32 *)&seg); + mbox->m_out.numsgelements = mega_build_sglist(adapter, scb, + (u32 *)&mbox->m_out.xferaddr, (u32 *)&seg); return scb; @@ -1357,9 +1357,9 @@ epthru = mega_prepare_extpassthru(adapter, scb, cmd, channel, target); - mbox->cmd = MEGA_MBOXCMD_EXTPTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU; - mbox->xferaddr = scb->epthru_dma_addr; + mbox->m_out.xferaddr = scb->epthru_dma_addr; } else { @@ -1369,13 +1369,13 @@ /* Initialize mailbox */ if( adapter->has_64bit_addr ) { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU64; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; } else { - mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; } - mbox->xferaddr = scb->pthru_dma_addr; + mbox->m_out.xferaddr = scb->pthru_dma_addr; } return scb; @@ -1593,20 +1593,21 @@ volatile mbox_t *mbox = adapter->mbox; unsigned int i = 0; - if(unlikely(mbox->busy)) { + if(unlikely(mbox->m_in.busy)) { do { udelay(1); i++; - } while( mbox->busy && (i < max_mbox_busy_wait) ); + } while( mbox->m_in.busy && (i < max_mbox_busy_wait) ); - if(mbox->busy) return -1; + if(mbox->m_in.busy) return -1; } /* Copy mailbox data into host structure */ - memcpy((char *)mbox, (char *)scb->raw_mbox, 16); + memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, + sizeof(struct mbox_out)); - mbox->cmdid = scb->idx; /* Set cmdid */ - mbox->busy = 1; /* Set busy */ + mbox->m_out.cmdid = scb->idx; /* Set cmdid */ + mbox->m_in.busy = 1; /* Set busy */ /* @@ -1614,14 +1615,14 @@ */ atomic_inc(&adapter->pend_cmds); - switch (mbox->cmd) { + switch (mbox->m_out.cmd) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->xferaddr; + mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; + mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; @@ -1634,8 +1635,8 @@ scb->state |= SCB_ISSUED; if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->poll = 0; - mbox->ack = 0; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0; WRINDOOR(adapter, adapter->mbox_dma | 0x1); } else { @@ -1661,24 +1662,23 @@ volatile mbox_t *mbox = adapter->mbox; u8 byte; - raw_mbox[0x1] = 0xFE; /* Set cmdid */ - raw_mbox[0xF] = 1; /* Set busy */ - /* Wait until mailbox is free */ if(mega_busywait_mbox (adapter)) goto bug_blocked_mailbox; /* Copy mailbox data into host structure */ - memcpy((char *) mbox, raw_mbox, 16); + memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out)); + mbox->m_out.cmdid = 0xFE; + mbox->m_in.busy = 1; switch (raw_mbox[0]) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: case MEGA_MBOXCMD_PASSTHRU64: case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->xferaddr; + mbox64->xfer_segment_lo = mbox->m_out.xferaddr; mbox64->xfer_segment_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; + mbox->m_out.xferaddr = 0xFFFFFFFF; break; default: mbox64->xfer_segment_lo = 0; @@ -1686,22 +1686,22 @@ } if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->poll = 0; - mbox->ack = 0; - mbox->numstatus = 0xFF; - mbox->status = 0xFF; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0; + mbox->m_in.numstatus = 0xFF; + mbox->m_in.status = 0xFF; WRINDOOR(adapter, adapter->mbox_dma | 0x1); - while((volatile u8)mbox->numstatus == 0xFF) + while((volatile u8)mbox->m_in.numstatus == 0xFF) cpu_relax(); - mbox->numstatus = 0xFF; + mbox->m_in.numstatus = 0xFF; - while( (volatile u8)mbox->poll != 0x77 ) + while( (volatile u8)mbox->m_in.poll != 0x77 ) cpu_relax(); - mbox->poll = 0; - mbox->ack = 0x77; + mbox->m_in.poll = 0; + mbox->m_in.ack = 0x77; WRINDOOR(adapter, adapter->mbox_dma | 0x2); @@ -1720,7 +1720,7 @@ irq_ack(adapter); } - return mbox->status; + return mbox->m_in.status; bug_blocked_mailbox: printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n"); @@ -1767,19 +1767,20 @@ } set_irq_state(adapter, byte); - while((nstatus = (volatile u8)adapter->mbox->numstatus) + while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) cpu_relax(); - adapter->mbox->numstatus = 0xFF; + adapter->mbox->m_in.numstatus = 0xFF; - status = adapter->mbox->status; + status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); - memcpy(completed, (void *)adapter->mbox->completed, nstatus); + memcpy(completed, (void *)adapter->mbox->m_in.completed, + nstatus); /* Acknowledge interrupt */ irq_ack(adapter); @@ -1843,20 +1844,21 @@ } WROUTDOOR(adapter, 0x10001234); - while((nstatus = (volatile u8)adapter->mbox->numstatus) + while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) == 0xFF) { cpu_relax(); } - adapter->mbox->numstatus = 0xFF; + adapter->mbox->m_in.numstatus = 0xFF; - status = adapter->mbox->status; + status = adapter->mbox->m_in.status; /* * decrement the pending queue counter */ atomic_sub(nstatus, &adapter->pend_cmds); - memcpy(completed, (void *)adapter->mbox->completed, nstatus); + memcpy(completed, (void *)adapter->mbox->m_in.completed, + nstatus); /* Acknowledge interrupt */ WRINDOOR(adapter, 0x2); @@ -1986,7 +1988,7 @@ #if MEGA_HAVE_STATS { - int logdrv = mbox->logdrv; + int logdrv = mbox->m_out.logdrv; islogical = adapter->logdrv_chan[cmd->channel]; /* @@ -2065,8 +2067,8 @@ SCSI_STATUS_CHECK_CONDITION */ /* set sense_buffer and result fields */ - if( mbox->cmd == MEGA_MBOXCMD_PASSTHRU || - mbox->cmd == MEGA_MBOXCMD_PASSTHRU64 ) { + if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU || + mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) { memcpy(cmd->sense_buffer, pthru->reqsensearea, 14); @@ -2076,7 +2078,7 @@ (CHECK_CONDITION << 1); } else { - if (mbox->cmd == MEGA_MBOXCMD_EXTPTHRU) { + if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) { memcpy(cmd->sense_buffer, epthru->reqsensearea, 14); @@ -2233,7 +2235,7 @@ static inline int mega_busywait_mbox (adapter_t *adapter) { - if (adapter->mbox->busy) + if (adapter->mbox->m_in.busy) return __mega_busywait_mbox(adapter); return 0; } @@ -2245,7 +2247,7 @@ long counter; for (counter = 0; counter < 10000; counter++) { - if (!mbox->busy) + if (!mbox->m_in.busy) return 0; udelay(100); yield(); } @@ -2400,7 +2402,7 @@ { adapter_t *adapter; mbox_t *mbox; - u_char raw_mbox[sizeof(mbox_t)]; + u_char raw_mbox[sizeof(struct mbox_out)]; char buf[12] = { 0 }; adapter = (adapter_t *)host->hostdata; @@ -2409,7 +2411,7 @@ printk(KERN_NOTICE "megaraid: being unloaded..."); /* Flush adapter cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -2419,7 +2421,7 @@ issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_SYSTEM; /* Issue a blocking (interrupts disabled) command to the card */ @@ -2569,35 +2571,6 @@ return buffer; } -volatile static int internal_done_flag = 0; -volatile static int internal_done_errcode = 0; - -static DECLARE_WAIT_QUEUE_HEAD (internal_wait); - -static void internal_done (Scsi_Cmnd *cmd) -{ - internal_done_errcode = cmd->result; - internal_done_flag++; - wake_up (&internal_wait); -} - -/* shouldn't be used, but included for completeness */ - -static int -megaraid_command (Scsi_Cmnd *cmd) -{ - internal_done_flag = 0; - - /* Queue command, and wait until it has completed */ - megaraid_queue (cmd, internal_done); - - while (!internal_done_flag) - interruptible_sleep_on (&internal_wait); - - return internal_done_errcode; -} - - /* * Abort a previous SCSI request. Only commands on the pending list can be * aborted. All the commands issued to the F/W must complete. @@ -2979,16 +2952,24 @@ int len = 0; len = sprintf(page, "Contents of Mail Box Structure\n"); - len += sprintf(page+len, " Fw Command = 0x%02x\n", mbox->cmd); - len += sprintf(page+len, " Cmd Sequence = 0x%02x\n", mbox->cmdid); - len += sprintf(page+len, " No of Sectors= %04d\n", mbox->numsectors); - len += sprintf(page+len, " LBA = 0x%02x\n", mbox->lba); - len += sprintf(page+len, " DTA = 0x%08x\n", mbox->xferaddr); - len += sprintf(page+len, " Logical Drive= 0x%02x\n", mbox->logdrv); + len += sprintf(page+len, " Fw Command = 0x%02x\n", + mbox->m_out.cmd); + len += sprintf(page+len, " Cmd Sequence = 0x%02x\n", + mbox->m_out.cmdid); + len += sprintf(page+len, " No of Sectors= %04d\n", + mbox->m_out.numsectors); + len += sprintf(page+len, " LBA = 0x%02x\n", + mbox->m_out.lba); + len += sprintf(page+len, " DTA = 0x%08x\n", + mbox->m_out.xferaddr); + len += sprintf(page+len, " Logical Drive= 0x%02x\n", + mbox->m_out.logdrv); len += sprintf(page+len, " No of SG Elmt= 0x%02x\n", - mbox->numsgelements); - len += sprintf(page+len, " Busy = %01x\n", mbox->busy); - len += sprintf(page+len, " Status = 0x%02x\n", mbox->status); + mbox->m_out.numsgelements); + len += sprintf(page+len, " Busy = %01x\n", + mbox->m_in.busy); + len += sprintf(page+len, " Status = 0x%02x\n", + mbox->m_in.status); *eof = 1; @@ -3881,7 +3862,7 @@ { adapter_t *adapter; struct Scsi_Host *host; - u8 raw_mbox[sizeof(mbox_t)]; + u8 raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int i,j; @@ -3897,7 +3878,7 @@ mbox = (mbox_t *)raw_mbox; /* Flush adapter cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -3910,7 +3891,7 @@ issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = FLUSH_SYSTEM; issue_scb_block(adapter, raw_mbox); @@ -4643,17 +4624,17 @@ static int mega_is_bios_enabled(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int ret; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; raw_mbox[0] = IS_BIOS_ENABLED; raw_mbox[2] = GET_BIOS; @@ -4676,13 +4657,13 @@ static void mega_enum_raid_scsi(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int i; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command to find out what channels are raid/scsi @@ -4692,7 +4673,7 @@ memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; /* * Non-ROMB firware fail this command, so all channels @@ -4731,7 +4712,7 @@ mega_get_boot_drv(adapter_t *adapter) { struct private_bios_data *prv_bios_data; - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; u16 cksum = 0; u8 *cksum_p; @@ -4740,14 +4721,14 @@ mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(raw_mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); raw_mbox[0] = BIOS_PVT_DATA; raw_mbox[2] = GET_BIOS_PVT_DATA; memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; adapter->boot_ldrv_enabled = 0; adapter->boot_ldrv = 0; @@ -4797,13 +4778,13 @@ static int mega_support_random_del(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int rval; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command @@ -4826,13 +4807,13 @@ static int mega_support_ext_cdb(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; int rval; mbox = (mbox_t *)raw_mbox; - memset(mbox, 0, sizeof(*mbox)); + memset(&mbox->m_out, 0, sizeof(raw_mbox)); /* * issue command to find out if controller supports extended CDBs. */ @@ -4944,7 +4925,7 @@ static void mega_get_max_sgl(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -4953,7 +4934,7 @@ memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; raw_mbox[0] = MAIN_MISC_OPCODE; raw_mbox[2] = GET_MAX_SG_SUPPORT; @@ -4989,7 +4970,7 @@ static int mega_support_cluster(adapter_t *adapter) { - unsigned char raw_mbox[sizeof(mbox_t)]; + unsigned char raw_mbox[sizeof(struct mbox_out)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -4998,7 +4979,7 @@ memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - mbox->xferaddr = (u32)adapter->buf_dma_handle; + mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; /* * Try to get the initiator id. This command will succeed iff the @@ -5367,7 +5348,6 @@ .detect = megaraid_detect, .release = megaraid_release, .info = megaraid_info, - .command = megaraid_command, .queuecommand = megaraid_queue, .bios_param = megaraid_biosparam, .max_sectors = MAX_SECTORS_PER_IO, diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h --- a/drivers/scsi/megaraid.h Mon May 12 07:26:13 2003 +++ b/drivers/scsi/megaraid.h Fri Jun 6 02:33:13 2003 @@ -120,8 +120,7 @@ #define NVIRT_CHAN 4 /* # of virtual channels to represent up to 60 logical drives */ - -typedef struct { +struct mbox_out { /* 0x0 */ u8 cmd; /* 0x1 */ u8 cmdid; /* 0x2 */ u16 numsectors; @@ -130,12 +129,20 @@ /* 0xC */ u8 logdrv; /* 0xD */ u8 numsgelements; /* 0xE */ u8 resvd; +} __attribute__ ((packed)); + +struct mbox_in { /* 0xF */ volatile u8 busy; /* 0x10 */ volatile u8 numstatus; /* 0x11 */ volatile u8 status; /* 0x12 */ volatile u8 completed[MAX_FIRMWARE_STATUS]; volatile u8 poll; volatile u8 ack; +} __attribute__ ((packed)); + +typedef struct { + struct mbox_out m_out; + struct mbox_in m_in; } __attribute__ ((packed)) mbox_t; typedef struct { @@ -1001,7 +1008,6 @@ static void mega_free_scb(adapter_t *, scb_t *); static int megaraid_release (struct Scsi_Host *); -static int megaraid_command (Scsi_Cmnd *); static int megaraid_abort(Scsi_Cmnd *); static int megaraid_reset(Scsi_Cmnd *); static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int); diff -Nru a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c --- a/drivers/scsi/mesh.c Wed Apr 23 06:09:26 2003 +++ b/drivers/scsi/mesh.c Sun Jun 8 12:18:41 2003 @@ -2047,11 +2047,8 @@ .name = "MESH", .detect = mesh_detect, .release = mesh_release, - .command = NULL, .queuecommand = mesh_queue, .eh_abort_handler = mesh_abort, - .eh_device_reset_handler = NULL, - .eh_bus_reset_handler = NULL, .eh_host_reset_handler = mesh_host_reset, .can_queue = 20, .this_id = 7, diff -Nru a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c --- a/drivers/scsi/mvme16x.c Wed Nov 20 03:36:31 2002 +++ b/drivers/scsi/mvme16x.c Mon Jun 2 17:27:45 2003 @@ -53,9 +53,22 @@ return 1; } +static int mvme16x_scsi_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "MVME16x NCR53c710 SCSI", .detect = mvme16x_scsi_detect, + .release = mvme16x_scsi_release, .queuecommand = NCR53c7xx_queue_command, .abort = NCR53c7xx_abort, .reset = NCR53c7xx_reset, diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c --- a/drivers/scsi/nsp32.c Tue May 27 07:52:55 2003 +++ b/drivers/scsi/nsp32.c Mon Jun 2 17:42:21 2003 @@ -1621,7 +1621,7 @@ /* * register this HBA as SCSI device */ - host = scsi_register(&nsp32_template, sizeof(nsp32_hw_data)); + host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data)); if (host == NULL) { nsp32_msg (KERN_ERR, "failed to scsi register"); goto err; @@ -1840,7 +1840,7 @@ kfree(data->lunt_list); scsi_unregister: - scsi_unregister(host); + scsi_host_put(host); err: return 1; diff -Nru a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c --- a/drivers/scsi/pas16.c Sun May 4 02:56:44 2003 +++ b/drivers/scsi/pas16.c Mon Jun 2 17:27:44 2003 @@ -600,9 +600,22 @@ #include "NCR5380.c" +static int pas16_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static Scsi_Host_Template driver_template = { .name = "Pro Audio Spectrum-16 SCSI", .detect = pas16_detect, + .release = pas16_release, .queuecommand = pas16_queue_command, .eh_abort_handler = pas16_abort, .eh_bus_reset_handler = pas16_bus_reset, diff -Nru a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c --- a/drivers/scsi/pci2000.c Mon Jun 9 16:05:35 2003 +++ b/drivers/scsi/pci2000.c Wed Jun 11 20:06:30 2003 @@ -612,41 +612,6 @@ return 0; } /**************************************************************** - * Name: internal_done :LOCAL - * - * Description: Done handler for non-queued commands - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Nothing. - * - ****************************************************************/ -static void internal_done (Scsi_Cmnd * SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Pci2000_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Pci2000_Command (Scsi_Cmnd *SCpnt) - { - DEB(printk("pci2000_command: ..calling pci2000_queuecommand\n")); - - Pci2000_QueueCommand (SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } -/**************************************************************** * Name: Pci2000_Detect * * Description: Detect and initialize our boards. @@ -856,7 +821,6 @@ .name = "PCI-2000 SCSI Intelligent Disk Controller", .detect = Pci2000_Detect, .release = Pci2000_Release, - .command = Pci2000_Command, .queuecommand = Pci2000_QueueCommand, .abort = Pci2000_Abort, .reset = Pci2000_Reset, diff -Nru a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c --- a/drivers/scsi/pci2220i.c Mon Jun 9 16:06:04 2003 +++ b/drivers/scsi/pci2220i.c Wed Jun 11 20:06:31 2003 @@ -2307,28 +2307,6 @@ } return 0; } -static void internal_done(Scsi_Cmnd *SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Pci2220i_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Pci2220i_Command (Scsi_Cmnd *SCpnt) - { - Pci2220i_QueueCommand (SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } /**************************************************************** * Name: ReadFlash * @@ -2924,7 +2902,6 @@ .name = "PCI-2220I/PCI-2240I", .detect = Pci2220i_Detect, .release = Pci2220i_Release, - .command = Pci2220i_Command, .queuecommand = Pci2220i_QueueCommand, .abort = Pci2220i_Abort, .reset = Pci2220i_Reset, diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c Mon May 12 08:14:55 2003 +++ b/drivers/scsi/pcmcia/nsp_cs.c Mon Jun 2 17:42:21 2003 @@ -1222,7 +1222,7 @@ DEBUG(0, "%s: this_id=%d\n", __FUNCTION__, sht->this_id); request_region(data->BaseAddress, data->NumAddress, "nsp_cs"); - host = scsi_register(sht, 0); + host = scsi_host_alloc(sht, 0); if(host == NULL) return NULL; diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c Tue May 27 08:56:01 2003 +++ b/drivers/scsi/ppa.c Sun Jun 8 12:18:41 2003 @@ -103,7 +103,6 @@ .name = "Iomega VPI0 (ppa) interface", .detect = ppa_detect, .release = ppa_release, - .command = ppa_command, .queuecommand = ppa_queuecommand, .eh_abort_handler = ppa_abort, .eh_bus_reset_handler = ppa_reset, @@ -759,39 +758,6 @@ return 0; } return 1; /* FINISH_RETURN */ -} - -/* deprecated synchronous interface */ -int ppa_command(Scsi_Cmnd * cmd) -{ - static int first_pass = 1; - int host_no = cmd->device->host->unique_id; - - if (first_pass) { - printk("ppa: using non-queuing interface\n"); - first_pass = 0; - } - if (ppa_hosts[host_no].cur_cmd) { - printk("PPA: bug in ppa_command\n"); - return 0; - } - ppa_hosts[host_no].failed = 0; - ppa_hosts[host_no].jstart = jiffies; - ppa_hosts[host_no].cur_cmd = cmd; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; - - ppa_pb_claim(host_no); - - while (ppa_engine(&ppa_hosts[host_no], cmd)) - schedule(); - - if (cmd->SCp.phase) /* Only disconnect if we have connected */ - ppa_disconnect(cmd->device->host->unique_id); - - ppa_pb_release(host_no); - ppa_hosts[host_no].cur_cmd = 0; - return cmd->result; } /* diff -Nru a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c --- a/drivers/scsi/psi240i.c Sun May 4 02:56:45 2003 +++ b/drivers/scsi/psi240i.c Sun Jun 8 12:18:41 2003 @@ -496,31 +496,6 @@ return 0; } -static void internal_done(Scsi_Cmnd * SCpnt) - { - SCpnt->SCp.Status++; - } -/**************************************************************** - * Name: Psi240i_Command - * - * Description: Process a command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * - * Returns: Status code. - * - ****************************************************************/ -int Psi240i_Command (Scsi_Cmnd *SCpnt) - { - DEB(printk("psi240i_command: ..calling psi240i_queuecommand\n")); - - Psi240i_QueueCommand (SCpnt, internal_done); - - SCpnt->SCp.Status = 0; - while (!SCpnt->SCp.Status) - barrier (); - return SCpnt->result; - } /*************************************************************************** * Name: ReadChipMemory * @@ -655,6 +630,17 @@ } return count; } + +static int Psi240i_Release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /**************************************************************** * Name: Psi240i_Abort * @@ -722,7 +708,7 @@ .proc_name = "psi240i", .name = "PSI-240I EIDE Disk Controller", .detect = Psi240i_Detect, - .command = Psi240i_Command, + .release = Psi240i_Release, .queuecommand = Psi240i_QueueCommand, .abort = Psi240i_Abort, .reset = Psi240i_Reset, diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c --- a/drivers/scsi/qlogicfas.c Sat Apr 26 07:28:27 2003 +++ b/drivers/scsi/qlogicfas.c Sun Jun 8 12:18:41 2003 @@ -544,46 +544,6 @@ #if QL_USE_IRQ -static void qlidone(Scsi_Cmnd * cmd) -{ -} /* null function */ - -#endif - -/* - * Synchronous command processing - */ - -static int qlogicfas_command(Scsi_Cmnd * cmd) -{ - int k; -#if QL_USE_IRQ - if (qlirq >= 0) { - qlogicfas_queuecommand(cmd, qlidone); - while (qlcmd != NULL) - { - cpu_relax(); - barrier(); - } - return cmd->result; - } -#endif - - /* - * Non-irq version - */ - - if (cmd->device->id == qinitid) - return (DID_BAD_TARGET << 16); - ql_icmd(cmd); - if ((k = ql_wai())) - return (k << 16); - return ql_pcmd(cmd); - -} - -#if QL_USE_IRQ - /* * Queued command */ @@ -739,6 +699,18 @@ return (__qlogicfas_detect(sht) != NULL); } +static int qlogicfas_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * Return bios parameters */ @@ -826,8 +798,8 @@ .name = "qlogicfas", .proc_name = "qlogicfas", .detect = qlogicfas_detect, + .release = qlogicfas_release, .info = qlogicfas_info, - .command = qlogicfas_command, .queuecommand = qlogicfas_queuecommand, .eh_abort_handler = qlogicfas_abort, .eh_bus_reset_handler = qlogicfas_bus_reset, diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Mon May 26 02:50:43 2003 +++ b/drivers/scsi/scsi.c Sun Jun 8 13:31:57 2003 @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -82,7 +83,6 @@ * Data declarations. */ unsigned long scsi_pid; -struct scsi_cmnd *last_cmnd; static unsigned long serial_number; /* @@ -108,26 +108,6 @@ "Enclosure ", }; -MODULE_PARM(scsi_logging_level, "i"); -MODULE_PARM_DESC(scsi_logging_level, "SCSI logging level; should be zero or nonzero"); - -#ifndef MODULE -static int __init scsi_logging_setup(char *str) -{ - int tmp; - - if (get_option(&str, &tmp) == 1) { - scsi_logging_level = (tmp ? ~0 : 0); - return 1; - } else { - printk(KERN_INFO "scsi_logging_setup : usage scsi_logging_level=n " - "(n should be 0 or non-zero)\n"); - return 0; - } -} -__setup("scsi_logging=", scsi_logging_setup); -#endif - /* * Function: scsi_allocate_request * @@ -460,29 +440,18 @@ goto out; } - if (host->can_queue) { - SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", - host->hostt->queuecommand)); + SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n", + host->hostt->queuecommand)); - spin_lock_irqsave(host->host_lock, flags); - rtn = host->hostt->queuecommand(cmd, scsi_done); - spin_unlock_irqrestore(host->host_lock, flags); - if (rtn) { - scsi_queue_insert(cmd, + spin_lock_irqsave(host->host_lock, flags); + rtn = host->hostt->queuecommand(cmd, scsi_done); + spin_unlock_irqrestore(host->host_lock, flags); + if (rtn) { + scsi_queue_insert(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ? - rtn : SCSI_MLQUEUE_HOST_BUSY); - SCSI_LOG_MLQUEUE(3, - printk("queuecommand : request rejected\n")); - } - } else { - SCSI_LOG_MLQUEUE(3, printk("command() : routine at %p\n", - host->hostt->command)); - - spin_lock_irqsave(host->host_lock, flags); - cmd->result = host->hostt->command(cmd); - scsi_done(cmd); - spin_unlock_irqrestore(host->host_lock, flags); - rtn = 0; + rtn : SCSI_MLQUEUE_HOST_BUSY); + SCSI_LOG_MLQUEUE(3, + printk("queuecommand : request rejected\n")); } out: @@ -752,16 +721,8 @@ struct scsi_device *sdev = cmd->device; struct Scsi_Host *shost = sdev->host; struct scsi_request *sreq; - unsigned long flags; - scsi_host_busy_dec_and_test(shost, sdev); - - /* - * XXX(hch): We really want a nice helper for this.. - */ - spin_lock_irqsave(&sdev->sdev_lock, flags); - sdev->device_busy--; - spin_unlock_irqrestore(&sdev->sdev_lock, flags); + scsi_device_unbusy(sdev); /* * Clear the flags which say that the device/host is no longer @@ -983,6 +944,9 @@ MODULE_DESCRIPTION("SCSI core"); MODULE_LICENSE("GPL"); +module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels"); + static int __init init_scsi(void) { int error, i; @@ -1003,7 +967,6 @@ for (i = 0; i < NR_CPUS; i++) INIT_LIST_HEAD(&done_q[i]); - scsi_host_init(); devfs_mk_dir("scsi"); open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL); printk(KERN_NOTICE "SCSI subsystem initialized\n"); diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Mon May 26 02:50:43 2003 +++ b/drivers/scsi/scsi.h Sun Jun 8 15:03:00 2003 @@ -16,6 +16,12 @@ #define _SCSI_H #include /* for CONFIG_SCSI_LOGGING */ + +#include +#include +#include +#include +#include #include /* @@ -112,19 +118,6 @@ #define SOFT_ERROR 0x2005 #define ADD_TO_MLQUEUE 0x2006 -/* - * These are the values that scsi_cmd->state can take. - */ -#define SCSI_STATE_TIMEOUT 0x1000 -#define SCSI_STATE_FINISHED 0x1001 -#define SCSI_STATE_FAILED 0x1002 -#define SCSI_STATE_QUEUED 0x1003 -#define SCSI_STATE_UNUSED 0x1006 -#define SCSI_STATE_DISCONNECTING 0x1008 -#define SCSI_STATE_INITIALIZING 0x1009 -#define SCSI_STATE_BHQUEUE 0x100a -#define SCSI_STATE_MLQUEUE 0x100b - #define IDENTIFY_BASE 0x80 #define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ ((can_disconnect) ? 0x40 : 0) |\ @@ -169,9 +162,6 @@ #define DRIVER_MASK 0x0f #define SUGGEST_MASK 0xf0 -#define MAX_COMMAND_SIZE 16 -#define SCSI_SENSE_BUFFERSIZE 64 - /* * SCSI command sets */ @@ -204,96 +194,20 @@ #define ASKED_FOR_SENSE 0x20 #define SYNC_RESET 0x40 -/* - * This specifies "machine infinity" for host templates which don't - * limit the transfer size. Note this limit represents an absolute - * maximum, and may be over the transfer limits allowed for individual - * devices (e.g. 256 for SCSI-1) - */ -#define SCSI_DEFAULT_MAX_SECTORS 1024 - -/* - * This is the crap from the old error handling code. We have it in a special - * place so that we can more easily delete it later on. - */ -#include "scsi_obsolete.h" - -/* - * Forward-declaration of structs for prototypes. - */ struct Scsi_Host; +struct scsi_cmnd; +struct scsi_device; struct scsi_target; struct scatterlist; /* - * Add some typedefs so that we can prototyope a bunch of the functions. - */ -typedef struct scsi_device Scsi_Device; -typedef struct scsi_cmnd Scsi_Cmnd; -typedef struct scsi_request Scsi_Request; - -/* - * These are the error handling functions defined in scsi_error.c - */ -extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, - void (*complete) (Scsi_Cmnd *)); -extern int scsi_delete_timer(Scsi_Cmnd * SCset); -extern int scsi_block_when_processing_errors(Scsi_Device *); -extern void scsi_sleep(int); - -/* - * Prototypes for functions in scsicam.c - */ -extern int scsi_partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, - unsigned int *secs); - -/* - * Prototypes for functions in scsi_lib.c - */ -extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, - int block_sectors); - -/* - * Prototypes for functions in scsi.c - */ -extern struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int flags); -extern void scsi_put_command(struct scsi_cmnd *cmd); -extern void scsi_adjust_queue_depth(Scsi_Device *, int, int); -extern int scsi_track_queue_full(Scsi_Device *, int); -extern int scsi_device_get(struct scsi_device *); -extern void scsi_device_put(struct scsi_device *); -extern void scsi_set_device_offline(struct scsi_device *); - -/* - * Newer request-based interfaces. - */ -extern Scsi_Request *scsi_allocate_request(Scsi_Device *); -extern void scsi_release_request(Scsi_Request *); -extern void scsi_wait_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - int timeout, int retries); -extern void scsi_do_req(Scsi_Request *, const void *cmnd, - void *buffer, unsigned bufflen, - void (*done) (struct scsi_cmnd *), - int timeout, int retries); - -/* - * Prototypes for functions in scsi_scan.c - */ -extern struct scsi_device *scsi_add_device(struct Scsi_Host *, - uint, uint, uint); -extern int scsi_remove_device(struct scsi_device *); -extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); - -/* * Prototypes for functions in constants.c * Some of these used to live in constants.h */ -extern void print_Scsi_Cmnd (Scsi_Cmnd *); +extern void print_Scsi_Cmnd(struct scsi_cmnd *); extern void print_command(unsigned char *); -extern void print_sense(const char *, Scsi_Cmnd *); -extern void print_req_sense(const char *, Scsi_Request *); +extern void print_sense(const char *, struct scsi_cmnd *); +extern void print_req_sense(const char *, struct scsi_request *); extern void print_driverbyte(int scsiresult); extern void print_hostbyte(int scsiresult); extern void print_status(unsigned char status); @@ -301,286 +215,6 @@ extern const char *scsi_sense_key_string(unsigned char); extern const char *scsi_extd_sense_format(unsigned char, unsigned char); - -/* - * The scsi_device struct contains what we know about each given scsi - * device. - * - * FIXME(eric) - One of the great regrets that I have is that I failed to - * define these structure elements as something like sdev_foo instead of foo. - * This would make it so much easier to grep through sources and so forth. - * I propose that all new elements that get added to these structures follow - * this convention. As time goes on and as people have the stomach for it, - * it should be possible to go back and retrofit at least some of the elements - * here with with the prefix. - */ - -struct scsi_device { - struct class_device sdev_classdev; - /* - * This information is private to the scsi mid-layer. - */ - struct list_head siblings; /* list of all devices on this host */ - struct list_head same_target_siblings; /* just the devices sharing same target id */ - struct Scsi_Host *host; - request_queue_t *request_queue; - volatile unsigned short device_busy; /* commands actually active on low-level */ - spinlock_t sdev_lock; /* also the request queue_lock */ - spinlock_t list_lock; - struct list_head cmd_list; /* queue of in use SCSI Command structures */ - struct list_head starved_entry; - Scsi_Cmnd *current_cmnd; /* currently active command */ - unsigned short queue_depth; /* How deep of a queue we want */ - unsigned short last_queue_full_depth; /* These two are used by */ - unsigned short last_queue_full_count; /* scsi_track_queue_full() */ - unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same - jiffie count on our counter, they - could all be from the same event. */ - - unsigned int id, lun, channel; - - unsigned int manufacturer; /* Manufacturer of device, for using - * vendor-specific cmd's */ - unsigned sector_size; /* size in bytes */ - - int access_count; /* Count of open channels/mounts */ - - void *hostdata; /* available to low-level driver */ - char devfs_name[256]; /* devfs junk */ - char type; - char scsi_level; - unsigned char inquiry_len; /* valid bytes in 'inquiry' */ - unsigned char * inquiry; /* INQUIRY response data */ - char * vendor; /* [back_compat] point into 'inquiry' ... */ - char * model; /* ... after scan; point to static string */ - char * rev; /* ... "nullnullnullnull" before scan */ - unsigned char current_tag; /* current tag */ -// unsigned char sync_min_period; /* Not less than this period */ -// unsigned char sync_max_offset; /* Not greater than this offset */ - struct scsi_target *sdev_target; /* used only for single_lun */ - - unsigned online:1; - unsigned writeable:1; - unsigned removable:1; - unsigned random:1; - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ - unsigned locked:1; /* Media removal disabled */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned disconnect:1; /* can disconnect */ - unsigned soft_reset:1; /* Uses soft reset option */ - unsigned sdtr:1; /* Device supports SDTR messages */ - unsigned wdtr:1; /* Device supports WDTR messages */ - unsigned ppr:1; /* Device supports PPR messages */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ - unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags - instead!!! Please fix your driver now!! */ - unsigned simple_tags:1; /* simple queue tag messages are enabled */ - unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ - unsigned single_lun:1; /* Indicates we should only allow I/O to - * one of the luns for the device at a - * time. */ - unsigned was_reset:1; /* There was a bus reset on the bus for - * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned use_10_for_rw:1; /* first try 10-byte read / write */ - unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ - unsigned remap:1; /* support remapping */ -// unsigned sync:1; /* Sync transfer state, managed by host */ -// unsigned wide:1; /* WIDE transfer state, managed by host */ - unsigned no_start_on_add:1; /* do not issue start on add */ - - unsigned int device_blocked; /* Device returned QUEUE_FULL. */ - - unsigned int max_device_blocked; /* what device_blocked counts down from */ - /* default value if the device doesn't override */ - #define SCSI_DEFAULT_DEVICE_BLOCKED 3 - - struct device sdev_driverfs_dev; -}; -#define to_scsi_device(d) \ - container_of(d, struct scsi_device, sdev_driverfs_dev) - - -typedef struct scsi_pointer { - char *ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - dma_addr_t dma_handle; - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -} Scsi_Pointer; - -/* - * This is essentially a slimmed down version of Scsi_Cmnd. The point of - * having this is that requests that are injected into the queue as result - * of things like ioctls and character devices shouldn't be using a - * Scsi_Cmnd until such a time that the command is actually at the head - * of the queue and being sent to the driver. - */ -struct scsi_request { - int sr_magic; - int sr_result; /* Status code from lower level driver */ - unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - struct Scsi_Host *sr_host; - Scsi_Device *sr_device; - Scsi_Cmnd *sr_command; - struct request *sr_request; /* A copy of the command we are - working on */ - unsigned sr_bufflen; /* Size of data buffer */ - void *sr_buffer; /* Data buffer */ - int sr_allowed; - unsigned char sr_data_direction; - unsigned char sr_cmd_len; - unsigned char sr_cmnd[MAX_COMMAND_SIZE]; - void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ - int sr_timeout_per_command; - unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ - unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ - unsigned sr_underflow; /* Return error if less than - this amount is transferred */ - void * upper_private_data; /* reserved for owner (usually upper - level driver) of this request */ -}; - -/* - * FIXME(eric) - one of the great regrets that I have is that I failed to - * define these structure elements as something like sc_foo instead of foo. - * This would make it so much easier to grep through sources and so forth. - * I propose that all new elements that get added to these structures follow - * this convention. As time goes on and as people have the stomach for it, - * it should be possible to go back and retrofit at least some of the elements - * here with with the prefix. - */ -struct scsi_cmnd { - int sc_magic; - - struct scsi_device *device; - unsigned short state; - unsigned short owner; - Scsi_Request *sc_request; - - struct list_head list; /* scsi_cmnd participates in queue lists */ - - struct list_head eh_entry; /* entry for the host eh_cmd_q */ - int eh_state; /* Used for state tracking in error handlr */ - int eh_eflags; /* Used by error handlr */ - void (*done) (struct scsi_cmnd *); /* Mid-level done function */ - /* - A SCSI Command is assigned a nonzero serial_number when internal_cmnd - passes it to the driver's queue command function. The serial_number - is cleared when scsi_done is entered indicating that the command has - been completed. If a timeout occurs, the serial number at the moment - of timeout is copied into serial_number_at_timeout. By subsequently - comparing the serial_number and serial_number_at_timeout fields - during abort or reset processing, we can detect whether the command - has already completed. This also detects cases where the command has - completed and the SCSI Command structure has already being reused - for another command, so that we can avoid incorrectly aborting or - resetting the new command. - */ - - unsigned long serial_number; - unsigned long serial_number_at_timeout; - - int retries; - int allowed; - int timeout_per_command; - int timeout_total; - int timeout; - - /* - * We handle the timeout differently if it happens when a reset, - * abort, etc are in process. - */ - unsigned volatile char internal_timeout; - - unsigned char cmd_len; - unsigned char old_cmd_len; - unsigned char sc_data_direction; - unsigned char sc_old_data_direction; - - /* These elements define the operation we are about to perform */ - unsigned char cmnd[MAX_COMMAND_SIZE]; - unsigned request_bufflen; /* Actual request size */ - - struct timer_list eh_timeout; /* Used to time out the command. */ - void *request_buffer; /* Actual requested buffer */ - - /* These elements define the operation we ultimately want to perform */ - unsigned char data_cmnd[MAX_COMMAND_SIZE]; - unsigned short old_use_sg; /* We save use_sg here when requesting - * sense info */ - unsigned short use_sg; /* Number of pieces of scatter-gather */ - unsigned short sglist_len; /* size of malloc'd scatter-gather list */ - unsigned short abort_reason; /* If the mid-level code requests an - * abort, this is the reason. */ - unsigned bufflen; /* Size of data buffer */ - void *buffer; /* Data buffer */ - - unsigned underflow; /* Return error if less than - this amount is transferred */ - unsigned old_underflow; /* save underflow here when reusing the - * command for error handling */ - - unsigned transfersize; /* How much we are guaranteed to - transfer with each SCSI transfer - (ie, between disconnect / - reconnects. Probably == sector - size */ - - int resid; /* Number of bytes requested to be - transferred less actual number - transferred (0 if not supported) */ - - struct request *request; /* The command we are - working on */ - - unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE - * when CHECK CONDITION is - * received on original command - * (auto-sense) */ - - unsigned flags; - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done) (struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - - Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char *host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ - - int result; /* Status code from lower level driver */ - - unsigned char tag; /* SCSI-II queued command tag */ - unsigned long pid; /* Process ID, starts at 0 */ -}; - /* * Definitions and prototypes used for scsi mid-level queue. */ @@ -588,104 +222,18 @@ #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 #define SCSI_MLQUEUE_EH_RETRY 0x1057 -/* - * Reset request from external source - */ -#define SCSI_TRY_RESET_DEVICE 1 -#define SCSI_TRY_RESET_BUS 2 -#define SCSI_TRY_RESET_HOST 3 - -extern int scsi_reset_provider(Scsi_Device *, int); - -#define MSG_SIMPLE_TAG 0x20 -#define MSG_HEAD_TAG 0x21 -#define MSG_ORDERED_TAG 0x22 - -#define SCSI_NO_TAG (-1) /* identify no tag in use */ - -/** - * scsi_activate_tcq - turn on tag command queueing - * @SDpnt: device to turn on TCQ for - * @depth: queue depth - * - * Notes: - * Eventually, I hope depth would be the maximum depth - * the device could cope with and the real queue depth - * would be adjustable from 0 to depth. - **/ -static inline void scsi_activate_tcq(Scsi_Device *SDpnt, int depth) { - if(SDpnt->tagged_supported) { - if(!blk_queue_tagged(SDpnt->request_queue)) - blk_queue_init_tags(SDpnt->request_queue, depth); - scsi_adjust_queue_depth(SDpnt, MSG_ORDERED_TAG, depth); - } -} - -/** - * scsi_deactivate_tcq - turn off tag command queueing - * @SDpnt: device to turn off TCQ for - **/ -static inline void scsi_deactivate_tcq(Scsi_Device *SDpnt, int depth) { - if(blk_queue_tagged(SDpnt->request_queue)) - blk_queue_free_tags(SDpnt->request_queue); - scsi_adjust_queue_depth(SDpnt, 0, depth); -} - -/** - * scsi_populate_tag_msg - place a tag message in a buffer - * @SCpnt: pointer to the Scsi_Cmnd for the tag - * @msg: pointer to the area to place the tag - * - * Notes: - * designed to create the correct type of tag message for the - * particular request. Returns the size of the tag message. - * May return 0 if TCQ is disabled for this device. - **/ -static inline int scsi_populate_tag_msg(Scsi_Cmnd *SCpnt, char *msg) { - struct request *req = SCpnt->request; - - if(!blk_rq_tagged(req)) - return 0; - - if (req->flags & REQ_HARDBARRIER) - *msg++ = MSG_ORDERED_TAG; - else - *msg++ = MSG_SIMPLE_TAG; - - *msg++ = SCpnt->request->tag; - - return 2; -} - -/** - * scsi_find_tag - find a tagged command by device - * @SDpnt: pointer to the ScSI device - * @tag: the tag number - * - * Notes: - * Only works with tags allocated by the generic blk layer. - **/ -static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { - - struct request *req; - - if(tag == SCSI_NO_TAG) - /* single command, look in space */ - return SDpnt->current_cmnd; - - req = blk_queue_find_tag(SDpnt->request_queue, tag); - - if(req == NULL) - return NULL; - - return (Scsi_Cmnd *)req->special; -} - -int scsi_set_medium_removal(Scsi_Device *dev, char state); - extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, struct device_attribute *attr); extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, struct class_device_attribute *attr); + +/* + * This is the crap from the old error handling code. We have it in a special + * place so that we can more easily delete it later on. + */ +#include "scsi_obsolete.h" + +/* obsolete typedef junk. */ +#include "scsi_typedefs.h" #endif /* _SCSI_H */ diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c Mon May 12 07:26:14 2003 +++ b/drivers/scsi/scsi_debug.c Mon Jun 2 17:42:21 2003 @@ -1681,7 +1681,7 @@ sdbg_host = to_sdebug_host(dev); - hpnt = scsi_register(&sdebug_driver_template, sizeof(sdbg_host)); + hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); if (NULL == hpnt) { printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); error = -ENODEV; @@ -1700,7 +1700,7 @@ if (error) { printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); error = -ENODEV; - scsi_unregister(hpnt); + scsi_host_put(hpnt); } @@ -1726,8 +1726,6 @@ return -EBUSY; } - scsi_unregister(sdbg_host->shost); - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, dev_list); @@ -1735,5 +1733,6 @@ kfree(sdbg_devinfo); } + scsi_host_put(sdbg_host->shost); return 0; } diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c Fri May 23 04:01:50 2003 +++ b/drivers/scsi/scsi_devinfo.c Wed Jun 11 14:07:46 2003 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -23,9 +24,9 @@ static const char spaces[] = " "; /* 16 of them */ -static char *scsi_dev_flags; static unsigned scsi_default_dev_flags; static LIST_HEAD(scsi_dev_info_list); +static __init char scsi_dev_flags[256]; /* * scsi_static_device_list: deprecated list of devices that require @@ -180,6 +181,7 @@ {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, { NULL, NULL, NULL, 0 }, }; @@ -450,35 +452,15 @@ return err; } -MODULE_PARM(scsi_dev_flags, "s"); -MODULE_PARM_DESC(scsi_dev_flags, - "Given scsi_dev_flags=vendor:model:flags, add a black/white list" - " entry for vendor and model with an integer value of flags" +module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); +MODULE_PARM_DESC(dev_flags, + "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white" + " list entries for vendor and model with an integer value of flags" " to the scsi device info list"); -MODULE_PARM(scsi_default_dev_flags, "i"); -MODULE_PARM_DESC(scsi_default_dev_flags, - "scsi default device flag integer value"); -static int __init setup_scsi_dev_flags(char *str) -{ - scsi_dev_flags = str; - return 1; -} - -static int __init setup_scsi_default_dev_flags(char *str) -{ - unsigned int tmp; - if (get_option(&str, &tmp) == 1) { - scsi_default_dev_flags = tmp; - printk(KERN_WARNING "%s %d\n", __FUNCTION__, - scsi_default_dev_flags); - return 1; - } else { - printk(KERN_WARNING "%s: usage scsi_default_dev_flags=intr\n", - __FUNCTION__); - return 0; - } -} +module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(default_dev_flags, + "scsi default device flag integer value"); /** * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove @@ -540,6 +522,3 @@ scsi_exit_devinfo(); return error; } - -__setup("scsi_dev_flags=", setup_scsi_dev_flags); -__setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags); diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Mon May 12 20:52:56 2003 +++ b/drivers/scsi/scsi_error.c Sun Jun 8 13:31:57 2003 @@ -44,6 +44,16 @@ #define BUS_RESET_SETTLE_TIME 10*HZ #define HOST_RESET_SETTLE_TIME 10*HZ +/* called with shost->host_lock held */ +void scsi_eh_wakeup(struct Scsi_Host *shost) +{ + if (shost->host_busy == shost->host_failed) { + up(shost->eh_wait); + SCSI_LOG_ERROR_RECOVERY(5, + printk("Waking error handler thread\n")); + } +} + /** * scsi_eh_scmd_add - add scsi cmd to error handling. * @scmd: scmd to run eh on. @@ -76,14 +86,8 @@ list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); shost->in_recovery = 1; shost->host_failed++; - if (shost->host_busy == shost->host_failed) { - up(shost->eh_wait); - SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler" - " thread\n")); - } - + scsi_eh_wakeup(shost); spin_unlock_irqrestore(shost->host_lock, flags); - return 1; } @@ -431,6 +435,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) { struct Scsi_Host *host = scmd->device->host; + DECLARE_MUTEX_LOCKED(sem); unsigned long flags; int rtn = SUCCESS; @@ -444,71 +449,53 @@ scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | (scmd->device->lun << 5 & 0xe0); - if (host->can_queue) { - DECLARE_MUTEX_LOCKED(sem); + scsi_add_timer(scmd, timeout, scsi_eh_times_out); - scsi_add_timer(scmd, timeout, scsi_eh_times_out); + /* + * set up the semaphore so we wait for the command to complete. + */ + scmd->device->host->eh_action = &sem; + scmd->request->rq_status = RQ_SCSI_BUSY; - /* - * set up the semaphore so we wait for the command to complete. - */ - scmd->device->host->eh_action = &sem; - scmd->request->rq_status = RQ_SCSI_BUSY; + spin_lock_irqsave(scmd->device->host->host_lock, flags); + host->hostt->queuecommand(scmd, scsi_eh_done); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - host->hostt->queuecommand(scmd, scsi_eh_done); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + down(&sem); - down(&sem); + scmd->device->host->eh_action = NULL; - scmd->device->host->eh_action = NULL; + /* + * see if timeout. if so, tell the host to forget about it. + * in other words, we don't want a callback any more. + */ + if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) { + scsi_eh_eflags_clr(scmd, SCSI_EH_REC_TIMEOUT); + scmd->owner = SCSI_OWNER_LOWLEVEL; /* - * see if timeout. if so, tell the host to forget about it. - * in other words, we don't want a callback any more. + * as far as the low level driver is + * concerned, this command is still active, so + * we must give the low level driver a chance + * to abort it. (db) + * + * FIXME(eric) - we are not tracking whether we could + * abort a timed out command or not. not sure how + * we should treat them differently anyways. */ - if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) { - scsi_eh_eflags_clr(scmd, SCSI_EH_REC_TIMEOUT); - scmd->owner = SCSI_OWNER_LOWLEVEL; - - /* - * as far as the low level driver is - * concerned, this command is still active, so - * we must give the low level driver a chance - * to abort it. (db) - * - * FIXME(eric) - we are not tracking whether we could - * abort a timed out command or not. not sure how - * we should treat them differently anyways. - */ - spin_lock_irqsave(scmd->device->host->host_lock, flags); - if (scmd->device->host->hostt->eh_abort_handler) - scmd->device->host->hostt->eh_abort_handler(scmd); - spin_unlock_irqrestore(scmd->device->host->host_lock, - flags); + spin_lock_irqsave(scmd->device->host->host_lock, flags); + if (scmd->device->host->hostt->eh_abort_handler) + scmd->device->host->hostt->eh_abort_handler(scmd); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); - scmd->request->rq_status = RQ_SCSI_DONE; - scmd->owner = SCSI_OWNER_ERROR_HANDLER; + scmd->request->rq_status = RQ_SCSI_DONE; + scmd->owner = SCSI_OWNER_ERROR_HANDLER; - rtn = FAILED; - } - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", - __FUNCTION__, scmd, rtn)); - } else { - int temp; - - /* - * we damn well had better never use this code. there is no - * timeout protection here, since we would end up waiting in - * the actual low level driver, we don't know how to wake it up. - */ - spin_lock_irqsave(host->host_lock, flags); - temp = host->hostt->command(scmd); - spin_unlock_irqrestore(host->host_lock, flags); - - scmd->result = temp; - /* fall through to code below to examine status. */ + rtn = FAILED; } + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", + __FUNCTION__, scmd, rtn)); /* * now examine the actual status codes to see whether the command diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c Sat Apr 26 13:04:25 2003 +++ b/drivers/scsi/scsi_ioctl.c Sun Jun 1 14:27:11 2003 @@ -90,75 +90,70 @@ * The output area is then filled in starting from the command byte. */ -static int ioctl_internal_command(Scsi_Device * dev, char *cmd, +static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { + struct scsi_request *sreq; int result; - Scsi_Request *SRpnt; - Scsi_Device *SDpnt; + SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0])); - if (NULL == (SRpnt = scsi_allocate_request(dev))) { + sreq = scsi_allocate_request(sdev); + if (!sreq) { printk("SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } - SRpnt->sr_data_direction = SCSI_DATA_NONE; - scsi_wait_req(SRpnt, cmd, NULL, 0, timeout, retries); + sreq->sr_data_direction = SCSI_DATA_NONE; + scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SRpnt->sr_result)); + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); - if (driver_byte(SRpnt->sr_result) != 0) - switch (SRpnt->sr_sense_buffer[2] & 0xf) { + if (driver_byte(sreq->sr_result)) { + switch (sreq->sr_sense_buffer[2] & 0xf) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) - dev->lockable = 0; + sdev->lockable = 0; else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); break; case NOT_READY: /* This happens if there is no disc in drive */ - if (dev->removable && (cmd[0] != TEST_UNIT_READY)) { + if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: - if (dev->removable) { - dev->changed = 1; - SRpnt->sr_result = 0; /* This is no longer considered an error */ - /* gag this error, VFS will log it anyway /axboe */ - /* printk(KERN_INFO "Disc change detected.\n"); */ + if (sdev->removable) { + sdev->changed = 1; + sreq->sr_result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ printk("SCSI error: host %d id %d lun %d return code = %x\n", - dev->host->host_no, - dev->id, - dev->lun, - SRpnt->sr_result); + sdev->host->host_no, + sdev->id, + sdev->lun, + sreq->sr_result); printk("\tSense class %x, sense error %x, extended sense %x\n", - sense_class(SRpnt->sr_sense_buffer[0]), - sense_error(SRpnt->sr_sense_buffer[0]), - SRpnt->sr_sense_buffer[2] & 0xf); + sense_class(sreq->sr_sense_buffer[0]), + sense_error(sreq->sr_sense_buffer[0]), + sreq->sr_sense_buffer[2] & 0xf); } + } - result = SRpnt->sr_result; - + result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - SDpnt = SRpnt->sr_device; - scsi_release_request(SRpnt); - SRpnt = NULL; - + scsi_release_request(sreq); return result; } -int scsi_set_medium_removal(Scsi_Device *dev, char state) +int scsi_set_medium_removal(struct scsi_device *sdev, char state) { char scsi_cmd[MAX_COMMAND_SIZE]; int ret; - if (!dev->removable || !dev->lockable) + if (!sdev->removable || !sdev->lockable) return 0; scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; @@ -168,11 +163,10 @@ scsi_cmd[4] = state; scsi_cmd[5] = 0; - ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - + ret = ioctl_internal_command(sdev, scsi_cmd, + IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); if (ret == 0) - dev->locked = state == SCSI_REMOVAL_PREVENT; - + sdev->locked = (state == SCSI_REMOVAL_PREVENT); return ret; } @@ -209,13 +203,13 @@ */ #define OMAX_SB_LEN 16 /* Old sense buffer length */ -int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic) +int scsi_ioctl_send_command(struct scsi_device *sdev, + struct scsi_ioctl_command *sic) { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; char *cmd_in; - Scsi_Request *SRpnt; - Scsi_Device *SDpnt; + struct scsi_request *sreq; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; @@ -225,7 +219,7 @@ if (!sic) return -EINVAL; - if (dev->host->unchecked_isa_dma) + if (sdev->host->unchecked_isa_dma) gfp_mask |= GFP_DMA; /* @@ -259,11 +253,11 @@ buf_needed = (buf_needed + 511) & ~511; if (buf_needed > MAX_BUF) buf_needed = MAX_BUF; - buf = (char *) kmalloc(buf_needed, gfp_mask); + buf = kmalloc(buf_needed, gfp_mask); if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); - if( inlen == 0 ) { + if (inlen == 0) { data_direction = SCSI_DATA_READ; } else if (outlen == 0 ) { data_direction = SCSI_DATA_WRITE; @@ -327,62 +321,34 @@ break; } -#ifndef DEBUG_NO_CMD - - - SRpnt = scsi_allocate_request(dev); - if( SRpnt == NULL ) - { + sreq = scsi_allocate_request(sdev); + if (sreq) { result = -EINTR; goto error; } - SRpnt->sr_data_direction = data_direction; - scsi_wait_req(SRpnt, cmd, buf, needed, timeout, retries); + sreq->sr_data_direction = data_direction; + scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); /* * If there was an error condition, pass the info back to the user. */ - - result = SRpnt->sr_result; - - if (SRpnt->sr_result) { - int sb_len = sizeof(SRpnt->sr_sense_buffer); + result = sreq->sr_result; + if (result) { + int sb_len = sizeof(sreq->sr_sense_buffer); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; - if (copy_to_user(cmd_in, SRpnt->sr_sense_buffer, sb_len)) + if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } - SDpnt = SRpnt->sr_device; - scsi_release_request(SRpnt); - SRpnt = NULL; - + scsi_release_request(sreq); error: - if (buf) - kfree(buf); - - + kfree(buf); return result; -#else - { - int i; - printk("scsi_ioctl : device %d. command = ", dev->id); - for (i = 0; i < cmdlen; ++i) - printk("%02x ", cmd[i]); - printk("\nbuffer ="); - for (i = 0; i < 20; ++i) - printk("%02x ", buf[i]); - printk("\n"); - printk("inlen = %d, outlen = %d, cmdlen = %d\n", - inlen, outlen, cmdlen); - printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); - } - return 0; -#endif } /* @@ -395,14 +361,13 @@ * device) * any copy_to_user() error on failure there */ -static int -scsi_ioctl_get_pci(Scsi_Device * sdev, void *arg) +static int scsi_ioctl_get_pci(struct scsi_device *sdev, void *arg) { struct device *dev = scsi_get_device(sdev->host); - if (!dev) return -ENXIO; - return copy_to_user(arg, dev->bus_id, - sizeof(dev->bus_id)); + if (!dev) + return -ENXIO; + return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id)); } @@ -411,12 +376,12 @@ * not take a major/minor number as the dev field. Rather, it takes * a pointer to a scsi_devices[] element, a structure. */ -int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) +int scsi_ioctl(struct scsi_device *sdev, int cmd, void *arg) { char scsi_cmd[MAX_COMMAND_SIZE]; /* No idea how this happens.... */ - if (!dev) + if (!sdev) return -ENXIO; /* @@ -425,24 +390,24 @@ * may try and take the device offline, in which case all further * access to the device is prohibited. */ - if (!scsi_block_when_processing_errors(dev)) { + if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; - } switch (cmd) { case SCSI_IOCTL_GET_IDLUN: - if (verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun))) + if (verify_area(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) return -EFAULT; - __put_user((dev->id & 0xff) - + ((dev->lun & 0xff) << 8) - + ((dev->channel & 0xff) << 16) - + ((dev->host->host_no & 0xff) << 24), - &((Scsi_Idlun *) arg)->dev_id); - __put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id); + __put_user((sdev->id & 0xff) + + ((sdev->lun & 0xff) << 8) + + ((sdev->channel & 0xff) << 16) + + ((sdev->host->host_no & 0xff) << 24), + &((struct scsi_idlun *)arg)->dev_id); + __put_user(sdev->host->unique_id, + &((struct scsi_idlun *)arg)->host_unique_id); return 0; case SCSI_IOCTL_GET_BUS_NUMBER: - return put_user(dev->host->host_no, (int *) arg); + return put_user(sdev->host->host_no, (int *)arg); /* * The next two ioctls either need to go or need to be changed to * pass tagged queueing changes through the low level drivers. @@ -454,61 +419,56 @@ case SCSI_IOCTL_TAGGED_ENABLE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!dev->tagged_supported) + if (!sdev->tagged_supported) return -EINVAL; - dev->tagged_queue = 1; - dev->current_tag = 1; + sdev->tagged_queue = 1; + sdev->current_tag = 1; return 0; case SCSI_IOCTL_TAGGED_DISABLE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!dev->tagged_supported) + if (!sdev->tagged_supported) return -EINVAL; - dev->tagged_queue = 0; - dev->current_tag = 0; + sdev->tagged_queue = 0; + sdev->current_tag = 0; return 0; case SCSI_IOCTL_PROBE_HOST: - return ioctl_probe(dev->host, arg); + return ioctl_probe(sdev->host, arg); case SCSI_IOCTL_SEND_COMMAND: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - return scsi_ioctl_send_command((Scsi_Device *) dev, - (Scsi_Ioctl_Command *) arg); + return scsi_ioctl_send_command(sdev, + (struct scsi_ioctl_command *)arg); case SCSI_IOCTL_DOORLOCK: - return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT); + return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); case SCSI_IOCTL_DOORUNLOCK: - return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW); + return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 1; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, START_STOP_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_STOP_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; scsi_cmd[4] = 0; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, + return ioctl_internal_command(sdev, scsi_cmd, START_STOP_TIMEOUT, NORMAL_RETRIES); - break; case SCSI_IOCTL_GET_PCI: - return scsi_ioctl_get_pci(dev, arg); - break; + return scsi_ioctl_get_pci(sdev, arg); default: - if (dev->host->hostt->ioctl) - return dev->host->hostt->ioctl(dev, cmd, arg); - return -EINVAL; + if (sdev->host->hostt->ioctl) + return sdev->host->hostt->ioctl(sdev, cmd, arg); } return -EINVAL; } @@ -518,13 +478,13 @@ * fs segment fiddling. */ -int kernel_scsi_ioctl(Scsi_Device * dev, int cmd, void *arg) +int kernel_scsi_ioctl(struct scsi_device *sdev, int cmd, void *arg) { mm_segment_t oldfs; int tmp; oldfs = get_fs(); set_fs(get_ds()); - tmp = scsi_ioctl(dev, cmd, arg); + tmp = scsi_ioctl(sdev, cmd, arg); set_fs(oldfs); return tmp; } diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Mon May 26 02:50:43 2003 +++ b/drivers/scsi/scsi_lib.c Wed Jun 4 04:43:01 2003 @@ -95,7 +95,6 @@ { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; - unsigned long flags; SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd)); @@ -134,10 +133,7 @@ * Decrement the counters, since these commands are no longer * active on the host/device. */ - spin_lock_irqsave(device->request_queue->queue_lock, flags); - device->device_busy--; - spin_unlock_irqrestore(device->request_queue->queue_lock, flags); - scsi_host_busy_dec_and_test(host, device); + scsi_device_unbusy(device); /* * Insert this command at the head of the queue for it's device. @@ -314,6 +310,21 @@ cmd->underflow = cmd->old_underflow; } +void scsi_device_unbusy(struct scsi_device *sdev) +{ + struct Scsi_Host *shost = sdev->host; + unsigned long flags; + + spin_lock_irqsave(shost->host_lock, flags); + shost->host_busy--; + if (unlikely(shost->in_recovery && shost->host_failed)) + scsi_eh_wakeup(shost); + spin_unlock(shost->host_lock); + spin_lock(&sdev->sdev_lock); + sdev->device_busy--; + spin_unlock_irqrestore(&sdev->sdev_lock, flags); +} + /* * Called for single_lun devices on IO completion. Clear starget_sdev_user, * and call blk_run_queue for all the scsi_devices on the target - @@ -730,17 +741,6 @@ * can choose a block to remap, etc. */ if (driver_byte(result) != 0) { - if (suggestion(result) == SUGGEST_REMAP) { -#ifdef REMAP - /* - * Not yet implemented. A read will fail after being remapped, - * a write will call the strategy routine again. - */ - if (cmd->device->remap) { - result = 0; - } -#endif - } if ((cmd->sense_buffer[0] & 0x7f) == 0x70) { /* * If the device is in the process of becoming ready, @@ -944,6 +944,18 @@ } else cmd = req->special; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + /* + * Just check to see if the device is online. If + * it isn't, we refuse to process ordinary commands + * (we will allow specials just in case someone needs + * to send a command to an offline device without bringing + * it back online) + */ + if(!sdev->online) { + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n", + sdev->host->host_no, sdev->id, sdev->lun); + return BLKPREP_KILL; + } /* * Now try and find a command block that we can use. */ diff -Nru a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c --- a/drivers/scsi/scsi_module.c Tue Feb 5 07:23:03 2002 +++ b/drivers/scsi/scsi_module.c Thu Jun 5 11:52:51 2003 @@ -1,71 +1,73 @@ /* - * scsi_module.c Copyright (1994, 1995) Eric Youngdale. + * Copyright (C) 2003 Christoph Hellwig. + * Released under GPL v2. * - * Support for loading low-level scsi drivers using the linux kernel loadable - * module interface. + * Support for old-style host templates. * - * To use, the host adapter should first define and initialize the variable - * driver_template (datatype Scsi_Host_Template), and then include this file. - * This should also be wrapped in a #ifdef MODULE/#endif. - * - * The low -level driver must also define a release function which will - * free any irq assignments, release any dma channels, release any I/O - * address space that might be reserved, and otherwise clean up after itself. - * The idea is that the same driver should be able to be reloaded without - * any difficulty. This makes debugging new drivers easier, as you should - * be able to load the driver, test it, unload, modify and reload. - * - * One *very* important caveat. If the driver may need to do DMA on the - * ISA bus, you must have unchecked_isa_dma set in the device template, - * even if this might be changed during the detect routine. This is - * because the shpnt structure will be allocated in a special way so that - * it will be below the appropriate DMA limit - thus if your driver uses - * the hostdata field of shpnt, and the board must be able to access this - * via DMA, the shpnt structure must be in a DMA accessible region of - * memory. This comment would be relevant for something like the buslogic - * driver where there are many boards, only some of which do DMA onto the - * ISA bus. There is no convenient way of specifying whether the host - * needs to be in a ISA DMA accessible region of memory when you call - * scsi_register. + * NOTE: Do not use this for new drivers ever. */ -#include #include +#include +#include + +#include "scsi.h" +#include "hosts.h" + static int __init init_this_scsi_driver(void) { - driver_template.module = THIS_MODULE; - scsi_register_host(&driver_template); - if (driver_template.present) - return 0; - - scsi_unregister_host(&driver_template); - return -ENODEV; + struct scsi_host_template *sht = &driver_template; + struct Scsi_Host *shost; + struct list_head *l; + int error; + + if (!sht->release) { + printk(KERN_ERR + "scsi HBA driver %s didn't set a release method.\n", + sht->name); + return -EINVAL; + } + + sht->module = THIS_MODULE; + INIT_LIST_HEAD(&sht->legacy_hosts); + + sht->detect(sht); + if (!sht->present) + return -ENODEV; + + list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) { + error = scsi_add_host(shost, NULL); + if (error) + goto fail; + } + return 0; + fail: + l = &shost->sht_legacy_list; + while ((l = l->prev) != &sht->legacy_hosts) + scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list)); + return error; } static void __exit exit_this_scsi_driver(void) { - scsi_unregister_host(&driver_template); + struct scsi_host_template *sht = &driver_template; + struct Scsi_Host *shost, *s; + + list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) + scsi_remove_host(shost); + list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) + sht->release(shost); + + if (list_empty(&sht->legacy_hosts)) + return; + + printk(KERN_WARNING "%s did not call scsi_unregister\n", sht->name); + dump_stack(); + + list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) + scsi_unregister(shost); } module_init(init_this_scsi_driver); module_exit(exit_this_scsi_driver); - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h Mon May 26 09:09:20 2003 +++ b/drivers/scsi/scsi_priv.h Thu Jun 5 11:49:12 2003 @@ -52,13 +52,6 @@ }; -/* hosts.c */ -extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); -extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); -extern struct Scsi_Host *scsi_host_lookup(unsigned short); -extern void scsi_host_put(struct Scsi_Host *); -extern void scsi_host_init(void); - /* scsi.c */ extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); extern int scsi_setup_command_freelist(struct Scsi_Host *shost); @@ -80,11 +73,13 @@ extern void scsi_times_out(struct scsi_cmnd *cmd); extern void scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); +extern void scsi_eh_wakeup(struct Scsi_Host *shost); extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd); +extern void scsi_device_unbusy(struct scsi_device *sdev); extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_next_command(struct scsi_cmnd *cmd); extern void scsi_run_host_queues(struct Scsi_Host *shost); @@ -107,12 +102,11 @@ #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ -extern void scsi_scan_host(struct Scsi_Host *shost); -extern void scsi_forget_host(struct Scsi_Host *shost); +extern void scsi_scan_host(struct Scsi_Host *); +extern void scsi_forget_host(struct Scsi_Host *); extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); -extern void scsi_host_get(struct Scsi_Host *); -extern void scsi_rescan_device(struct device *dev); +extern void scsi_rescan_device(struct device *); /* scsi_sysfs.c */ extern int scsi_device_register(struct scsi_device *); diff -Nru a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c --- a/drivers/scsi/scsi_proc.c Mon May 26 09:04:01 2003 +++ b/drivers/scsi/scsi_proc.c Wed Jun 11 19:47:21 2003 @@ -42,48 +42,15 @@ EXPORT_SYMBOL(proc_scsi); -/* Used if the driver currently has no own support for /proc/scsi */ -static int generic_proc_info(char *buffer, char **start, off_t offset, - int count, const char *(*info)(struct Scsi_Host *), - struct Scsi_Host *shost) -{ - int len, pos, begin = 0; - static const char noprocfs[] = - "The driver does not yet support the proc-fs\n"; - - if (info && shost) - len = sprintf(buffer, "%s\n", info(shost)); - else - len = sprintf(buffer, "%s\n", noprocfs); - - pos = len; - if (pos < offset) { - len = 0; - begin = pos; - } - - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > count) - len = count; - - return len; -} - static int proc_scsi_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { struct Scsi_Host *shost = data; int n; - if (shost->hostt->proc_info == NULL) - n = generic_proc_info(buffer, start, offset, length, - shost->hostt->info, shost); - else - n = shost->hostt->proc_info(shost, buffer, start, offset, - length, 0); - + n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0); *eof = (n < length); + return n; } @@ -95,8 +62,6 @@ char *page; char *start; - if (!shost->hostt->proc_info) - return -ENOSYS; if (count > PROC_BLOCK_SIZE) return -EOVERFLOW; @@ -114,10 +79,13 @@ void scsi_proc_host_add(struct Scsi_Host *shost) { - Scsi_Host_Template *sht = shost->hostt; + struct scsi_host_template *sht = shost->hostt; struct proc_dir_entry *p; char name[10]; + if (!sht->proc_info) + return; + if (!sht->proc_dir) { sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); if (!sht->proc_dir) { @@ -130,27 +98,29 @@ sprintf(name,"%d", shost->host_no); p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - shost->hostt->proc_dir, proc_scsi_read, shost); + sht->proc_dir, proc_scsi_read, shost); if (!p) { printk(KERN_ERR "%s: Failed to register host %d in" "%s\n", __FUNCTION__, shost->host_no, - shost->hostt->proc_name); + sht->proc_name); return; } p->write_proc = proc_scsi_write_proc; p->owner = shost->hostt->module; - } void scsi_proc_host_rm(struct Scsi_Host *shost) { + struct scsi_host_template *sht = shost->hostt; char name[10]; - sprintf(name,"%d", shost->host_no); - remove_proc_entry(name, shost->hostt->proc_dir); - if (!shost->hostt->present) - remove_proc_entry(shost->hostt->proc_name, proc_scsi); + if (sht->proc_info) { + sprintf(name,"%d", shost->host_no); + remove_proc_entry(name, sht->proc_dir); + if (!sht->present) + remove_proc_entry(sht->proc_name, proc_scsi); + } } static int proc_print_scsidevice(struct device *dev, void *data) @@ -244,8 +214,8 @@ return error; } -static int proc_scsi_write(struct file *file, const char* buf, - size_t length, loff_t *ppos) +static ssize_t proc_scsi_write(struct file *file, const char __user *buf, + size_t length, loff_t *ppos) { int host, channel, id, lun; char *buffer, *p; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Sun Jun 15 13:38:43 2003 +++ b/drivers/scsi/scsi_scan.c Mon Jun 16 17:22:18 2003 @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -72,29 +73,9 @@ static unsigned int max_scsi_luns = 1; #endif -#ifdef MODULE -MODULE_PARM(max_scsi_luns, "i"); -MODULE_PARM_DESC(max_scsi_luns, +module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(max_luns, "last scsi LUN (should be between 1 and 2^32-1)"); -#else - -static int __init scsi_luns_setup(char *str) -{ - unsigned int tmp; - - if (get_option(&str, &tmp) == 1) { - max_scsi_luns = tmp; - return 1; - } else { - printk(KERN_WARNING "scsi_luns_setup: usage max_scsi_luns=n " - "(n should be between 1 and 2^32-1)\n"); - return 0; - } -} - -__setup("max_scsi_luns=", scsi_luns_setup); - -#endif #ifdef CONFIG_SCSI_REPORT_LUNS /* @@ -106,29 +87,10 @@ */ static unsigned int max_scsi_report_luns = 128; -#ifdef MODULE -MODULE_PARM(max_scsi_report_luns, "i"); -MODULE_PARM_DESC(max_scsi_report_luns, +module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(max_report_luns, "REPORT LUNS maximum number of LUNS received (should be" " between 1 and 16384)"); -#else -static int __init scsi_report_luns_setup(char *str) -{ - unsigned int tmp; - - if (get_option(&str, &tmp) == 1) { - max_scsi_report_luns = tmp; - return 1; - } else { - printk(KERN_WARNING "scsi_report_luns_setup: usage" - " max_scsi_report_luns=n (n should be between 1" - " and 16384)\n"); - return 0; - } -} - -__setup("max_scsi_report_luns=", scsi_report_luns_setup); -#endif #endif /** @@ -141,7 +103,8 @@ * @sreq to unlock a device, storing the (unused) results into result. * Called for BLIST_KEY devices. **/ -static void scsi_unlock_floptical(Scsi_Request *sreq, unsigned char *result) +static void scsi_unlock_floptical(struct scsi_request *sreq, + unsigned char *result) { unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -154,8 +117,7 @@ scsi_cmd[5] = 0; sreq->sr_cmd_len = 0; sreq->sr_data_direction = SCSI_DATA_READ; - scsi_wait_req(sreq, (void *) scsi_cmd, (void *) result, 0x2a /* size */, - SCSI_TIMEOUT, 3); + scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3); } /** @@ -354,10 +316,10 @@ * are copied to the Scsi_Device at @sreq->sr_device (sdev); * any flags value is stored in *@bflags. **/ -static void scsi_probe_lun(Scsi_Request *sreq, char *inq_result, +static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, int *bflags) { - Scsi_Device *sdev = sreq->sr_device; /* a bit ugly */ + struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int possible_inq_resp_len; @@ -522,7 +484,7 @@ * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device * SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized **/ -static int scsi_add_lun(Scsi_Device *sdev, char *inq_result, int *bflags) +static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) { struct scsi_device *sdev_sibling; struct scsi_target *starget; @@ -578,8 +540,6 @@ default: printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type); } - - sdev->random = (sdev->type == TYPE_TAPE) ? 0 : 1; scsi_set_name(sdev, inq_result); diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c Mon May 26 03:03:34 2003 +++ b/drivers/scsi/scsi_syms.c Thu Jun 5 04:26:04 2003 @@ -31,10 +31,12 @@ */ EXPORT_SYMBOL(scsi_register_driver); EXPORT_SYMBOL(scsi_register_interface); -EXPORT_SYMBOL(scsi_register_host); -EXPORT_SYMBOL(scsi_unregister_host); +EXPORT_SYMBOL(scsi_host_alloc); EXPORT_SYMBOL(scsi_add_host); EXPORT_SYMBOL(scsi_remove_host); +EXPORT_SYMBOL(scsi_host_get); +EXPORT_SYMBOL(scsi_host_put); +EXPORT_SYMBOL(scsi_host_lookup); EXPORT_SYMBOL(scsi_register); EXPORT_SYMBOL(scsi_unregister); EXPORT_SYMBOL(scsicam_bios_param); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Mon May 26 08:45:44 2003 +++ b/drivers/scsi/scsi_sysfs.c Thu Jun 5 11:52:51 2003 @@ -487,7 +487,7 @@ } EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute); -void scsi_sysfs_release_attributes(struct SHT *hostt) +void scsi_sysfs_release_attributes(struct scsi_host_template *hostt) { if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs) kfree(hostt->sdev_attrs); diff -Nru a/drivers/scsi/scsi_typedefs.h b/drivers/scsi/scsi_typedefs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/scsi_typedefs.h Thu Jun 5 11:47:24 2003 @@ -0,0 +1,6 @@ + +typedef struct scsi_host_template Scsi_Host_Template; +typedef struct scsi_device Scsi_Device; +typedef struct scsi_cmnd Scsi_Cmnd; +typedef struct scsi_request Scsi_Request; +typedef struct scsi_pointer Scsi_Pointer; diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sun Jun 15 13:38:43 2003 +++ b/drivers/scsi/sd.c Tue Jun 17 02:17:15 2003 @@ -76,6 +76,7 @@ struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; struct gendisk *disk; + unsigned int openers; /* protected by BKL for now, yuck */ sector_t capacity; /* size in 512-byte sectors */ u32 index; u8 media_present; @@ -87,7 +88,7 @@ static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; -static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk); +static int sd_revalidate_disk(struct gendisk *disk); static void sd_rw_intr(struct scsi_cmnd * SCpnt); static int sd_probe(struct device *); @@ -95,7 +96,6 @@ static void sd_shutdown(struct device *dev); static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); -static int sd_synchronize_cache(struct scsi_disk *, int); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); @@ -396,9 +396,10 @@ if (!sdev->online) goto error_out; - if (sdev->removable && sdev->access_count == 1) + if (!sdkp->openers++ && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); + } return 0; @@ -421,13 +422,15 @@ static int sd_release(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; - struct scsi_device *sdev = scsi_disk(disk)->device; + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdev = sdkp->device; SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name)); - if (sdev->removable && sdev->access_count == 1) + if (!--sdkp->openers && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); + } /* * XXX and what if there are packets in flight and this close() @@ -566,7 +569,7 @@ * UNIT ATTENTION, or with same cartridge - GOOD STATUS. * * Drives that auto spin down. eg iomega jaz 1G, will be started - * by sd_spinup_disk() from sd_init_onedisk(), which happens whenever + * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever * sd_revalidate() is called. */ retval = -ENODEV; @@ -632,15 +635,6 @@ kfree(buffer); } -static int sd_revalidate_disk(struct gendisk *disk) -{ - struct scsi_disk *sdkp = scsi_disk(disk); - - sd_init_onedisk(sdkp, disk); - set_capacity(disk, sdkp->capacity); - return 0; -} - static struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, @@ -772,7 +766,7 @@ } /* - * spinup disk - called only in sd_init_onedisk() + * spinup disk - called only in sd_revalidate_disk() */ static void sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, @@ -856,7 +850,7 @@ SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; - SRpnt->sr_data_direction = SCSI_DATA_READ; + SRpnt->sr_data_direction = SCSI_DATA_NONE; scsi_wait_req(SRpnt, (void *)cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); @@ -892,7 +886,7 @@ } /* - * read disk capacity - called only in sd_init_onedisk() + * read disk capacity */ static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, @@ -1105,7 +1099,7 @@ } /* - * read write protect setting, if possible - called only in sd_init_onedisk() + * read write protect setting, if possible - called only in sd_revalidate_disk() * called with buffer of length 512 */ static void @@ -1147,7 +1141,7 @@ } /* - * sd_read_cache_type - called only from sd_init_onedisk() + * sd_read_cache_type - called only from sd_revalidate_disk() * called with buffer of length 512 */ static void @@ -1206,71 +1200,69 @@ } /** - * sd_init_onedisk - called the first time a new disk is seen, + * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. - * @sdkp: pointer to associated struct scsi_disk object - * @dsk_nr: disk number within this driver (e.g. 0->/dev/sda, - * 1->/dev/sdb, etc) - * - * Note: this function is local to this driver. + * @disk: struct gendisk we care about **/ -static void -sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk) +static int sd_revalidate_disk(struct gendisk *disk) { + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdp = sdkp->device; + struct scsi_request *sreq; unsigned char *buffer; - struct scsi_device *sdp; - struct scsi_request *SRpnt; - SCSI_LOG_HLQUEUE(3, printk("sd_init_onedisk: disk=%s\n", disk->disk_name)); + SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); /* * If the device is offline, don't try and read capacity or any * of the other niceties. */ - sdp = sdkp->device; - if (sdp->online == FALSE) - return; + if (!sdp->online) + goto out; - SRpnt = scsi_allocate_request(sdp); - if (!SRpnt) { - printk(KERN_WARNING "(sd_init_onedisk:) Request allocation " + sreq = scsi_allocate_request(sdp); + if (!sreq) { + printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation " "failure.\n"); - return; + goto out; } - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); if (!buffer) { - printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation " + printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " "failure.\n"); - goto leave; + goto out_release_request; } /* defaults, until the device tells us otherwise */ + sdp->sector_size = 512; sdkp->capacity = 0; - sdkp->device->sector_size = 512; sdkp->media_present = 1; sdkp->write_prot = 0; sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp, disk->disk_name, SRpnt, buffer); + sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer); - if (sdkp->media_present) - sd_read_capacity(sdkp, disk->disk_name, SRpnt, buffer); - - if (sdp->removable && sdkp->media_present) - sd_read_write_protect_flag(sdkp, disk->disk_name, SRpnt, buffer); - /* without media there is no reason to ask; - moreover, some devices react badly if we do */ - if (sdkp->media_present) - sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer); + /* + * Without media there is no reason to ask; moreover, some devices + * react badly if we do. + */ + if (sdkp->media_present) { + sd_read_capacity(sdkp, disk->disk_name, sreq, buffer); + if (sdp->removable) + sd_read_write_protect_flag(sdkp, disk->disk_name, + sreq, buffer); + sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer); + } - SRpnt->sr_device->remap = 1; - - leave: - scsi_release_request(SRpnt); - + set_capacity(disk, sdkp->capacity); kfree(buffer); + + out_release_request: + scsi_release_request(sreq); + out: + return 0; } /** @@ -1329,6 +1321,7 @@ sdkp->driver = &sd_template; sdkp->disk = gd; sdkp->index = index; + sdkp->openers = 0; gd->major = sd_major(index >> 4); gd->first_minor = (index & 15) << 4; @@ -1344,16 +1337,16 @@ strcpy(gd->devfs_name, sdp->devfs_name); - sd_init_onedisk(sdkp, gd); + gd->private_data = &sdkp->driver; + + sd_revalidate_disk(gd); gd->driverfs_dev = &sdp->sdev_driverfs_dev; gd->flags = GENHD_FL_DRIVERFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; - gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; - set_capacity(gd, sdkp->capacity); dev_set_drvdata(dev, sdkp); add_disk(gd); @@ -1400,16 +1393,57 @@ return 0; } +/* + * Send a SYNCHRONIZE CACHE instruction down to the device through + * the normal SCSI command structure. Wait for the command to + * complete. + */ static void sd_shutdown(struct device *dev) { + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); + struct scsi_request *sreq; + int retries, res; - if (sdkp->WCE) { - printk(KERN_NOTICE "Synchronizing SCSI cache: "); - sd_synchronize_cache(sdkp, 1); - printk("\n"); + if (!sdp->online || !sdkp->WCE) + return; + + printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ", + sdkp->disk->disk_name); + + sreq = scsi_allocate_request(sdp); + if (!sreq) { + printk("FAILED\n No memory for request\n"); + return; } -} + + sreq->sr_data_direction = SCSI_DATA_NONE; + for (retries = 3; retries > 0; --retries) { + unsigned char cmd[10] = { 0 }; + + cmd[0] = SYNCHRONIZE_CACHE; + /* + * Leave the rest of the command zero to indicate + * flush everything. + */ + scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); + if (sreq->sr_result == 0) + break; + } + + res = sreq->sr_result; + if (res) { + printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + "host = %d, driver = %02x\n ", + status_byte(res), msg_byte(res), + host_byte(res), driver_byte(res)); + if (driver_byte(res) & DRIVER_SENSE) + print_req_sense("sd", sreq); + } + + scsi_release_request(sreq); + printk("\n"); +} /** * init_sd - entry point for this driver (both when built in or when @@ -1447,60 +1481,6 @@ scsi_unregister_driver(&sd_template.gendrv); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); -} - -/* send a SYNCHRONIZE CACHE instruction down to the device through the - * normal SCSI command structure. Wait for the command to complete (must - * have user context) */ -static int sd_synchronize_cache(struct scsi_disk *sdkp, int verbose) -{ - struct scsi_request *SRpnt; - struct scsi_device *SDpnt = sdkp->device; - int retries, the_result; - - if (!SDpnt->online) - return 0; - - if (verbose) - printk("%s ", sdkp->disk->disk_name); - - SRpnt = scsi_allocate_request(SDpnt); - if(!SRpnt) { - if(verbose) - printk("FAILED\n No memory for request\n"); - return 0; - } - - SRpnt->sr_data_direction = SCSI_DATA_NONE; - - for(retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* leave the rest of the command zero to indicate - * flush everything */ - scsi_wait_req(SRpnt, (void *)cmd, NULL, 0, - SD_TIMEOUT, SD_MAX_RETRIES); - - if(SRpnt->sr_result == 0) - break; - } - - the_result = SRpnt->sr_result; - if(verbose) { - if(the_result != 0) { - printk("FAILED\n status = %x, message = %02x, host = %d, driver = %02x\n ", - status_byte(the_result), - msg_byte(the_result), - host_byte(the_result), - driver_byte(the_result)); - if (driver_byte(the_result) & DRIVER_SENSE) - print_req_sense("sd", SRpnt); - - } - } - scsi_release_request(SRpnt); - return (the_result == 0); } MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c --- a/drivers/scsi/seagate.c Sun May 4 02:56:46 2003 +++ b/drivers/scsi/seagate.c Sun Jun 8 12:18:41 2003 @@ -729,13 +729,6 @@ return 0; } -static int seagate_st0x_command(Scsi_Cmnd * SCpnt) -{ - return internal_command (SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd, - SCpnt->request_buffer, SCpnt->request_bufflen, - (int) NO_RECONNECT); -} - static int internal_command (unsigned char target, unsigned char lun, const void *cmnd, void *buff, int bufflen, int reselect) { @@ -1704,7 +1697,6 @@ .detect = seagate_st0x_detect, .release = seagate_st0x_release, .info = seagate_st0x_info, - .command = seagate_st0x_command, .queuecommand = seagate_st0x_queue_command, .eh_abort_handler = seagate_st0x_abort, .eh_bus_reset_handler = seagate_st0x_bus_reset, diff -Nru a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c --- a/drivers/scsi/sim710.c Sun May 25 17:00:00 2003 +++ b/drivers/scsi/sim710.c Tue Jun 17 13:27:45 2003 @@ -121,6 +121,7 @@ hostdata->differential = differential; hostdata->clock = clock; hostdata->chip710 = 1; + NCR_700_set_io_mapped(hostdata); /* and register the chip */ if((host = NCR_700_detect(&sim710_driver_template, hostdata)) == NULL) { @@ -143,7 +144,7 @@ return 0; out_unregister: - scsi_unregister(host); + scsi_host_put(host); out_release: release_region(host->base, 64); out_free: @@ -294,12 +295,17 @@ unsigned char irq, differential = 0, scsi_id = 7; if(strcmp(edev->id.sig, "HWP0C80") == 0) { + __u8 val; eisa_irqs = eisa_hwp_irqs; irq_index = (inb(io_addr + 0xc85) & 0x7) - 1; -#if 0 - /* this doesn't seem to work at the moment */ - scsi_id = ffs(inb(io_addr + 0x4)); -#endif + + val = inb(io_addr + 0x4); + scsi_id = ffs(val) - 1; + + if(scsi_id > 7 || (val & ~(1<name); + scsi_id = 7; + } } else { eisa_irqs = eisa_cpq_irqs; irq_index = inb(io_addr + 0xc88) & 0x07; diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Sun Jun 15 13:38:43 2003 +++ b/drivers/scsi/sr.c Mon Jun 16 17:22:18 2003 @@ -524,7 +524,6 @@ sprintf(cd->cdi.name, "sr%d", minor); sdev->sector_size = 2048; /* A guess, just in case */ - sdev->remap = 1; /* FIXME: need to handle a get_capabilities failure properly ?? */ get_capabilities(cd); diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Mon May 26 04:18:14 2003 +++ b/drivers/scsi/st.c Thu Jun 5 11:39:47 2003 @@ -3674,22 +3674,6 @@ #endif -/* Driverfs file support */ -static ssize_t st_device_kdev_read(struct device *dev, char *page) -{ - kdev_t kdev; - kdev.value=(unsigned long)dev->driver_data; - return sprintf(page, "%x\n",kdev.value); -} -static DEVICE_ATTR(kdev,S_IRUGO,st_device_kdev_read,NULL); - -static ssize_t st_device_type_read(struct device *ev, char * page) -{ - return sprintf (page, "CHR\n"); -} -static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL); - - static struct file_operations st_fops = { .owner = THIS_MODULE, diff -Nru a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c --- a/drivers/scsi/sun3x_esp.c Fri Feb 7 14:02:17 2003 +++ b/drivers/scsi/sun3x_esp.c Sun Jun 8 12:18:41 2003 @@ -413,7 +413,6 @@ .slave_alloc = esp_slave_alloc, .slave_destroy = esp_slave_destroy, .info = esp_info, - .command = esp_command, .queuecommand = esp_queue, .eh_abort_handler = esp_abort, .eh_bus_reset_handler = esp_reset, diff -Nru a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c --- a/drivers/scsi/sym53c416.c Sun May 4 02:56:46 2003 +++ b/drivers/scsi/sym53c416.c Sun Jun 8 12:18:41 2003 @@ -787,20 +787,6 @@ return 0; } -static void internal_done(Scsi_Cmnd *SCpnt) -{ - SCpnt->SCp.Status++; -} - -static int sym53c416_command(Scsi_Cmnd *SCpnt) -{ - sym53c416_queuecommand(SCpnt, internal_done); - SCpnt->SCp.Status = 0; - while(!SCpnt->SCp.Status) - barrier(); - return SCpnt->result; -} - static int sym53c416_abort(Scsi_Cmnd *SCpnt) { return FAILED; @@ -880,7 +866,6 @@ .name = "Symbios Logic 53c416", .detect = sym53c416_detect, .info = sym53c416_info, - .command = sym53c416_command, .queuecommand = sym53c416_queuecommand, .eh_abort_handler = sym53c416_abort, .eh_host_reset_handler =sym53c416_host_reset, diff -Nru a/drivers/scsi/t128.c b/drivers/scsi/t128.c --- a/drivers/scsi/t128.c Sun May 4 02:56:46 2003 +++ b/drivers/scsi/t128.c Mon Jun 2 17:27:45 2003 @@ -280,6 +280,16 @@ return count; } +static int t128_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + /* * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) * @@ -403,6 +413,7 @@ static Scsi_Host_Template driver_template = { .name = "Trantor T128/T128F/T228", .detect = t128_detect, + .release = t128_release, .queuecommand = t128_queue_command, .eh_abort_handler = t128_abort, .eh_bus_reset_handler = t128_bus_reset, diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Thu May 8 11:24:15 2003 +++ b/drivers/scsi/u14-34f.c Tue Jun 3 10:54:37 2003 @@ -1,6 +1,36 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 + * + Update for new IRQ API. + * + Use "goto" when appropriate. + * + Drop u14-34f.h. + * + Update for new module_param API. + * + Module parameters can now be specified only in the + * same format as the kernel boot options. + * + * boot option old module param + * ----------- ------------------ + * addr,... io_port=addr,... + * lc:[y|n] linked_comm=[1|0] + * mq:xx max_queue_depth=xx + * tm:[0|1|2] tag_mode=[0|1|2] + * et:[y|n] ext_tran=[1|0] + * of:[y|n] have_old_firmware=[1|0] + * + * A valid example using the new parameter format is: + * modprobe u14-34f "u14-34f=0x340,0x330,lc:y,tm:0,mq:4" + * + * which is equivalent to the old format: + * modprobe u14-34f io_port=0x340,0x330 linked_comm=1 tag_mode=0 \ + * max_queue_depth=4 + * + * With actual module code, u14-34f and u14_34f are equivalent + * as module parameter names. + * + * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 + * + Release irq before calling scsi_register. + * * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 * + Release driver_lock before calling scsi_register. * @@ -221,7 +251,7 @@ * * Multiple U14F and/or U34F host adapters are supported. * - * Copyright (C) 1994-2002 Dario Ballabio (ballabio_dario@emc.com) + * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) * * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it * @@ -375,31 +405,8 @@ * the driver sets host->wish_block = TRUE for all ISA boards. */ -#include - -#ifndef LinuxVersionCode -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#endif - -#define MAX_INT_PARAM 10 - -#if defined(MODULE) -#include - -MODULE_PARM(boot_options, "s"); -MODULE_PARM(io_port, "1-" __MODULE_STRING(MAX_INT_PARAM) "i"); -MODULE_PARM(linked_comm, "i"); -MODULE_PARM(have_old_firmware, "i"); -MODULE_PARM(link_statistics, "i"); -MODULE_PARM(max_queue_depth, "i"); -MODULE_PARM(tag_mode, "i"); -MODULE_PARM(ext_tran, "i"); -MODULE_AUTHOR("Dario Ballabio"); - -#endif - +#include #include -#include #include #include #include @@ -408,20 +415,42 @@ #include #include #include +#include #include -#include #include #include #include #include #include - +#include "scsi.h" +#include "hosts.h" #include #include -#include "scsi.h" -#include "hosts.h" -#include "u14-34f.h" +static int u14_34f_detect(Scsi_Host_Template *); +static int u14_34f_release(struct Scsi_Host *); +static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +static int u14_34f_eh_abort(Scsi_Cmnd *); +static int u14_34f_eh_host_reset(Scsi_Cmnd *); +static int u14_34f_bios_param(struct scsi_device *, struct block_device *, + sector_t, int *); +static int u14_34f_slave_configure(Scsi_Device *); + +static Scsi_Host_Template driver_template = { + .name = "UltraStor 14F/34F rev. 8.10.00 ", + .detect = u14_34f_detect, + .release = u14_34f_release, + .queuecommand = u14_34f_queuecommand, + .eh_abort_handler = u14_34f_eh_abort, + .eh_device_reset_handler = NULL, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = u14_34f_eh_host_reset, + .bios_param = u14_34f_bios_param, + .slave_configure = u14_34f_slave_configure, + .this_id = 7, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING + }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" @@ -610,7 +639,6 @@ static int setup_done = FALSE; static int link_statistics; static int ext_tran = FALSE; -static char *boot_options; #if defined(HAVE_OLD_UX4F_FIRMWARE) static int have_old_firmware = TRUE; @@ -636,6 +664,24 @@ static int max_queue_depth = MAX_CMD_PER_LUN; #endif +#define MAX_INT_PARAM 10 +#define MAX_BOOT_OPTIONS_SIZE 256 +static char boot_options[MAX_BOOT_OPTIONS_SIZE]; + +#if defined(MODULE) +#include +#include + +module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); +MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \ +"option." \ +" Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\""); +MODULE_AUTHOR("Dario Ballabio"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver"); + +#endif + static int u14_34f_slave_configure(Scsi_Device *dev) { int j, tqd, utqd; char *tag_suffix, *link_suffix; @@ -802,24 +848,20 @@ sprintf(name, "%s%d", driver_name, j); - if(!request_region(port_base, REGION_SIZE, driver_name)) { + if (!request_region(port_base, REGION_SIZE, driver_name)) { #if defined(DEBUG_DETECT) printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); #endif - return FALSE; + goto fail; } - if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) { - release_region(port_base, REGION_SIZE); - return FALSE; - } + spin_lock_irq(&driver_lock); + + if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) goto freelock; in_byte = inb(port_base + REG_PRODUCT_ID2); - if ((in_byte & 0xf0) != PRODUCT_ID2) { - release_region(port_base, REGION_SIZE); - return FALSE; - } + if ((in_byte & 0xf0) != PRODUCT_ID2) goto freelock; *(char *)&config_1 = inb(port_base + REG_CONFIG1); *(char *)&config_2 = inb(port_base + REG_CONFIG2); @@ -833,16 +875,13 @@ SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), driver_name, (void *) &sha[j])) { printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freelock; } if (subversion == ISA && request_dma(dma_channel, driver_name)) { printk("%s: unable to allocate DMA channel %u, detaching.\n", name, dma_channel); - free_irq(irq, &sha[j]); - release_region(port_base, REGION_SIZE); - return FALSE; + goto freeirq; } if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING; @@ -853,13 +892,7 @@ if (sh[j] == NULL) { printk("%s: unable to register host, detaching.\n", name); - - free_irq(irq, &sha[j]); - - if (subversion == ISA) free_dma(dma_channel); - - release_region(port_base, REGION_SIZE); - return FALSE; + goto freedma; } sh[j]->io_port = port_base; @@ -938,6 +971,8 @@ if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); else sprintf(dma_name, "DMA %u", dma_channel); + spin_unlock_irq(&driver_lock); + for (i = 0; i < sh[j]->can_queue; i++) HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); @@ -947,8 +982,7 @@ sh[j]->sg_tablesize * sizeof(struct sg_list), (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - u14_34f_release(sh[j]); - return FALSE; + goto release; } if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) @@ -960,7 +994,7 @@ tag_mode = TAG_ORDERED; if (j == 0) { - printk("UltraStor 14F/34F: Copyright (C) 1994-2002 Dario Ballabio.\n"); + printk("UltraStor 14F/34F: Copyright (C) 1994-2003 Dario Ballabio.\n"); printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n", driver_name, YESNO(have_old_firmware), tag_mode, YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); @@ -979,6 +1013,20 @@ BN(j), i, sh[j]->this_id); return TRUE; + +freedma: + if (subversion == ISA) free_dma(dma_channel); +freeirq: + free_irq(irq, &sha[j]); +freelock: + spin_unlock_irq(&driver_lock); + release_region(port_base, REGION_SIZE); +fail: + return FALSE; + +release: + u14_34f_release(sh[j]); + return FALSE; } static void internal_setup(char *str, int *ints) { @@ -1034,13 +1082,10 @@ static int u14_34f_detect(Scsi_Host_Template *tpnt) { unsigned int j = 0, k; - unsigned long spin_flags; - - spin_lock_irqsave(&driver_lock, spin_flags); tpnt->proc_name = "u14-34f"; - if(boot_options) option_setup(boot_options); + if(strlen(boot_options)) option_setup(boot_options); #if defined(MODULE) /* io_port could have been modified when loading as a module */ @@ -1060,7 +1105,6 @@ } num_boards = j; - spin_unlock_irqrestore(&driver_lock, spin_flags); return j; } @@ -1680,7 +1724,7 @@ } -static void ihdlr(int irq, unsigned int j) { +static irqreturn_t ihdlr(int irq, unsigned int j) { Scsi_Cmnd *SCpnt; unsigned int i, k, c, status, tstatus, reg, ret; struct mscp *spp, *cpp; @@ -1689,7 +1733,7 @@ panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq); /* Check if this board need to be serviced */ - if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) return; + if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none; HD(j)->iocount++; @@ -1701,7 +1745,7 @@ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", BN(j), irq, reg, HD(j)->iocount); - return; + goto none; } ret = inl(sh[j]->io_port + REG_ICM); @@ -1721,23 +1765,23 @@ spp = cpp; #if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) return; + if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; #endif if (HD(j)->cp_stat[i] == IGNORE) { HD(j)->cp_stat[i] = FREE; - return; + goto handled; } else if (HD(j)->cp_stat[i] == LOCKED) { HD(j)->cp_stat[i] = FREE; printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == FREE) { printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, HD(j)->iocount); - return; + goto handled; } else if (HD(j)->cp_stat[i] == IN_RESET) printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); @@ -1887,23 +1931,25 @@ if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, HD(j)->iocount); - return; +handled: + return IRQ_HANDLED; +none: + return IRQ_NONE; } static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) -{ + struct pt_regs *regs) { unsigned int j; unsigned long spin_flags; + irqreturn_t ret; /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; + if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ihdlr(irq, j); + ret = ihdlr(irq, j); spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return IRQ_HANDLED; + return ret; } static int u14_34f_release(struct Scsi_Host *shpnt) { @@ -1930,22 +1976,8 @@ return FALSE; } -static Scsi_Host_Template driver_template = { - .name = "UltraStor 14F/34F rev. " U14_34F_VERSION " ", - .detect = u14_34f_detect, - .release = u14_34f_release, - .queuecommand = u14_34f_queuecommand, - .eh_abort_handler = u14_34f_eh_abort, - .eh_host_reset_handler = u14_34f_eh_host_reset, - .bios_param = u14_34f_bios_param, - .slave_configure = u14_34f_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; #include "scsi_module.c" #ifndef MODULE __setup("u14-34f=", option_setup); #endif /* end MODULE */ -MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h --- a/drivers/scsi/u14-34f.h Sun May 4 02:56:46 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,14 +0,0 @@ -/* - * u14-34f.h - used by the low-level driver for UltraStor 14F/34F - */ - -static int u14_34f_detect(Scsi_Host_Template *); -static int u14_34f_release(struct Scsi_Host *); -static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int u14_34f_eh_abort(Scsi_Cmnd *); -static int u14_34f_eh_host_reset(Scsi_Cmnd *); -static int u14_34f_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int u14_34f_slave_configure(Scsi_Device *); - -#define U14_34F_VERSION "8.03.00" diff -Nru a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c --- a/drivers/scsi/ultrastor.c Thu May 8 11:24:15 2003 +++ b/drivers/scsi/ultrastor.c Mon Jun 2 17:27:44 2003 @@ -643,6 +643,18 @@ return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt); } +static int ultrastor_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} + static const char *ultrastor_info(struct Scsi_Host * shpnt) { static char buf[64]; @@ -1177,6 +1189,7 @@ static Scsi_Host_Template driver_template = { .name = "UltraStor 14F/24F/34F", .detect = ultrastor_detect, + .release = ultrastor_release, .info = ultrastor_info, .queuecommand = ultrastor_queuecommand, .eh_abort_handler = ultrastor_abort, diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c --- a/drivers/scsi/wd7000.c Mon May 12 08:12:55 2003 +++ b/drivers/scsi/wd7000.c Sun Jun 8 12:18:41 2003 @@ -1031,14 +1031,6 @@ return (scsierr | (hosterr << 16)); } - -static void wd7000_scsi_done(Scsi_Cmnd * SCpnt) -{ - dprintk("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt); - SCpnt->SCp.phase = 0; -} - - #define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) static void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs *regs) @@ -1188,20 +1180,6 @@ return 0; } - -static int wd7000_command(Scsi_Cmnd * SCpnt) -{ - wd7000_queuecommand(SCpnt, wd7000_scsi_done); - - while (SCpnt->SCp.phase > 0) { - cpu_relax(); - barrier(); /* phase counts scbs down to 0 */ - } - - return (SCpnt->result); -} - - static int wd7000_diagnostics(Adapter * host, int code) { static IcbDiag icb = { ICB_OP_DIAGNOSTICS }; @@ -1616,6 +1594,15 @@ return (present); } +static int wd7000_release(struct Scsi_Host *shost) +{ + if (shost->irq) + free_irq(shost->irq, NULL); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; +} /* * I have absolutely NO idea how to do an abort with the WD7000... @@ -1722,7 +1709,7 @@ .proc_info = wd7000_proc_info, .name = "Western Digital WD-7000", .detect = wd7000_detect, - .command = wd7000_command, + .release = wd7000_release, .queuecommand = wd7000_queuecommand, .eh_bus_reset_handler = wd7000_bus_reset, .eh_device_reset_handler = wd7000_device_reset, diff -Nru a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c --- a/drivers/serial/8250_pnp.c Thu Mar 13 17:07:59 2003 +++ b/drivers/serial/8250_pnp.c Wed Jun 18 15:22:43 2003 @@ -315,19 +315,6 @@ MODULE_DEVICE_TABLE(pnp, pnp_dev_table); -static inline void avoid_irq_share(struct pnp_dev *dev) -{ - unsigned int map = 0x1FF8; - struct pnp_irq *irq; - struct pnp_resources *res = dev->possible; - - serial8250_get_irq_map(&map); - - for ( ; res; res = res->dep) - for (irq = res->irq; irq; irq = irq->next) - irq->map = map; -} - static char *modem_names[] __devinitdata = { "MODEM", "Modem", "modem", "FAX", "Fax", "fax", "56K", "56k", "K56", "33.6", "28.8", "14.4", @@ -346,6 +333,29 @@ return 0; } +static int __devinit check_resources(struct pnp_option *option) +{ + struct pnp_option *tmp; + if (!option) + return 0; + + for (tmp = option; tmp; tmp = tmp->next) { + struct pnp_port *port; + for (port = tmp->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || +#ifdef CONFIG_X86_PC9800 + (port->min == 0x8b0) || +#endif + (port->min == 0x3e8))) + return 1; + } + + return 0; +} + /* * Given a complete unknown PnP device, try to use some heuristics to * detect modems. Currently use such heuristic set: @@ -357,30 +367,16 @@ * PnP modems, alternatively we must hardcode all modems in pnp_devices[] * table. */ -static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags) +static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) { - struct pnp_resources *res = dev->possible; - struct pnp_resources *resa; - if (!(check_name(dev->dev.name) || (dev->card && check_name(dev->card->dev.name)))) return -ENODEV; - if (!res) - return -ENODEV; + if (check_resources(dev->independent)) + return 0; - for (resa = res->dep; resa; resa = resa->dep) { - struct pnp_port *port; - for (port = res->port; port; port = port->next) - if ((port->size == 8) && - ((port->min == 0x2f8) || - (port->min == 0x3f8) || - (port->min == 0x2e8) || -#ifdef CONFIG_X86_PC9800 - (port->min == 0x8b0) || -#endif - (port->min == 0x3e8))) - return 0; - } + if (check_resources(dev->dependent)) + return 0; return -ENODEV; } @@ -395,8 +391,6 @@ if (ret < 0) return ret; } - if (flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); memset(&serial_req, 0, sizeof(serial_req)); serial_req.irq = pnp_irq(dev,0); serial_req.port = pnp_port_start(dev, 0); diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig Wed May 14 07:50:37 2003 +++ b/drivers/serial/Kconfig Wed Jun 18 10:23:47 2003 @@ -77,7 +77,15 @@ a module, say M here and read . If unsure, say N. -config SERIAL_HCDP +config SERIAL_8250_ACPI + bool "8250/16550 device discovery via ACPI namespace" + default y if IA64 + depends on ACPI_BUS + ---help--- + If you wish to enable serial port discovery via the ACPI + namespace, say Y here. If unsure, say N. + +config SERIAL_8250_HCDP bool "8250/16550 device discovery support via EFI HCDP table" depends on IA64 ---help--- diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Sat Jun 14 12:07:41 2003 +++ b/drivers/serial/Makefile Wed Jun 18 10:23:46 2003 @@ -8,7 +8,8 @@ serial-8250-$(CONFIG_GSC) += 8250_gsc.o serial-8250-$(CONFIG_PCI) += 8250_pci.o serial-8250-$(CONFIG_PNP) += 8250_pnp.o -serial-8250-$(CONFIG_SERIAL_HCDP) += 8250_hcdp.o +serial-8250-$(CONFIG_SERIAL_8250_HCDP) += 8250_hcdp.o +serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o obj-$(CONFIG_SERIAL_CORE) += core.o obj-$(CONFIG_SERIAL_21285) += 21285.o diff -Nru a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c --- a/drivers/telephony/ixj.c Mon Jun 9 16:11:00 2003 +++ b/drivers/telephony/ixj.c Thu Jun 19 17:55:51 2003 @@ -7247,8 +7247,8 @@ len += sprintf(buf + len, "\n%s", ixj_h_rcsid); len += sprintf(buf + len, "\n%s", ixjuser_h_rcsid); len += sprintf(buf + len, "\nDriver version %i.%i.%i", IXJ_VER_MAJOR, IXJ_VER_MINOR, IXJ_BLD_VER); - len += sprintf(buf + len, "\nsizeof IXJ struct %d bytes", sizeof(IXJ)); - len += sprintf(buf + len, "\nsizeof DAA struct %d bytes", sizeof(DAA_REGS)); + len += sprintf(buf + len, "\nsizeof IXJ struct %Zd bytes", sizeof(IXJ)); + len += sprintf(buf + len, "\nsizeof DAA struct %Zd bytes", sizeof(DAA_REGS)); len += sprintf(buf + len, "\nUsing old telephony API"); len += sprintf(buf + len, "\nDebug Level %d\n", ixjdebug); diff -Nru a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h --- a/drivers/telephony/ixj.h Sun Jan 12 12:14:11 2003 +++ b/drivers/telephony/ixj.h Thu Jun 19 17:55:51 2003 @@ -1213,7 +1213,7 @@ #endif char *read_buffer, *read_buffer_end; char *read_convert_buffer; - unsigned int read_buffer_size; + size_t read_buffer_size; unsigned int read_buffer_ready; #if LINUX_VERSION_CODE < 0x020400 struct wait_queue *write_q; @@ -1222,7 +1222,7 @@ #endif char *write_buffer, *write_buffer_end; char *write_convert_buffer; - unsigned int write_buffer_size; + size_t write_buffer_size; unsigned int write_buffers_empty; unsigned long drybuffer; char *write_buffer_rp, *write_buffer_wp; @@ -1281,7 +1281,7 @@ unsigned char fskcnt; unsigned int cidsize; unsigned int cidcnt; - unsigned pstn_cid_received; + unsigned long pstn_cid_received; PHONE_CID cid; PHONE_CID cid_send; unsigned long pstn_ring_int; diff -Nru a/drivers/usb/Makefile.lib b/drivers/usb/Makefile.lib --- a/drivers/usb/Makefile.lib Tue Feb 18 16:32:57 2003 +++ b/drivers/usb/Makefile.lib Mon Jun 16 14:19:37 2003 @@ -1,3 +1,4 @@ +obj-$(CONFIG_USB_AX8817X) += crc32.o obj-$(CONFIG_USB_CATC) += crc32.o obj-$(CONFIG_USB_SPEEDTOUCH) += crc32.o obj-$(CONFIG_USB_USBNET) += crc32.o diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c Thu May 29 12:54:57 2003 +++ b/drivers/usb/class/audio.c Tue Jun 17 07:52:28 2003 @@ -541,7 +541,7 @@ pgrem = rem; memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->wrptr += pgrem; if (db->wrptr >= db->dmasize) db->wrptr = 0; @@ -564,14 +564,14 @@ pgrem = rem; memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem); size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; db->rdptr += pgrem; if (db->rdptr >= db->dmasize) db->rdptr = 0; } } -static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size) +static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size) { unsigned int pgrem, rem; @@ -589,14 +589,14 @@ if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; } } -static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size) +static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size) { unsigned int pgrem, rem; @@ -614,7 +614,7 @@ if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem)) return -EFAULT; size -= pgrem; - (char *)buffer += pgrem; + buffer += pgrem; ptr += pgrem; if (ptr >= db->dmasize) ptr = 0; @@ -2010,7 +2010,7 @@ strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); info.modify_counter = ms->modcnt; - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return 0; } @@ -2018,7 +2018,7 @@ _old_mixer_info info; strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); - if (copy_to_user((void *)arg, &info, sizeof(info))) + if (copy_to_user((void __user *)arg, &info, sizeof(info))) return -EFAULT; return 0; } @@ -2140,7 +2140,7 @@ /* --------------------------------------------------------------------- */ -static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -2208,7 +2208,7 @@ return ret; } -static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -2507,7 +2507,7 @@ abinfo.fragstotal = as->usbout.dma.numfrag; abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift; spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_GETISPACE: if (!(file->f_mode & FMODE_READ)) @@ -2520,7 +2520,7 @@ abinfo.fragstotal = as->usbin.dma.numfrag; abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift; spin_unlock_irqrestore(&as->lock, flags); - return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: file->f_flags |= O_NONBLOCK; @@ -2544,7 +2544,7 @@ if (as->usbin.dma.mapped) as->usbin.dma.count &= as->usbin.dma.fragsize-1; spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) + if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; @@ -2558,7 +2558,7 @@ if (as->usbout.dma.mapped) as->usbout.dma.count &= as->usbout.dma.fragsize-1; spin_unlock_irqrestore(&as->lock, flags); - if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo))) + if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) return -EFAULT; return 0; diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Wed Jun 11 12:32:42 2003 +++ b/drivers/usb/class/bluetty.c Tue Jun 17 07:52:28 2003 @@ -484,7 +484,7 @@ retval = -ENOMEM; goto exit; } - if (copy_from_user (temp_buffer, buf, count)) { + if (copy_from_user (temp_buffer, (void __user *)buf, count)) { retval = -EFAULT; goto exit; } diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Wed Jun 11 12:32:44 2003 +++ b/drivers/usb/class/cdc-acm.c Tue Jun 17 07:52:28 2003 @@ -388,7 +388,7 @@ count = (count > acm->writesize) ? acm->writesize : count; if (from_user) { - if (copy_from_user(acm->writeurb->transfer_buffer, buf, count)) + if (copy_from_user(acm->writeurb->transfer_buffer, (void __user *)buf, count)) return -EFAULT; } else memcpy(acm->writeurb->transfer_buffer, buf, count); @@ -548,7 +548,7 @@ struct usb_host_config *cfacm; struct usb_host_interface *ifcom, *ifdata; struct usb_endpoint_descriptor *epctrl, *epread, *epwrite; - int readsize, ctrlsize, minor, i; + int readsize, ctrlsize, minor, i, j; unsigned char *buf; dev = interface_to_usbdev (intf); @@ -558,120 +558,123 @@ dbg("probing config %d", cfacm->desc.bConfigurationValue); - if (cfacm->desc.bNumInterfaces != 2 || - usb_interface_claimed(cfacm->interface + 0) || - usb_interface_claimed(cfacm->interface + 1)) + for (j = 0; j < cfacm->desc.bNumInterfaces - 1; j++) { + + if (usb_interface_claimed(cfacm->interface + j) || + usb_interface_claimed(cfacm->interface + j + 1)) continue; - ifcom = cfacm->interface[0].altsetting + 0; - ifdata = cfacm->interface[1].altsetting + 0; + ifcom = cfacm->interface[j].altsetting + 0; + ifdata = cfacm->interface[j + 1].altsetting + 0; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) { - ifcom = cfacm->interface[1].altsetting + 0; - ifdata = cfacm->interface[0].altsetting + 0; - if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) + if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) { + ifcom = cfacm->interface[j + 1].altsetting + 0; + ifdata = cfacm->interface[j].altsetting + 0; + if (ifdata->desc.bInterfaceClass != 10 || ifdata->desc.bNumEndpoints < 2) + continue; + } + + if (ifcom->desc.bInterfaceClass != 2 || ifcom->desc.bInterfaceSubClass != 2 || + ifcom->desc.bInterfaceProtocol < 1 || ifcom->desc.bInterfaceProtocol > 6 || + ifcom->desc.bNumEndpoints < 1) continue; - } - - if (ifcom->desc.bInterfaceClass != 2 || ifcom->desc.bInterfaceSubClass != 2 || - ifcom->desc.bInterfaceProtocol != 1 || ifcom->desc.bNumEndpoints < 1) - continue; - - epctrl = &ifcom->endpoint[0].desc; - epread = &ifdata->endpoint[0].desc; - epwrite = &ifdata->endpoint[1].desc; - - if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || - (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || - ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) - continue; - - if ((epread->bEndpointAddress & 0x80) != 0x80) { - epread = &ifdata->endpoint[1].desc; - epwrite = &ifdata->endpoint[0].desc; - } - usb_set_configuration(dev, cfacm->desc.bConfigurationValue); - - for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); - if (acm_table[minor]) { - err("no more free acm devices"); - return -ENODEV; - } - - if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { - err("out of memory"); - return -ENOMEM; - } - memset(acm, 0, sizeof(struct acm)); - - ctrlsize = epctrl->wMaxPacketSize; - readsize = epread->wMaxPacketSize; - acm->writesize = epwrite->wMaxPacketSize; - acm->iface = cfacm->interface; - acm->minor = minor; - acm->dev = dev; - - INIT_WORK(&acm->work, acm_softint, acm); - - if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { - err("out of memory"); - kfree(acm); - return -ENOMEM; - } + epctrl = &ifcom->endpoint[0].desc; + epread = &ifdata->endpoint[0].desc; + epwrite = &ifdata->endpoint[1].desc; + + if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || + (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || + ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) + continue; - acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->ctrlurb) { - err("out of memory"); - kfree(acm); - kfree(buf); - return -ENOMEM; + if ((epread->bEndpointAddress & 0x80) != 0x80) { + epread = &ifdata->endpoint[1].desc; + epwrite = &ifdata->endpoint[0].desc; + } + + usb_set_configuration(dev, cfacm->desc.bConfigurationValue); + + for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); + if (acm_table[minor]) { + err("no more free acm devices"); + return -ENODEV; + } + + if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { + err("out of memory"); + return -ENOMEM; + } + memset(acm, 0, sizeof(struct acm)); + + ctrlsize = epctrl->wMaxPacketSize; + readsize = epread->wMaxPacketSize; + acm->writesize = epwrite->wMaxPacketSize; + acm->iface = cfacm->interface + j; + acm->minor = minor; + acm->dev = dev; + + INIT_WORK(&acm->work, acm_softint, acm); + + if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { + err("out of memory"); + kfree(acm); + return -ENOMEM; + } + + acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->ctrlurb) { + err("out of memory"); + kfree(acm); + kfree(buf); + return -ENOMEM; + } + acm->readurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->readurb) { + err("out of memory"); + usb_free_urb(acm->ctrlurb); + kfree(acm); + kfree(buf); + return -ENOMEM; + } + acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); + if (!acm->writeurb) { + err("out of memory"); + usb_free_urb(acm->readurb); + usb_free_urb(acm->ctrlurb); + kfree(acm); + kfree(buf); + return -ENOMEM; + } + + usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), + buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + + usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), + buf += ctrlsize, readsize, acm_read_bulk, acm); + acm->readurb->transfer_flags |= URB_NO_FSBR; + + usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), + buf += readsize, acm->writesize, acm_write_bulk, acm); + acm->writeurb->transfer_flags |= URB_NO_FSBR; + + info("ttyACM%d: USB ACM device", minor); + + acm_set_control(acm, acm->ctrlout); + + acm->line.speed = cpu_to_le32(9600); + acm->line.databits = 8; + acm_set_line(acm, &acm->line); + + usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm); + usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm); + + tty_register_device(acm_tty_driver, minor, &intf->dev); + + acm_table[minor] = acm; + usb_set_intfdata (intf, acm); + return 0; } - acm->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->readurb) { - err("out of memory"); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; - } - acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->writeurb) { - err("out of memory"); - usb_free_urb(acm->readurb); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; - } - - usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), - buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); - - usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), - buf += ctrlsize, readsize, acm_read_bulk, acm); - acm->readurb->transfer_flags |= URB_NO_FSBR; - - usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), - buf += readsize, acm->writesize, acm_write_bulk, acm); - acm->writeurb->transfer_flags |= URB_NO_FSBR; - - info("ttyACM%d: USB ACM device", minor); - - acm_set_control(acm, acm->ctrlout); - - acm->line.speed = cpu_to_le32(9600); - acm->line.databits = 8; - acm_set_line(acm, &acm->line); - - usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm); - usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm); - - tty_register_device(acm_tty_driver, minor, &intf->dev); - - acm_table[minor] = acm; - usb_set_intfdata (intf, acm); - return 0; } return -EIO; diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c Thu May 29 12:58:32 2003 +++ b/drivers/usb/class/usb-midi.c Tue Jun 17 07:52:28 2003 @@ -642,7 +642,7 @@ * **/ -static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usb_mididev *m = (struct usb_mididev *)file->private_data; struct midi_in_endpoint *ep = m->min.ep; @@ -725,7 +725,7 @@ * **/ -static ssize_t usb_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct usb_mididev *m = (struct usb_mididev *)file->private_data; ssize_t ret; diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c Sat May 10 16:30:31 2003 +++ b/drivers/usb/class/usblp.c Tue Jun 17 07:52:28 2003 @@ -296,13 +296,13 @@ } status = *usblp->statusbuf; - if (~status & LP_PERRORP) { + + if (~status & LP_PERRORP) newerr = 3; - if (status & LP_POUTPA) - newerr = 1; - if (~status & LP_PSELECD) - newerr = 2; - } + if (status & LP_POUTPA) + newerr = 1; + if (~status & LP_PSELECD) + newerr = 2; if (newerr != err) info("usblp%d: %s", usblp->minor, usblp_messages[newerr]); @@ -426,7 +426,7 @@ { struct usblp *usblp = file->private_data; int length, err, i; - unsigned char lpstatus, newChannel; + unsigned char newChannel; int status; int twoints[2]; int retval = 0; @@ -455,7 +455,7 @@ if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */ - if (copy_to_user((unsigned char *) arg, + if (copy_to_user((void __user *) arg, usblp->device_id_string, (unsigned long) length)) { retval = -EFAULT; @@ -479,7 +479,7 @@ twoints[1] |= (1<dev->bus->busnum; twoints[1] = usblp->dev->devnum; - if (copy_to_user((unsigned char *)arg, + if (copy_to_user((void __user *)arg, (unsigned char *)twoints, sizeof(twoints))) { retval = -EFAULT; @@ -560,7 +560,7 @@ twoints[0] = usblp->dev->descriptor.idVendor; twoints[1] = usblp->dev->descriptor.idProduct; - if (copy_to_user((unsigned char *)arg, + if (copy_to_user((void __user *)arg, (unsigned char *)twoints, sizeof(twoints))) { retval = -EFAULT; @@ -578,13 +578,13 @@ switch (cmd) { case LPGETSTATUS: - if (usblp_read_status(usblp, &lpstatus)) { + if (usblp_read_status(usblp, usblp->statusbuf)) { err("usblp%d: failed reading printer status", usblp->minor); retval = -EIO; goto done; } - status = lpstatus; - if (copy_to_user ((int *)arg, &status, sizeof(int))) + status = *usblp->statusbuf; + if (copy_to_user ((void __user *)arg, &status, sizeof(int))) retval = -EFAULT; break; @@ -597,7 +597,7 @@ return retval; } -static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); struct usblp *usblp = file->private_data; @@ -682,7 +682,7 @@ return count; } -static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct usblp *usblp = file->private_data; DECLARE_WAITQUEUE(wait, current); @@ -858,8 +858,8 @@ } usblp->writebuf = usblp->readbuf = NULL; - usblp->writeurb->transfer_flags = URB_NO_DMA_MAP; - usblp->readurb->transfer_flags = URB_NO_DMA_MAP; + usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; /* Malloc write & read buffers. We somewhat wastefully * malloc both regardless of bidirectionality, because the * alternate setting can be changed later via an ioctl. */ diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Tue May 27 07:10:17 2003 +++ b/drivers/usb/core/hcd.c Thu Jun 12 07:28:01 2003 @@ -459,7 +459,8 @@ /* rh_timer protected by hcd_data_lock */ if (hcd->rh_timer.data || urb->status != -EINPROGRESS - || urb->transfer_buffer_length < len) { + || urb->transfer_buffer_length < len + || !HCD_IS_RUNNING (hcd->state)) { dev_dbg (hcd->controller, "not queuing rh status urb, stat %d\n", urb->status); @@ -489,11 +490,10 @@ local_irq_save (flags); spin_lock (&urb->lock); - /* do nothing if the hc is gone or the urb's been unlinked */ + /* do nothing if the urb's been unlinked */ if (!urb->dev || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == 0 - || !HCD_IS_RUNNING (hcd->state)) { + || (hcd = urb->dev->bus->hcpriv) == 0) { spin_unlock (&urb->lock); local_irq_restore (flags); return; @@ -1027,7 +1027,8 @@ * valid and usb_buffer_{sync,unmap}() not be needed, since * they could clobber root hub response data. */ - urb->transfer_flags |= URB_NO_DMA_MAP; + urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); status = rh_urb_enqueue (hcd, urb); goto done; } @@ -1035,15 +1036,16 @@ /* lower level hcd code should use *_dma exclusively, * unless it uses pio or talks to another transport. */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP) - && hcd->controller->dma_mask) { - if (usb_pipecontrol (urb->pipe)) + if (hcd->controller->dma_mask) { + if (usb_pipecontrol (urb->pipe) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) urb->setup_dma = dma_map_single ( hcd->controller, urb->setup_packet, sizeof (struct usb_ctrlrequest), DMA_TO_DEVICE); - if (urb->transfer_buffer_length != 0) + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) urb->transfer_dma = dma_map_single ( hcd->controller, urb->transfer_buffer, @@ -1410,12 +1412,14 @@ // It would catch exit/unlink paths for all urbs. /* lower level hcd code should use *_dma exclusively */ - if (!(urb->transfer_flags & URB_NO_DMA_MAP)) { - if (usb_pipecontrol (urb->pipe)) + if (hcd->controller->dma_mask) { + if (usb_pipecontrol (urb->pipe) + && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) pci_unmap_single (hcd->pdev, urb->setup_dma, sizeof (struct usb_ctrlrequest), PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) + if (urb->transfer_buffer_length != 0 + && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) pci_unmap_single (hcd->pdev, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Mon Jun 9 05:15:48 2003 +++ b/drivers/usb/core/hub.c Thu Jun 12 07:28:01 2003 @@ -461,7 +461,7 @@ usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); hub->urb->transfer_dma = hub->buffer_dma; - hub->urb->transfer_flags |= URB_NO_DMA_MAP; + hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ret = usb_submit_urb(hub->urb, GFP_KERNEL); if (ret) { message = "couldn't submit status urb"; diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Fri May 23 03:46:51 2003 +++ b/drivers/usb/core/message.c Thu Jun 12 07:28:01 2003 @@ -344,7 +344,8 @@ if (!io->urbs) goto nomem; - urb_flags = URB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT; + urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP + | URB_NO_INTERRUPT; if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Tue Apr 29 15:11:51 2003 +++ b/drivers/usb/core/urb.c Thu Jun 12 07:28:01 2003 @@ -297,7 +297,7 @@ /* enforce simple/standard policy */ allowed = URB_ASYNC_UNLINK; // affects later unlinks - allowed |= URB_NO_DMA_MAP; + allowed |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); allowed |= URB_NO_INTERRUPT; switch (temp) { case PIPE_BULK: diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Mon Jun 2 03:37:34 2003 +++ b/drivers/usb/core/usb.c Thu Jun 12 07:28:01 2003 @@ -1234,7 +1234,7 @@ } /** - * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_DMA_MAP + * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP * @dev: device the buffer will be used with * @size: requested buffer size * @mem_flags: affect whether allocation may block @@ -1245,9 +1245,9 @@ * specified device. Such cpu-space buffers are returned along with the DMA * address (through the pointer provided). * - * These buffers are used with URB_NO_DMA_MAP set in urb->transfer_flags to - * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping - * hardware for long idle periods. The implementation varies between + * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags + * to avoid behaviors like using "DMA bounce buffers", or tying down I/O + * mapping hardware for long idle periods. The implementation varies between * platforms, depending on details of how DMA will work to this device. * Using these buffers also helps prevent cacheline sharing problems on * architectures where CPU caches are not DMA-coherent. @@ -1291,17 +1291,17 @@ /** * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be mapped + * @urb: urb whose transfer_buffer/setup_packet will be mapped * * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_DMA_MAP is added to urb->transfer_flags if the - * operation succeeds. If the device is connected to this system through - * a non-DMA controller, this operation always succeeds. + * the parameter. URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are + * added to urb->transfer_flags if the operation succeeds. If the device + * is connected to this system through a non-DMA controller, this operation + * always succeeds. * * This call would normally be used for an urb which is reused, perhaps * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. It may not be used for - * control requests. + * calls to synchronize memory and dma state. * * Reverse the effect of this call with usb_buffer_unmap(). */ @@ -1311,7 +1311,6 @@ struct device *controller; if (!urb - || usb_pipecontrol (urb->pipe) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) @@ -1322,17 +1321,23 @@ urb->transfer_buffer, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + if (usb_pipecontrol (urb->pipe)) + urb->setup_dma = dma_map_single (controller, + urb->setup_packet, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); // FIXME generic api broken like pci, can't report errors // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; } else urb->transfer_dma = ~0; - urb->transfer_flags |= URB_NO_DMA_MAP; + urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); return urb; } /** * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer will be synchronized + * @urb: urb whose transfer_buffer/setup_packet will be synchronized */ void usb_buffer_dmasync (struct urb *urb) { @@ -1340,17 +1345,23 @@ struct device *controller; if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) return; - if (controller->dma_mask) + if (controller->dma_mask) { dma_sync_single (controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + if (usb_pipecontrol (urb->pipe)) + dma_sync_single (controller, + urb->setup_dma, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + } } /** @@ -1365,18 +1376,25 @@ struct device *controller; if (!urb - || !(urb->transfer_flags & URB_NO_DMA_MAP) + || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) || !urb->dev || !(bus = urb->dev->bus) || !(controller = bus->controller)) return; - if (controller->dma_mask) + if (controller->dma_mask) { dma_unmap_single (controller, urb->transfer_dma, urb->transfer_buffer_length, usb_pipein (urb->pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - urb->transfer_flags &= ~URB_NO_DMA_MAP; + if (usb_pipecontrol (urb->pipe)) + dma_unmap_single (controller, + urb->setup_dma, + sizeof (struct usb_ctrlrequest), + DMA_TO_DEVICE); + } + urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); } /** @@ -1391,7 +1409,7 @@ * * The caller is responsible for placing the resulting DMA addresses from * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_DMA_MAP transfer flag in each of those URBs. + * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. * * Top I/O rates come from queuing URBs, instead of waiting for each one * to complete before starting the next I/O. This is particularly easy diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c Mon Jun 9 11:18:58 2003 +++ b/drivers/usb/gadget/net2280.c Mon Jun 16 10:44:07 2003 @@ -2222,7 +2222,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wIndex != 0 /* HALT feature */ + if (u.r.wValue != 0 /* HALT feature */ || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) @@ -2239,7 +2239,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wIndex != 0 /* HALT feature */ + if (u.r.wValue != 0 /* HALT feature */ || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Wed Mar 19 02:25:01 2003 +++ b/drivers/usb/host/ehci-dbg.c Wed Jun 11 06:24:24 2003 @@ -115,19 +115,28 @@ #ifdef DEBUG static void __attribute__((__unused__)) +dbg_qtd (char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) +{ + ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, + cpu_to_le32p (&qtd->hw_next), + cpu_to_le32p (&qtd->hw_alt_next), + cpu_to_le32p (&qtd->hw_token), + cpu_to_le32p (&qtd->hw_buf [0])); + if (qtd->hw_buf [1]) + ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n", + cpu_to_le32p (&qtd->hw_buf [1]), + cpu_to_le32p (&qtd->hw_buf [2]), + cpu_to_le32p (&qtd->hw_buf [3]), + cpu_to_le32p (&qtd->hw_buf [4])); +} + +static void __attribute__((__unused__)) dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) { - dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label, + ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, qh, qh->hw_next, qh->hw_info1, qh->hw_info2, - qh->hw_current, qh->hw_qtd_next); - dbg (" alt+nak+t= %x, token= %x, page0= %x, page1= %x", - qh->hw_alt_next, qh->hw_token, - qh->hw_buf [0], qh->hw_buf [1]); - if (qh->hw_buf [2]) { - dbg (" page2= %x, page3= %x, page4= %x", - qh->hw_buf [2], qh->hw_buf [3], - qh->hw_buf [4]); - } + qh->hw_current); + dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next); } static int __attribute__((__unused__)) @@ -284,8 +293,7 @@ return '*'; if (token & QTD_STS_HALT) return '-'; - if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */ - || QTD_LENGTH (token) == 0) + if (!IS_SHORT_READ (token)) return ' '; /* tries to advance through hw_alt_next */ return '/'; @@ -307,11 +315,14 @@ char *next = *nextp; char mark; - mark = token_mark (qh->hw_token); + if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */ + mark = '@'; + else + mark = token_mark (qh->hw_token); if (mark == '/') { /* qh_alt_next controls qh advance? */ if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) mark = '#'; /* blocked */ - else if (qh->hw_alt_next & cpu_to_le32 (0x01)) + else if (qh->hw_alt_next == EHCI_LIST_END) mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } @@ -324,7 +335,7 @@ (scratch >> 8) & 0x000f, scratch, cpu_to_le32p (&qh->hw_info2), cpu_to_le32p (&qh->hw_token), mark, - (cpu_to_le32 (0x8000000) & qh->hw_token) + (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) ? "data0" : "data1", (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; @@ -390,6 +401,8 @@ char *next; struct ehci_qh *qh; + *buf = 0; + pdev = container_of (dev, struct pci_dev, dev); ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd); next = buf; @@ -412,7 +425,7 @@ } spin_unlock_irqrestore (&ehci->lock, flags); - return PAGE_SIZE - size; + return strlen (buf); } static DEVICE_ATTR (async, S_IRUGO, show_async, NULL); @@ -548,7 +561,8 @@ /* Capability Registers */ i = readw (&ehci->caps->hci_version); temp = snprintf (next, size, - "EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n", + "%s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", + pdev->dev.name, i >> 8, i & 0x0ff, ehci->hcd.state); size -= temp; next += temp; diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Sun May 11 11:20:45 2003 +++ b/drivers/usb/host/ehci-hcd.c Mon Jun 16 11:00:43 2003 @@ -39,13 +39,10 @@ #include #include #include +#include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32) -#include "../hcd.h" -#else #include "../core/hcd.h" -#endif #include #include @@ -94,11 +91,11 @@ * 2001-June Works with usb-storage and NEC EHCI on 2.4 */ -#define DRIVER_VERSION "2003-Jan-22" +#define DRIVER_VERSION "2003-Jun-13" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" -static const char hcd_name [] = "ehci-hcd"; +static const char hcd_name [] = "ehci_hcd"; // #define EHCI_VERBOSE_DEBUG @@ -123,7 +120,7 @@ /* Initial IRQ latency: lower than default */ static int log2_irq_thresh = 0; // 0 to 6 -MODULE_PARM (log2_irq_thresh, "i"); +module_param (log2_irq_thresh, int, S_IRUGO); MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); #define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT) @@ -434,7 +431,7 @@ pci_set_mwi (ehci->hcd.pdev); /* clear interrupt enables, set irq latency */ - temp = readl (&ehci->regs->command) & 0xff; + temp = readl (&ehci->regs->command) & 0x0fff; if (log2_irq_thresh < 0 || log2_irq_thresh > 6) log2_irq_thresh = 0; temp |= 1 << (16 + log2_irq_thresh); @@ -1020,7 +1017,8 @@ if (usb_disabled()) return -ENODEV; - dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", + pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Mon May 19 02:10:48 2003 +++ b/drivers/usb/host/ehci-q.c Mon Jun 16 11:00:43 2003 @@ -88,7 +88,6 @@ static inline void qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) { - qh->hw_current = 0; qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END; @@ -99,8 +98,6 @@ /*-------------------------------------------------------------------------*/ -#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) - static void qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, @@ -279,16 +276,15 @@ /* hardware copies qtd out of qh overlay */ rmb (); token = le32_to_cpu (qtd->hw_token); - stopped = stopped - || (HALT_BIT & qh->hw_token) != 0 - || (ehci->hcd.state == USB_STATE_HALT); /* always clean up qtds the hc de-activated */ if ((token & QTD_STS_ACTIVE) == 0) { - /* magic dummy for short reads; won't advance */ - if (IS_SHORT_READ (token) - && !(token & QTD_STS_HALT) + if ((token & QTD_STS_HALT) != 0) { + stopped = 1; + + /* magic dummy for some short reads; qh won't advance */ + } else if (IS_SHORT_READ (token) && (qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) { stopped = 1; @@ -296,10 +292,13 @@ } /* stop scanning when we reach qtds the hc is using */ - } else if (likely (!stopped)) { + } else if (likely (!stopped + && HCD_IS_RUNNING (ehci->hcd.state))) { break; } else { + stopped = 1; + /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. @@ -358,12 +357,20 @@ qh->qh_state = state; /* update qh after fault cleanup */ - if (unlikely ((HALT_BIT & qh->hw_token) != 0)) { - qh_update (ehci, qh, - list_empty (&qh->qtd_list) - ? qh->dummy - : list_entry (qh->qtd_list.next, - struct ehci_qtd, qtd_list)); + if (unlikely (stopped != 0) + /* some EHCI 0.95 impls will overlay dummy qtds */ + || qh->hw_qtd_next == EHCI_LIST_END) { + if (list_empty (&qh->qtd_list)) + end = qh->dummy; + else { + end = list_entry (qh->qtd_list.next, + struct ehci_qtd, qtd_list); + /* first qtd may already be partially processed */ + if (cpu_to_le32 (end->qtd_dma) == qh->hw_current) + end = 0; + } + if (end) + qh_update (ehci, qh, end); } return count; @@ -683,12 +690,11 @@ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ - /* init as halted, toggle clear, advance to dummy */ + /* init as live, toggle clear, advance to dummy */ qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_le32 (info1); qh->hw_info2 = cpu_to_le32 (info2); qh_update (ehci, qh, qh->dummy); - qh->hw_token = cpu_to_le32 (QTD_STS_HALT); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); return qh; } @@ -787,11 +793,6 @@ } } } - - /* FIXME: changing config or interface setting is not - * supported yet. preferred fix is for usbcore to tell - * us to clear out each endpoint's state, but... - */ /* usb_clear_halt() means qh data toggle gets reset */ if (unlikely (!usb_gettoggle (urb->dev, diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h Thu Apr 24 06:29:02 2003 +++ b/drivers/usb/host/ehci.h Mon Jun 9 12:20:12 2003 @@ -290,7 +290,10 @@ size_t length; /* length of buffer */ } __attribute__ ((aligned (32))); -#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */ +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK __constant_cpu_to_le32 (~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c --- a/drivers/usb/image/hpusbscsi.c Fri Jun 6 12:51:40 2003 +++ b/drivers/usb/image/hpusbscsi.c Wed Jun 11 20:06:31 2003 @@ -104,7 +104,7 @@ goto out_free_controlurb; /* In host->hostdata we store a pointer to desc */ - new->host = scsi_register(&hpusbscsi_scsi_host_template, sizeof(new)); + new->host = scsi_host_alloc(&hpusbscsi_scsi_host_template, sizeof(new)); if (!new->host) goto out_unlink_controlurb; @@ -137,7 +137,7 @@ scsi_remove_host(desc->host); usb_unlink_urb(desc->controlurb); - scsi_unregister(desc->host); + scsi_host_put(desc->host); usb_free_urb(desc->controlurb); usb_free_urb(desc->dataurb); diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c Thu May 29 21:51:27 2003 +++ b/drivers/usb/image/microtek.c Thu Jun 5 11:39:39 2003 @@ -811,7 +811,7 @@ MTS_WARNING( "will this work? Image data EP is not usually %d\n", (int)new_desc->ep_image ); - new_desc->host = scsi_register(&mts_scsi_host_template, + new_desc->host = scsi_host_alloc(&mts_scsi_host_template, sizeof(new_desc)); if (!new_desc->host) goto out_free_urb; @@ -838,7 +838,7 @@ scsi_remove_host(desc->host); usb_unlink_urb(desc->urb); - scsi_unregister(desc->host); + scsi_host_put(desc->host); usb_free_urb(desc->urb); kfree(desc); diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Thu May 29 13:09:33 2003 +++ b/drivers/usb/input/aiptek.c Thu Jun 12 07:28:01 2003 @@ -330,7 +330,7 @@ aiptek->data, aiptek->features->pktlen, aiptek->features->irq, aiptek, endpoint->bInterval); aiptek->irq->transfer_dma = aiptek->data_dma; - aiptek->irq->transfer_flags |= URB_NO_DMA_MAP; + aiptek->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&aiptek->dev); diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Wed Jun 11 07:57:32 2003 +++ b/drivers/usb/input/hid-core.c Mon Jun 16 12:37:02 2003 @@ -1518,7 +1518,7 @@ usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_DMA_MAP; + hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { if (hid->urbout) continue; @@ -1528,7 +1528,7 @@ usb_fill_bulk_urb(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_DMA_MAP; + hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } @@ -1577,7 +1577,8 @@ hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= URB_NO_DMA_MAP; + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); return hid; diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c Thu May 29 13:13:12 2003 +++ b/drivers/usb/input/kbtab.c Thu Jun 12 07:28:01 2003 @@ -181,7 +181,7 @@ kbtab->data, 8, kbtab_irq, kbtab, endpoint->bInterval); kbtab->irq->transfer_dma = kbtab->data_dma; - kbtab->irq->transfer_flags |= URB_NO_DMA_MAP; + kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&kbtab->dev); diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Thu May 29 13:13:56 2003 +++ b/drivers/usb/input/powermate.c Thu Jun 12 07:28:01 2003 @@ -180,7 +180,7 @@ (void *) pm->configcr, 0, 0, powermate_config_complete, pm); pm->config->setup_dma = pm->configcr_dma; - pm->config->transfer_flags |= URB_NO_DMA_MAP; + pm->config->transfer_flags |= URB_NO_SETUP_DMA_MAP; if (usb_submit_urb(pm->config, GFP_ATOMIC)) printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); @@ -355,7 +355,7 @@ POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval); pm->irq->transfer_dma = pm->data_dma; - pm->irq->transfer_flags |= URB_NO_DMA_MAP; + pm->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* register our interrupt URB with the USB system */ if (usb_submit_urb(pm->irq, GFP_KERNEL)) { diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c --- a/drivers/usb/input/usbkbd.c Thu May 29 13:14:44 2003 +++ b/drivers/usb/input/usbkbd.c Thu Jun 12 07:28:01 2003 @@ -282,7 +282,7 @@ kbd->new, (maxp > 8 ? 8 : maxp), usb_kbd_irq, kbd, endpoint->bInterval); kbd->irq->transfer_dma = kbd->new_dma; - kbd->irq->transfer_flags |= URB_NO_DMA_MAP; + kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; kbd->cr->bRequest = 0x09; @@ -325,7 +325,8 @@ usb_kbd_led, kbd); kbd->led->setup_dma = kbd->cr_dma; kbd->led->transfer_dma = kbd->leds_dma; - kbd->led->transfer_flags |= URB_NO_DMA_MAP; + kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP + | URB_NO_SETUP_DMA_MAP); input_register_device(&kbd->dev); diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c --- a/drivers/usb/input/usbmouse.c Thu May 29 13:15:39 2003 +++ b/drivers/usb/input/usbmouse.c Thu Jun 12 07:28:01 2003 @@ -207,7 +207,7 @@ (maxp > 8 ? 8 : maxp), usb_mouse_irq, mouse, endpoint->bInterval); mouse->irq->transfer_dma = mouse->data_dma; - mouse->irq->transfer_flags |= URB_NO_DMA_MAP; + mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&mouse->dev); printk(KERN_INFO "input: %s on %s\n", mouse->name, path); diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Thu May 29 13:16:36 2003 +++ b/drivers/usb/input/wacom.c Thu Jun 12 07:28:01 2003 @@ -590,7 +590,7 @@ wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; - wacom->irq->transfer_flags |= URB_NO_DMA_MAP; + wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; input_register_device(&wacom->dev); diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Thu May 29 13:17:29 2003 +++ b/drivers/usb/input/xpad.c Thu Jun 12 07:28:01 2003 @@ -259,7 +259,7 @@ xpad->idata, XPAD_PKT_LEN, xpad_irq_in, xpad, ep_irq_in->bInterval); xpad->irq_in->transfer_dma = xpad->idata_dma; - xpad->irq_in->transfer_flags |= URB_NO_DMA_MAP; + xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; xpad->udev = udev; diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c --- a/drivers/usb/misc/auerswald.c Thu May 29 13:35:07 2003 +++ b/drivers/usb/misc/auerswald.c Tue Jun 17 08:12:48 2003 @@ -149,8 +149,8 @@ /* External data structures / Interface */ typedef struct { - char *buf; /* return buffer for string contents */ - unsigned int bsize; /* size of return buffer */ + char __user *buf; /* return buffer for string contents */ + unsigned int bsize; /* size of return buffer */ } audevinfo_t,*paudevinfo_t; /* IO controls */ @@ -1548,7 +1548,7 @@ /* get a string descriptor for the device */ case IOCTL_AU_DEVINFO: dbg ("IOCTL_AU_DEVINFO"); - if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) { + if (copy_from_user (&devinfo, (void __user *) arg, sizeof (audevinfo_t))) { ret = -EFAULT; break; } @@ -1578,7 +1578,7 @@ } /* Read data from the device */ -static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos) +static ssize_t auerchar_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) { unsigned long flags; pauerchar_t ccp = (pauerchar_t) file->private_data; @@ -1708,7 +1708,7 @@ /* Write a data block into the right service channel of the device */ -static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos) +static ssize_t auerchar_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos) { pauerchar_t ccp = (pauerchar_t) file->private_data; pauerswald_t cp = NULL; diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c --- a/drivers/usb/misc/brlvger.c Sun May 25 17:00:00 2003 +++ b/drivers/usb/misc/brlvger.c Tue Jun 17 08:12:48 2003 @@ -109,9 +109,9 @@ static void brlvger_disconnect(struct usb_interface *intf); static int brlvger_open(struct inode *inode, struct file *file); static int brlvger_release(struct inode *inode, struct file *file); -static ssize_t brlvger_write(struct file *file, const char *buffer, +static ssize_t brlvger_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos); -static ssize_t brlvger_read(struct file *file, char *buffer, +static ssize_t brlvger_read(struct file *file, char __user *buffer, size_t count, loff_t *unused_pos); static int brlvger_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg); @@ -546,7 +546,7 @@ } static ssize_t -brlvger_write(struct file *file, const char *buffer, +brlvger_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { struct brlvger_priv *priv = file->private_data; @@ -655,7 +655,7 @@ } static ssize_t -brlvger_read(struct file *file, char *buffer, +brlvger_read(struct file *file, char __user *buffer, size_t count, loff_t *unused_pos) { struct brlvger_priv *priv = file->private_data; @@ -719,7 +719,7 @@ memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE); memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE); - if(copy_to_user((void *)arg, &vi, sizeof(vi))) + if(copy_to_user((void __user *)arg, &vi, sizeof(vi))) return -EFAULT; return 0; } diff -Nru a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c --- a/drivers/usb/misc/rio500.c Sat May 31 12:28:17 2003 +++ b/drivers/usb/misc/rio500.c Tue Jun 17 08:12:48 2003 @@ -111,7 +111,7 @@ { struct RioCommand rio_cmd; struct rio_usb_data *rio = &rio_instance; - void *data; + void __user *data; unsigned char *buffer; int result, requesttype; int retries; @@ -129,7 +129,7 @@ switch (cmd) { case RIO_RECV_COMMAND: - data = (void *) arg; + data = (void __user *) arg; if (data == NULL) break; if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { @@ -199,7 +199,7 @@ break; case RIO_SEND_COMMAND: - data = (void *) arg; + data = (void __user *) arg; if (data == NULL) break; if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { @@ -266,7 +266,7 @@ } static ssize_t -write_rio(struct file *file, const char *buffer, +write_rio(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) { struct rio_usb_data *rio = &rio_instance; @@ -352,7 +352,7 @@ } static ssize_t -read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos) +read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { struct rio_usb_data *rio = &rio_instance; ssize_t read_count; diff -Nru a/drivers/usb/misc/rio500_usb.h b/drivers/usb/misc/rio500_usb.h --- a/drivers/usb/misc/rio500_usb.h Thu Apr 4 14:32:51 2002 +++ b/drivers/usb/misc/rio500_usb.h Tue Jun 17 08:12:48 2003 @@ -32,6 +32,6 @@ int requesttype; int value; int index; - void *buffer; + void __user *buffer; int timeout; }; diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c --- a/drivers/usb/misc/speedtch.c Fri May 23 11:04:51 2003 +++ b/drivers/usb/misc/speedtch.c Mon Jun 16 02:35:26 2003 @@ -61,6 +61,7 @@ #include #include +#include #include #include #include @@ -102,12 +103,43 @@ #define SPEEDTOUCH_VENDORID 0x06b9 #define SPEEDTOUCH_PRODUCTID 0x4061 -#define UDSL_NUM_RCV_URBS 1 -#define UDSL_NUM_SND_URBS 1 -#define UDSL_NUM_RCV_BUFS (2*UDSL_NUM_RCV_URBS) -#define UDSL_NUM_SND_BUFS (2*UDSL_NUM_SND_URBS) -#define UDSL_RCV_BUF_SIZE 32 /* ATM cells */ -#define UDSL_SND_BUF_SIZE 64 /* ATM cells */ +#define UDSL_MAX_RCV_URBS 4 +#define UDSL_MAX_SND_URBS 4 +#define UDSL_MAX_RCV_BUFS 8 +#define UDSL_MAX_SND_BUFS 8 +#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */ +#define UDSL_DEFAULT_RCV_URBS 1 +#define UDSL_DEFAULT_SND_URBS 1 +#define UDSL_DEFAULT_RCV_BUFS 2 +#define UDSL_DEFAULT_SND_BUFS 2 +#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */ +#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */ + +static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS; +static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS; +static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS; +static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS; +static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE; +static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE; + +module_param (num_rcv_urbs, uint, 0444); +MODULE_PARM_DESC (num_rcv_urbs, "Number of urbs used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_URBS) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_URBS) ")"); + +module_param (num_snd_urbs, uint, 0444); +MODULE_PARM_DESC (num_snd_urbs, "Number of urbs used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_URBS) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_URBS) ")"); + +module_param (num_rcv_bufs, uint, 0444); +MODULE_PARM_DESC (num_rcv_bufs, "Number of buffers used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_BUFS) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_BUFS) ")"); + +module_param (num_snd_bufs, uint, 0444); +MODULE_PARM_DESC (num_snd_bufs, "Number of buffers used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_BUFS) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_BUFS) ")"); + +module_param (rcv_buf_size, uint, 0444); +MODULE_PARM_DESC (rcv_buf_size, "Size of the buffers used for reception (range: 0-" __MODULE_STRING (UDSL_MAX_RCV_BUF_SIZE) ", default: " __MODULE_STRING (UDSL_DEFAULT_RCV_BUF_SIZE) ")"); + +module_param (snd_buf_size, uint, 0444); +MODULE_PARM_DESC (snd_buf_size, "Size of the buffers used for transmission (range: 0-" __MODULE_STRING (UDSL_MAX_SND_BUF_SIZE) ", default: " __MODULE_STRING (UDSL_DEFAULT_SND_BUF_SIZE) ")"); #define UDSL_IOCTL_LINE_UP 1 #define UDSL_IOCTL_LINE_DOWN 2 @@ -196,8 +228,8 @@ struct list_head vcc_list; /* receive */ - struct udsl_receiver receivers [UDSL_NUM_RCV_URBS]; - struct udsl_receive_buffer receive_buffers [UDSL_NUM_RCV_BUFS]; + struct udsl_receiver receivers [UDSL_MAX_RCV_URBS]; + struct udsl_receive_buffer receive_buffers [UDSL_MAX_RCV_BUFS]; spinlock_t receive_lock; struct list_head spare_receivers; @@ -207,8 +239,8 @@ struct list_head spare_receive_buffers; /* send */ - struct udsl_sender senders [UDSL_NUM_SND_URBS]; - struct udsl_send_buffer send_buffers [UDSL_NUM_SND_BUFS]; + struct udsl_sender senders [UDSL_MAX_SND_URBS]; + struct udsl_send_buffer send_buffers [UDSL_MAX_SND_BUFS]; struct sk_buff_head sndqueue; @@ -503,7 +535,7 @@ vdbg ("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf); - BUG_ON (buf->filled_cells > UDSL_RCV_BUF_SIZE); + BUG_ON (buf->filled_cells > rcv_buf_size); /* may not be in_interrupt() */ spin_lock_irqsave (&instance->receive_lock, flags); @@ -541,7 +573,7 @@ instance->usb_dev, usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN), buf->base, - UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE, + rcv_buf_size * ATM_CELL_SIZE, udsl_complete_receive, rcv); @@ -626,11 +658,11 @@ instance->usb_dev, usb_sndbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_OUT), buf->base, - (UDSL_SND_BUF_SIZE - buf->free_cells) * ATM_CELL_SIZE, + (snd_buf_size - buf->free_cells) * ATM_CELL_SIZE, udsl_complete_send, snd); - vdbg ("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", snd->urb, UDSL_SND_BUF_SIZE - buf->free_cells, snd, buf); + vdbg ("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", snd->urb, snd_buf_size - buf->free_cells, snd, buf); if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) { dbg ("udsl_process_send: urb submission failed (%d)!", err); @@ -662,7 +694,7 @@ spin_unlock_irq (&instance->send_lock); buf->free_start = buf->base; - buf->free_cells = UDSL_SND_BUF_SIZE; + buf->free_cells = snd_buf_size; instance->current_buffer = buf; } @@ -676,7 +708,7 @@ instance->current_buffer = NULL; } - vdbg ("udsl_process_send: buffer contains %d cells, %d left", UDSL_SND_BUF_SIZE - buf->free_cells, buf->free_cells); + vdbg ("udsl_process_send: buffer contains %d cells, %d left", snd_buf_size - buf->free_cells, buf->free_cells); if (!UDSL_SKB (skb)->num_cells) { struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc; @@ -1039,7 +1071,7 @@ INIT_LIST_HEAD (&instance->filled_send_buffers); /* receive init */ - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) { + for (i = 0; i < num_rcv_urbs; i++) { struct udsl_receiver *rcv = &(instance->receivers [i]); if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) { @@ -1052,10 +1084,10 @@ list_add (&rcv->list, &instance->spare_receivers); } - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) { + for (i = 0; i < num_rcv_bufs; i++) { struct udsl_receive_buffer *buf = &(instance->receive_buffers [i]); - if (!(buf->base = kmalloc (UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) { + if (!(buf->base = kmalloc (rcv_buf_size * ATM_CELL_SIZE, GFP_KERNEL))) { dbg ("udsl_usb_probe: no memory for receive buffer %d!", i); goto fail; } @@ -1064,7 +1096,7 @@ } /* send init */ - for (i = 0; i < UDSL_NUM_SND_URBS; i++) { + for (i = 0; i < num_snd_urbs; i++) { struct udsl_sender *snd = &(instance->senders [i]); if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) { @@ -1077,10 +1109,10 @@ list_add (&snd->list, &instance->spare_senders); } - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) { + for (i = 0; i < num_snd_bufs; i++) { struct udsl_send_buffer *buf = &(instance->send_buffers [i]); - if (!(buf->base = kmalloc (UDSL_SND_BUF_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) { + if (!(buf->base = kmalloc (snd_buf_size * ATM_CELL_SIZE, GFP_KERNEL))) { dbg ("udsl_usb_probe: no memory for send buffer %d!", i); goto fail; } @@ -1139,16 +1171,16 @@ return 0; fail: - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) + for (i = 0; i < num_snd_bufs; i++) kfree (instance->send_buffers [i].base); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) usb_free_urb (instance->senders [i].urb); - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) + for (i = 0; i < num_rcv_bufs; i++) kfree (instance->receive_buffers [i].base); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) usb_free_urb (instance->receivers [i].urb); kfree (instance); @@ -1175,7 +1207,7 @@ /* receive finalize */ tasklet_disable (&instance->receive_tasklet); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) if ((result = usb_unlink_urb (instance->receivers [i].urb)) < 0) dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d", i, result); @@ -1184,13 +1216,13 @@ count = 0; spin_lock_irq (&instance->receive_lock); list_for_each (pos, &instance->spare_receivers) - if (++count > UDSL_NUM_RCV_URBS) + if (++count > num_rcv_urbs) panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__); spin_unlock_irq (&instance->receive_lock); dbg ("udsl_usb_disconnect: found %u spare receivers", count); - if (count == UDSL_NUM_RCV_URBS) + if (count == num_rcv_urbs) break; set_current_state (TASK_RUNNING); @@ -1203,16 +1235,16 @@ tasklet_enable (&instance->receive_tasklet); - for (i = 0; i < UDSL_NUM_RCV_URBS; i++) + for (i = 0; i < num_rcv_urbs; i++) usb_free_urb (instance->receivers [i].urb); - for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) + for (i = 0; i < num_rcv_bufs; i++) kfree (instance->receive_buffers [i].base); /* send finalize */ tasklet_disable (&instance->send_tasklet); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) if ((result = usb_unlink_urb (instance->senders [i].urb)) < 0) dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d", i, result); @@ -1221,13 +1253,13 @@ count = 0; spin_lock_irq (&instance->send_lock); list_for_each (pos, &instance->spare_senders) - if (++count > UDSL_NUM_SND_URBS) + if (++count > num_snd_urbs) panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__); spin_unlock_irq (&instance->send_lock); dbg ("udsl_usb_disconnect: found %u spare senders", count); - if (count == UDSL_NUM_SND_URBS) + if (count == num_snd_urbs) break; set_current_state (TASK_RUNNING); @@ -1241,10 +1273,10 @@ tasklet_enable (&instance->send_tasklet); - for (i = 0; i < UDSL_NUM_SND_URBS; i++) + for (i = 0; i < num_snd_urbs; i++) usb_free_urb (instance->senders [i].urb); - for (i = 0; i < UDSL_NUM_SND_BUFS; i++) + for (i = 0; i < num_snd_bufs; i++) kfree (instance->send_buffers [i].base); wmb (); @@ -1269,6 +1301,11 @@ printk (KERN_ERR __FILE__ ": unusable with this kernel!\n"); return -EIO; } + + if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) || (num_snd_urbs > UDSL_MAX_SND_URBS) || + (num_rcv_bufs > UDSL_MAX_RCV_BUFS) || (num_snd_bufs > UDSL_MAX_SND_BUFS) || + (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE) || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE)) + return -EINVAL; return usb_register (&udsl_usb_driver); } diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c --- a/drivers/usb/misc/tiglusb.c Thu May 8 01:08:09 2003 +++ b/drivers/usb/misc/tiglusb.c Tue Jun 17 08:12:48 2003 @@ -155,7 +155,7 @@ } static ssize_t -tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos) +tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos) { ptiglusb_t s = (ptiglusb_t) filp->private_data; ssize_t ret = 0; @@ -208,7 +208,7 @@ } static ssize_t -tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos) +tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * f_pos) { ptiglusb_t s = (ptiglusb_t) filp->private_data; ssize_t ret = 0; diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c --- a/drivers/usb/misc/usblcd.c Thu May 29 13:37:48 2003 +++ b/drivers/usb/misc/usblcd.c Tue Jun 17 08:12:48 2003 @@ -88,12 +88,12 @@ i = (lcd->lcd_dev)->descriptor.bcdDevice; sprintf(buf,"%1d%1d.%1d%1d",(i & 0xF000)>>12,(i & 0xF00)>>8, (i & 0xF0)>>4,(i & 0xF)); - if (copy_to_user((void *)arg,buf,strlen(buf))!=0) + if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) return -EFAULT; break; case IOCTL_GET_DRV_VERSION: sprintf(buf,DRIVER_VERSION); - if (copy_to_user((void *)arg,buf,strlen(buf))!=0) + if (copy_to_user((void __user *)arg,buf,strlen(buf))!=0) return -EFAULT; break; default: @@ -105,7 +105,7 @@ } static ssize_t -write_lcd(struct file *file, const char *buffer, +write_lcd(struct file *file, const char __user *buffer, size_t count, loff_t * ppos) { struct lcd_usb_data *lcd = &lcd_instance; @@ -171,7 +171,7 @@ } static ssize_t -read_lcd(struct file *file, char *buffer, size_t count, loff_t * ppos) +read_lcd(struct file *file, char __user *buffer, size_t count, loff_t * ppos) { struct lcd_usb_data *lcd = &lcd_instance; ssize_t read_count; diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Sat May 10 06:00:12 2003 +++ b/drivers/usb/misc/usbtest.c Thu Jun 12 07:28:01 2003 @@ -107,7 +107,7 @@ urb->interval = (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE; - urb->transfer_flags = URB_NO_DMA_MAP; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig --- a/drivers/usb/net/Kconfig Fri Apr 25 02:13:43 2003 +++ b/drivers/usb/net/Kconfig Tue Jun 17 07:37:22 2003 @@ -7,6 +7,27 @@ comment "Networking support is needed for USB Networking device support" depends on USB && !NET +config USB_AX8817X + tristate "USB ASIX AX8817X Ethernet device support (EXPERIMENTAL)" + depends on USB && NET && EXPERIMENTAL + ---help--- + Say Y if you want to use one of the following 10/100Mps USB + Ethernet devices based on the ASIX AX88172 chip. Supported + devices are: + ASIX AX88172 + D-Link DUB-E100 + Hawking UF200 + Netgear FA120 + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called ax8817x.o. If you want to compile it as a + module, say M here and read . + config USB_CATC tristate "USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)" depends on USB && NET && EXPERIMENTAL @@ -191,7 +212,8 @@ help Choose this option to support the "usb-eth" networking driver used by most of the ARM Linux community with device controllers - such as the SA-11x0 and PXA-25x UDCs. + such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities + in some PXA versions of the "blob" boot loader. Although the ROMs shipped with Sharp Zaurus products use a different link level framing protocol, you can have them use diff -Nru a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile --- a/drivers/usb/net/Makefile Sat Apr 12 06:28:38 2003 +++ b/drivers/usb/net/Makefile Mon Jun 16 14:19:37 2003 @@ -2,6 +2,7 @@ # Makefile for USB Network drivers # +obj-$(CONFIG_USB_AX8817X) += ax8817x.o obj-$(CONFIG_USB_CATC) += catc.o obj-$(CONFIG_USB_KAWETH) += kaweth.o obj-$(CONFIG_USB_PEGASUS) += pegasus.o diff -Nru a/drivers/usb/net/Makefile.mii b/drivers/usb/net/Makefile.mii --- a/drivers/usb/net/Makefile.mii Tue Jan 21 07:32:44 2003 +++ b/drivers/usb/net/Makefile.mii Mon Jun 16 14:19:37 2003 @@ -2,4 +2,5 @@ # Makefile for USB Network drivers which require generic MII code. # +obj-$(CONFIG_USB_AX8817X) += mii.o obj-$(CONFIG_USB_PEGASUS) += mii.o diff -Nru a/drivers/usb/net/ax8817x.c b/drivers/usb/net/ax8817x.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/net/ax8817x.c Mon Jun 16 09:43:11 2003 @@ -0,0 +1,1341 @@ +/* + * ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver + * + * $Id: ax8817x.c,v 1.11 2003/06/15 19:00:02 dhollis Exp $ + * + * Copyright (c) 2002-2003 TiVo Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * History + * + * 2003-06-15 - Dave Hollis 2.0.0 + * * Remove crc32 inline function, use core kernel instead + * * Set sane defaults for rx_buffers + * * Fix ethtool GETDRVINFO bits - use strlcpy and + * usb_make_path + * + * 2003-06-05 - Dave Hollis 0.10.0 + * * Port to 2.5 series kernels + * * Remove #if 0 blocks that are confirmed + * unnecessary + * * Re-did tx routines based off pegasus driver. + * This resolved hard crashes and greatly simplified + * things. + * * Redo mii/ethtool routines + * + * 2003-05-31 - Dave Hollis 0.9.8 + * * Don't stop/start the queue in start_xmit + * * Swallow URB status upon hard removal + * * Cleanup remaining comments (kill // style) + * + * 2003-05-29 - Dave Hollis 0.9.7 + * * Set module owner + * * Follow-up on suggestions from David Brownell & + * Oliver Neukum which should help with robustness + * * Use ether_crc from stock kernel if available + * + * 2003-05-28 - Dave Hollis 0.9.6 + * * Added basic ethtool & mii support + * + * 2003-05-28 - Dave Hollis 0.9.5 + * * Workout devrequest change to usb_ctrlrequest structure + * * Replace FILL_BULK_URB macros to non-deprecated + * usb_fill_bulk_urb macros + * * Replace printks with equivalent macros + * * Use defines for module description, version, author to + * simplify future changes + * + * Known Issues + * + * Todo + * Fix mii/ethtool output +*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version Information */ +#define DRIVER_VERSION "v2.0.0" +#define DRIVER_AUTHOR "TiVo, Inc." +#define DRIVER_DESC "ASIX AX8817x USB Ethernet driver" +#define DRIVER_NAME "ax8817x" + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL"); + +#define AX_REQ_READ ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) +#define AX_REQ_WRITE ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE ) + +#define AX_CMD_SET_SW_MII 0x06 +#define AX_CMD_READ_MII_REG 0x07 +#define AX_CMD_WRITE_MII_REG 0x08 +#define AX_CMD_SET_HW_MII 0x0a +#define AX_CMD_WRITE_RX_CTL 0x10 +#define AX_CMD_WRITE_MULTI_FILTER 0x16 +#define AX_CMD_READ_NODE_ID 0x17 +#define AX_CMD_READ_PHY_ID 0x19 +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b +#define AX_CMD_WRITE_GPIOS 0x1f + +#define AX_RX_MAX ETH_FRAME_LEN +#define AX_TIMEOUT_CMD ( HZ / 10 ) +#define AX_TIMEOUT_TX ( HZ * 2 ) +#define AX_MAX_MCAST 64 + +#define AX_DRV_STATE_INITIALIZING 0x00 +#define AX_DRV_STATE_RUNNING 0x01 +#define AX_DRV_STATE_EXITING 0x02 + +#define AX_PHY_STATE_INITIALIZING 0x00 +#define AX_PHY_STATE_NO_LINK 0x01 +#define AX_PHY_STATE_POLLING_1 0x02 +#define AX_PHY_STATE_POLLING_2 0x03 +#define AX_PHY_STATE_POLLING_3 0x04 +#define AX_PHY_STATE_POLLING_4 0x05 +#define AX_PHY_STATE_SETTING_MAC 0x06 +#define AX_PHY_STATE_LINK 0x07 +#define AX_PHY_STATE_ABORT_POLL 0x08 +#define AX_PHY_STATE_ABORTING 0x09 + +#define AX_MAX_PHY_RETRY 50 + +#define AX_RX_URBS_DEFAULT 2 + +static int n_rx_urbs = AX_RX_URBS_DEFAULT; + +MODULE_PARM(n_rx_urbs, "i"); +MODULE_PARM_DESC(n_rx_urbs, + "Number of rx buffers to queue at once (def 2)"); + +struct ax8817x_info; +struct ax_cmd_req; +typedef int (*ax_cmd_callback_t) (struct ax8817x_info *, + struct ax_cmd_req *); + +struct ax_cmd_req { + struct list_head list; + ax_cmd_callback_t cmd_callback; + void *priv; + int status; + void *data; + int data_size; + int timeout; + struct usb_ctrlrequest devreq; +}; + +struct ax8817x_info { + struct usb_device *usb; + struct net_device *net; + struct net_device_stats stats; + struct mii_if_info mii; + struct urb **rx_urbs; + struct urb *int_urb; + struct urb *tx_urb; + u8 *int_buf; + struct urb *ctl_urb; + struct list_head ctl_queue; + spinlock_t ctl_lock; + atomic_t rx_refill_cnt; + struct ax_cmd_req phy_req; + u8 phy_id; + u8 phy_state; + u8 drv_state; +}; + + +const struct usb_device_id ax8817x_id_table[] __devinitdata = { + /* Linksys USB200M */ + {USB_DEVICE(0x077b, 0x2226), driver_info:0x00130103}, + /* Hawking UF200, TRENDnet TU2-ET100 */ + {USB_DEVICE(0x07b8, 0x420a), driver_info:0x001f1d1f}, + /* NETGEAR FA120 */ + {USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103}, + /* D-Link DUB-E100 */ + {USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f}, + + {} +}; + +MODULE_DEVICE_TABLE(usb, ax8817x_id_table); + + +static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *, + int); +static void ax_rx_callback(struct urb *, struct pt_regs *); + +static void ax_ctl_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = + (struct ax8817x_info *) urb->context; + + ax_run_ctl_queue(ax_info, NULL, + urb->status ? urb->status : urb->actual_length); +} + +/* + * Queue a new ctl request, or dequeue the first in the list +*/ +static void ax_run_ctl_queue(struct ax8817x_info *ax_info, + struct ax_cmd_req *req, int status) +{ + struct ax_cmd_req *next_req = NULL; + struct ax_cmd_req *last_req = NULL; + unsigned long flags; + + /* Need to lock around queue list manipulation */ + spin_lock_irqsave(&ax_info->ctl_lock, flags); + + if (req == NULL) { + last_req = + list_entry(ax_info->ctl_queue.next, struct ax_cmd_req, + list); + } else { + if (list_empty(&ax_info->ctl_queue)) { + next_req = req; + } + + req->status = -EINPROGRESS; + list_add_tail(&req->list, &ax_info->ctl_queue); + } + + while (1) { + if (last_req != NULL) { + /* dequeue completed entry */ + list_del(&last_req->list); + + last_req->status = status; + if (last_req->cmd_callback(ax_info, last_req)) { + /* requeue if told to do so */ + last_req->status = -EINPROGRESS; + list_add_tail(&last_req->list, + &ax_info->ctl_queue); + } + + if (list_empty(&ax_info->ctl_queue)) { + next_req = NULL; + } else { + next_req = + list_entry(ax_info->ctl_queue.next, + struct ax_cmd_req, list); + } + } + + spin_unlock_irqrestore(&ax_info->ctl_lock, flags); + + if (next_req == NULL) { + break; + } + + /* XXX: do something with timeout */ + usb_fill_control_urb(ax_info->ctl_urb, ax_info->usb, + next_req->devreq. + bRequestType & USB_DIR_IN ? + usb_rcvctrlpipe(ax_info->usb, + 0) : + usb_sndctrlpipe(ax_info->usb, 0), + (void *) &next_req->devreq, + next_req->data, next_req->data_size, + ax_ctl_callback, ax_info); + + status = usb_submit_urb(ax_info->ctl_urb, GFP_ATOMIC); + if (status >= 0) { + break; + } + + last_req = next_req; + + spin_lock_irqsave(&ax_info->ctl_lock, flags); + } +} + +static int ax_sync_cmd_callback(struct ax8817x_info *unused, + struct ax_cmd_req *req) +{ + wait_queue_head_t *wq = (wait_queue_head_t *) req->priv; + + wake_up(wq); + + return 0; +} + +static int ax_async_cmd_callback(struct ax8817x_info *unused, + struct ax_cmd_req *req) +{ + if (req->status < 0) { + err("%s: Async command %d failed: %d\n", __FUNCTION__, + req->devreq.bRequest, req->status); + } + + /* Nothing else to do here, just need to free the request (and its + allocated data) */ + if (req->data != NULL) { + kfree(req->data); + } + kfree(req); + + return 0; +} + +/* + * This is mostly the same as usb_control_msg(), except that it is able + * to queue control messages +*/ +static int ax_control_msg(struct ax8817x_info *ax_info, u8 requesttype, + u8 request, u16 value, u16 index, void *data, + u16 size, int timeout) +{ + struct ax_cmd_req *req; + DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAITQUEUE(wait, current); + int ret; + + req = kmalloc(sizeof(struct ax_cmd_req), GFP_KERNEL); + if (req == NULL) { + return -ENOMEM; + } + + req->devreq.bRequestType = requesttype; + req->devreq.bRequest = request; + req->devreq.wValue = cpu_to_le16(value); + req->devreq.wIndex = cpu_to_le16(index); + req->devreq.wLength = cpu_to_le16(size); + req->data = data; + req->data_size = size; + req->timeout = timeout; + + req->priv = &wq; + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&wq, &wait); + + req->cmd_callback = ax_sync_cmd_callback; + + ax_run_ctl_queue(ax_info, req, 0); + schedule(); + + ret = req->status; + + kfree(req); + + return ret; +} + +/* + * Same, but can be used asynchronously, may fail, and returns no exit + * status +*/ +static void ax_control_msg_async(struct ax8817x_info *ax_info, + u8 requesttype, u8 request, u16 value, + u16 index, void *data, u16 size, + int timeout) +{ + struct ax_cmd_req *req; + + req = kmalloc(sizeof(struct ax_cmd_req), GFP_ATOMIC); + if (req == NULL) { + /* There's not much else we can do here... */ + err("%s: Failed alloc\n", __FUNCTION__); + return; + } + + req->devreq.bRequestType = requesttype; + req->devreq.bRequest = request; + req->devreq.wValue = cpu_to_le16(value); + req->devreq.wIndex = cpu_to_le16(index); + req->devreq.wLength = cpu_to_le16(size); + req->data = data; + req->data_size = size; + req->timeout = timeout; + + req->cmd_callback = ax_async_cmd_callback; + + ax_run_ctl_queue(ax_info, req, 0); +} + +static inline int ax_read_cmd(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, void *data) +{ + return ax_control_msg(ax_info, AX_REQ_READ, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static inline int ax_write_cmd(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, void *data) +{ + return ax_control_msg(ax_info, AX_REQ_WRITE, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static inline void ax_write_cmd_async(struct ax8817x_info *ax_info, u8 cmd, + u16 value, u16 index, u16 size, + void *data) +{ + ax_control_msg_async(ax_info, AX_REQ_WRITE, cmd, value, index, + data, size, AX_TIMEOUT_CMD); +} + +static int ax_refill_rx_urb(struct ax8817x_info *ax_info, struct urb *urb) +{ + struct sk_buff *skb; + int ret; + + skb = dev_alloc_skb(AX_RX_MAX + 2); + if (skb != NULL) { + skb_reserve(skb, 2); /* for IP header alignment */ + skb->dev = ax_info->net; + + usb_fill_bulk_urb(urb, ax_info->usb, + usb_rcvbulkpipe(ax_info->usb, 3), + skb->data, AX_RX_MAX, ax_rx_callback, + skb); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + err("Failed submit rx URB (%d)\n", ret); + dev_kfree_skb_irq(skb); + urb->context = NULL; + } else { + ret = 0; + } + } else { + /* this just means we're low on memory at the moment. Try to + handle it gracefully. */ + urb->context = NULL; + ret = 1; + } + + return ret; +} + +static int ax_phy_cmd_callback(struct ax8817x_info *ax_info, + struct ax_cmd_req *req) +{ + int full_duplex; + int flow_control; + u16 mii_data_le; + + if (req->status < 0) { + err("%s: Failed at state %d: %d\n", __FUNCTION__, + ax_info->phy_state, req->status); + /* Not sure what else we can do, so just bail */ + ax_info->phy_state = AX_PHY_STATE_ABORTING; + } + + switch (ax_info->phy_state) { + /* Now that we're in software MII mode, read the BMSR */ + case AX_PHY_STATE_POLLING_1: + ax_info->phy_state = AX_PHY_STATE_POLLING_2; + req->devreq.bRequestType = AX_REQ_READ; + req->devreq.bRequest = AX_CMD_READ_MII_REG; + req->devreq.wValue = cpu_to_le16(ax_info->phy_id); + req->devreq.wIndex = cpu_to_le16(MII_BMSR); + req->devreq.wLength = cpu_to_le16(2); + req->data_size = 2; + req->priv = 0; /* This is the retry count */ + return 1; + + /* Done reading BMSR */ + case AX_PHY_STATE_POLLING_2: + mii_data_le = *(u16 *) req->data; + if ((mii_data_le & + cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) + == cpu_to_le16(BMSR_LSTATUS | BMSR_ANEGCAPABLE)) { + if (mii_data_le & cpu_to_le16(BMSR_ANEGCOMPLETE)) { + /* Autonegotiation done, go on to read LPA */ + ax_info->phy_state = + AX_PHY_STATE_POLLING_3; + req->devreq.wIndex = cpu_to_le16(MII_LPA); + return 1; + } else if ((long) req->priv++ < AX_MAX_PHY_RETRY) { + /* Reread BMSR if it's still autonegotiating. This is + probably unnecessary logic, I've never seen it take + more than 1 try... */ + return 1; + } + /* else fall through to abort */ + } + /* XXX: should probably handle auto-neg failure better, + by reverting to manual setting of something safe. (?) */ + + ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; + /* and then fall through to set hw MII */ + + /* Got what we needed from PHY, set back to hardware MII mode + (Do same for abort in mid-poll) */ + case AX_PHY_STATE_POLLING_3: + case AX_PHY_STATE_ABORT_POLL: + ax_info->phy_state += 1; + req->devreq.bRequestType = AX_REQ_WRITE; + req->devreq.bRequest = AX_CMD_SET_HW_MII; + req->devreq.wValue = cpu_to_le16(0); + req->devreq.wIndex = cpu_to_le16(0); + req->devreq.wLength = cpu_to_le16(0); + req->data_size = 0; + return 1; + + /* The end result, set the right duplex and flow control mode in the + MAC (based on the PHY's LPA reg, which should still be in the data + buffer) */ + case AX_PHY_STATE_POLLING_4: + mii_data_le = *(u16 *) req->data; + ax_info->phy_state = AX_PHY_STATE_SETTING_MAC; + req->devreq.bRequest = AX_CMD_WRITE_MEDIUM_MODE; + full_duplex = mii_data_le & cpu_to_le16(LPA_DUPLEX); + flow_control = full_duplex && + (mii_data_le & cpu_to_le16(0x0400)); + req->devreq.wValue = cpu_to_le16(0x04) | + (full_duplex ? cpu_to_le16(0x02) : 0) | + (flow_control ? cpu_to_le16(0x10) : 0); + info("%s: Link established, %s duplex, flow control %sabled\n", ax_info->net->name, full_duplex ? "full" : "half", flow_control ? "en" : "dis"); + return 1; + + /* All done */ + case AX_PHY_STATE_SETTING_MAC: + ax_info->phy_state = AX_PHY_STATE_LINK; + netif_carrier_on(ax_info->net); + return 0; + + default: + err("%s: Unknown state %d\n", __FUNCTION__, + ax_info->phy_state); + /* fall through */ + case AX_PHY_STATE_ABORTING: + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + return 0; + } +} + +static void ax_int_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = + (struct ax8817x_info *) urb->context; + u8 phy_link; + + if (ax_info->drv_state == AX_DRV_STATE_EXITING || + urb->actual_length < 3) { + return; + } + + /* Ignore the first PHY link report, it will sometimes be reported as + link active, even though we just told the PHY to reset. If it + really has link, we'll pick it up next int callback. + */ + if (ax_info->phy_state == AX_PHY_STATE_INITIALIZING) { + netif_carrier_off(ax_info->net); + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + return; + } + + /* Assume we're only interested in the primary PHY for now. */ + phy_link = ax_info->int_buf[2] & 1; + + if (phy_link == + (ax_info->phy_state == AX_PHY_STATE_NO_LINK) ? 0 : 1) { + /* Common case, no change */ + return; + } + + if (phy_link == 0) { + netif_carrier_off(ax_info->net); + /* Abort an in-progress poll of the PHY if necessary */ + switch (ax_info->phy_state) { + case AX_PHY_STATE_POLLING_1: + case AX_PHY_STATE_POLLING_2: + case AX_PHY_STATE_POLLING_3: + ax_info->phy_state = AX_PHY_STATE_ABORT_POLL; + break; + + case AX_PHY_STATE_POLLING_4: + case AX_PHY_STATE_SETTING_MAC: + ax_info->phy_state = AX_PHY_STATE_ABORTING; + break; + + case AX_PHY_STATE_LINK: + ax_info->phy_state = AX_PHY_STATE_NO_LINK; + break; + + default: + /* If we're already aborting, continue aborting */ + break; + } + } else { + /* Note that we only fall into this case if previous phy_state was + AX_PHY_STATE_NO_LINK. When the link is reported active while + we're still polling, or when we're aborting, the logic above + will just return, and we'll check again next int callback. */ + + ax_info->phy_state = AX_PHY_STATE_POLLING_1; + ax_info->phy_req.devreq.bRequestType = AX_REQ_WRITE; + ax_info->phy_req.devreq.bRequest = AX_CMD_SET_SW_MII; + ax_info->phy_req.devreq.wValue = cpu_to_le16(0); + ax_info->phy_req.devreq.wIndex = cpu_to_le16(0); + ax_info->phy_req.devreq.wLength = cpu_to_le16(0); + ax_info->phy_req.data_size = 0; + ax_info->phy_req.timeout = AX_TIMEOUT_CMD; + ax_info->phy_req.cmd_callback = ax_phy_cmd_callback; + + ax_run_ctl_queue(ax_info, &ax_info->phy_req, 0); + } +} + +static void ax_rx_callback(struct urb *urb, struct pt_regs *regs) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct net_device *net = skb->dev; + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + int ret, len, refill; + + switch (urb->status) { + case 0: + break; + + default: + err("%s: URB status %d\n", __FUNCTION__, urb->status); + /* It's not clear that we can do much in this case, the rx pipe + doesn't ever seem to stall, so if we got -ETIMEDOUT, that + usually means the device was unplugged, and we just haven't + noticed yet. + Just fall through and free skb without resubmitting urb. */ + case -ENOENT: /* */ + case -ECONNRESET: /* Async unlink */ + case -ESHUTDOWN: /* Hardware gone */ + case -EILSEQ: /* Get this when you yank it out on UHCI */ + case -ETIMEDOUT: /* OHCI */ + case -EPROTO: /* EHCI */ + case -EPIPE: + dev_kfree_skb_any(skb); + urb->context = NULL; + return; + } + + if (ax_info->drv_state == AX_DRV_STATE_INITIALIZING) { + /* Not really expecting this to ever happen, since we haven't yet + enabled receive in the rx_ctl register, but ya never know... */ + goto refill_same; + } else if (ax_info->drv_state == AX_DRV_STATE_EXITING) { + dev_kfree_skb_any(skb); + urb->context = NULL; + return; + } + + len = urb->actual_length; + if (len == 0) { + /* this shouldn't happen... */ + goto refill_same; + } + + refill = ax_refill_rx_urb(ax_info, urb); + + if (refill == 0 + || atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { + /* Send the receive buffer up the network stack */ + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, net); + net->last_rx = jiffies; + ax_info->stats.rx_packets++; + ax_info->stats.rx_bytes += len; + + netif_rx(skb); + + if (refill == 0) { + int i; + + /* This is the common case. This URB got refilled OK, and + no other URBs need to be refilled. */ + if (atomic_read(&ax_info->rx_refill_cnt) == 0) { + return; + } + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb->context == NULL) { + if (ax_refill_rx_urb(ax_info, urb) + == 0) { + atomic_dec(&ax_info-> + rx_refill_cnt); + } else { + break; + } + } + } + } else { + /* remember to refill this one later */ + atomic_inc(&ax_info->rx_refill_cnt); + } + + return; + } else { + ax_info->stats.rx_dropped++; + if (refill < 0) { + /* the error code was already printk'ed in ax_refill_rx_urb() + so just note the consequences here: */ + warn("Halting rx due to error\n"); + return; + } + + /* fall through to resubmit this URB with the existing skb + will try to reallocate skb's on next rx callback */ + } + +refill_same: + usb_fill_bulk_urb(urb, ax_info->usb, + usb_rcvbulkpipe(ax_info->usb, 3), skb->data, + AX_RX_MAX, ax_rx_callback, skb); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + err("Failed submit rx URB (%d)\n", ret); + } +} + +static int ax8817x_open(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[4]; + int i, ret; + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0) { + return ret; + } + + ret = 0; + + ax_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->tx_urb == NULL) { + err("Error allocating tx_urb!"); + ret = -ENOMEM; + } + + atomic_set(&ax_info->rx_refill_cnt, 0); + + for (i = 0; i < n_rx_urbs && ret == 0; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb == NULL) { + urb = ax_info->rx_urbs[i] = + usb_alloc_urb(0, GFP_KERNEL); + if (urb == NULL) { + ret = -ENOMEM; + break; + } + if (n_rx_urbs > 1) { + urb->transfer_flags |= URB_NO_INTERRUPT; /* FIXME: Was USB_QUEUE_BULK */ + } + } + ret = ax_refill_rx_urb(ax_info, urb); + if (ret == 1) { + atomic_inc(&ax_info->rx_refill_cnt); + ret = 0; + } + } + + /* XXX: should handle the case where we couldn't allocate any skb's + better. They get allocated with GFP_ATOMIC, so they may all fail... */ + if (ret == 0 && atomic_read(&ax_info->rx_refill_cnt) < n_rx_urbs) { + netif_start_queue(net); + } else { + /* Error: clean up anything we allocated and bail. */ + usb_free_urb(ax_info->tx_urb); + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + + if (urb != NULL) { + /* skb gets freed in the URB callback */ + usb_unlink_urb(urb); + usb_free_urb(urb); + } + } + + err("%s: Failed start rx queue (%d)\n", __FUNCTION__, ret); + } + return ret; +} + +static int ax8817x_stop(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[4]; + int i, ret; + + netif_stop_queue(net); + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0 && ax_info->drv_state != AX_DRV_STATE_EXITING) { + err("%s: Failed cmd (%d)\n", __FUNCTION__, ret); + } + if (ax_info->tx_urb != NULL) { + usb_unlink_urb(ax_info->tx_urb); + usb_free_urb(ax_info->tx_urb); + ax_info->tx_urb = NULL; + } + + for (i = 0; i < n_rx_urbs; i++) { + struct urb *urb = ax_info->rx_urbs[i]; + if (urb != NULL) { + /* skb gets freed in the URB callback */ + usb_unlink_urb(urb); + usb_free_urb(urb); + ax_info->rx_urbs[i] = NULL; + } + } + + return 0; +} + +static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct ax8817x_info *ax_info = urb->context; + + if (!ax_info || (ax_info->drv_state == AX_DRV_STATE_EXITING)) + return; + + if (!netif_device_present(ax_info->net)) + return; + + if (urb->status) + info("%s: TX status %d", ax_info->net->name, urb->status); + + ax_info->net->trans_start = jiffies; + netif_wake_queue(ax_info->net); +} + +static int ax8817x_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + struct ax8817x_info *ax_info = net->priv; + int res; + + netif_stop_queue(net); + + ax_info->tx_urb->transfer_flags |= URB_ZERO_PACKET; + usb_fill_bulk_urb(ax_info->tx_urb, ax_info->usb, + usb_sndbulkpipe(ax_info->usb, 2), + skb->data, skb->len, write_bulk_callback, + ax_info); + if ((res = usb_submit_urb(ax_info->tx_urb, GFP_ATOMIC))) { + warn("Failed tx_urb %d", res); + ax_info->stats.tx_errors++; + netif_start_queue(net); + } else { + ax_info->stats.tx_packets++; + ax_info->stats.tx_bytes += skb->len; + net->trans_start = jiffies; + } + dev_kfree_skb(skb); + + return 0; +} + +static void ax8817x_tx_timeout(struct net_device *net) +{ + struct ax8817x_info *ax_info = net->priv; + + if (!ax_info) + return; + + warn("%s: Tx timed out.", net->name); + ax_info->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; + usb_unlink_urb(ax_info->tx_urb); + ax_info->stats.tx_errors++; +} + +static struct net_device_stats *ax8817x_stats(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + + return &ax_info->stats; +} + +static void ax8817x_set_multicast(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 rx_ctl = 0x8c; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x01; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > AX_MAX_MCAST) { + rx_ctl |= 0x02; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + struct dev_mc_list *mc_list = net->mc_list; + u8 *multi_filter; + u32 crc_bits; + int i; + + multi_filter = kmalloc(8, GFP_ATOMIC); + if (multi_filter == NULL) { + /* Oops, couldn't allocate a DMA buffer for setting the multicast + filter. Try all multi mode, although the ax_write_cmd_async + will almost certainly fail, too... (but it will printk). */ + rx_ctl |= 0x02; + } else { + memset(multi_filter, 0, 8); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = + ether_crc(ETH_ALEN, + mc_list->dmi_addr) >> 26; + multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + ax_write_cmd_async(ax_info, + AX_CMD_WRITE_MULTI_FILTER, 0, 0, + 8, multi_filter); + + rx_ctl |= 0x10; + } + } + + ax_write_cmd_async(ax_info, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, + NULL); +} + +static int read_mii_word(struct ax8817x_info *ax_info, __u8 phy, __u8 indx, + __u16 * regd) +{ + int ret; + + ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); + ret = + ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, phy, indx, 2, regd); + ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); + + return 0; +} + +static int write_mii_word(struct ax8817x_info *ax_info, __u8 phy, + __u8 indx, __u16 regd) +{ + warn("write_mii_word - not implemented!"); + return 0; +} + +static int mdio_read(struct net_device *dev, int phy_id, int loc) +{ + struct ax8817x_info *ax_info = dev->priv; + int res; + + read_mii_word(ax_info, phy_id, loc, (u16 *) & res); + return res & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int loc, + int val) +{ + struct ax8817x_info *ax_info = dev->priv; + + write_mii_word(ax_info, phy_id, loc, val); +} + +static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) +{ + struct ax8817x_info *ax_info; + int cmd; + + ax_info = net->priv; + if (get_user(cmd, (int *) uaddr)) + return -EFAULT; + + switch (cmd) { + case ETHTOOL_GDRVINFO:{ + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + + strlcpy(info.driver, DRIVER_NAME, + ETHTOOL_BUSINFO_LEN); + strlcpy(info.version, DRIVER_VERSION, + ETHTOOL_BUSINFO_LEN); + usb_make_path(ax_info->usb, info.bus_info,sizeof info.bus_info); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case ETHTOOL_GSET:{ + struct ethtool_cmd ecmd; + + mii_ethtool_gset(&ax_info->mii, &ecmd); + if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET:{ + int r; + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, uaddr, sizeof(ecmd))) + return -EFAULT; + r = mii_ethtool_sset(&ax_info->mii, &ecmd); + return r; + } + case ETHTOOL_NWAY_RST:{ + return mii_nway_restart(&ax_info->mii); + } + case ETHTOOL_GLINK:{ + struct ethtool_value edata = { ETHTOOL_GLINK }; + + edata.data = + ax_info->phy_state == AX_PHY_STATE_LINK; + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_GMSGLVL:{ + struct ethtool_value edata = { ETHTOOL_GMSGLVL }; + /* edata.data = ax_info->msg_enable; FIXME */ + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SMSGLVL:{ + struct ethtool_value edata; + + if (copy_from_user(&edata, uaddr, sizeof(edata))) + return -EFAULT; + /* sp->msg_enable = edata.data; FIXME */ + return 0; + } + } + return -EOPNOTSUPP; +} + +static int ax8817x_mii_ioctl(struct net_device *net, struct ifreq *ifr, + int cmd) +{ + struct ax8817x_info *ax_info; + struct mii_ioctl_data *data_ptr = + (struct mii_ioctl_data *) &(ifr->ifr_data); + + ax_info = net->priv; + + switch (cmd) { + case SIOCGMIIPHY: + data_ptr->phy_id = ax_info->phy_id; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, 0, + data_ptr->reg_num & 0x1f, 2, + &(data_ptr->val_out)); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr, + int cmd) +{ + struct ax8817x_info *ax_info; + int res; + + ax_info = net->priv; + res = 0; + + switch (cmd) { + case SIOCETHTOOL: + res = ax8817x_ethtool_ioctl(net, (void __user *)ifr->ifr_data); + break; + case SIOCGMIIPHY: /* Get address of PHY in use */ + case SIOCGMIIREG: /* Read from MII PHY register */ + case SIOCSMIIREG: /* Write to MII PHY register */ + return ax8817x_mii_ioctl(net, ifr, cmd); + default: + res = -EOPNOTSUPP; + } + + return res; +} + +static int ax8817x_net_init(struct net_device *net) +{ + struct ax8817x_info *ax_info = (struct ax8817x_info *) net->priv; + u8 buf[6]; + u16 *buf16 = (u16 *) buf; + int ret; + + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf); + if (ret < 0) { + return ret; + } + + memset(buf, 0, 6); + + /* Get the MAC address */ + ret = ax_read_cmd(ax_info, AX_CMD_READ_NODE_ID, 0, 0, 6, buf); + if (ret < 0) { + return ret; + } + + memcpy(net->dev_addr, buf, 6); + + /* Get the PHY id */ + ret = ax_read_cmd(ax_info, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); + if (ret < 0) { + return ret; + } else if (ret < 2) { + /* this should always return 2 bytes */ + return -EIO; + } + + /* Reset the PHY, and drop it into auto-negotiation mode */ + ax_info->phy_id = buf[1]; + ax_info->phy_state = AX_PHY_STATE_INITIALIZING; + + ret = ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); + if (ret < 0) { + return ret; + } + + *buf16 = cpu_to_le16(BMCR_RESET); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_BMCR, 2, buf16); + if (ret < 0) { + return ret; + } + + /* Advertise that we can do full-duplex pause */ + *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_ADVERTISE, 2, buf16); + if (ret < 0) { + return ret; + } + + *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_MII_REG, + ax_info->phy_id, MII_BMCR, 2, buf16); + if (ret < 0) { + return ret; + } + + ret = ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + if (ret < 0) { + return ret; + } + + net->open = ax8817x_open; + net->stop = ax8817x_stop; + net->hard_start_xmit = ax8817x_start_xmit; + net->tx_timeout = ax8817x_tx_timeout; + net->watchdog_timeo = AX_TIMEOUT_TX; + net->get_stats = ax8817x_stats; + net->do_ioctl = ax8817x_ioctl; + net->set_multicast_list = ax8817x_set_multicast; + + return 0; +} + +static int ax8817x_bind(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *usb = interface_to_usbdev(intf); + struct ax8817x_info *ax_info; + struct net_device *net; + int i, ret; + unsigned long gpio_bits = id->driver_info; + u8 buf[2]; + + /* Allocate the URB lists along with the device info struct */ + ax_info = kmalloc(sizeof(struct ax8817x_info) + + n_rx_urbs * sizeof(struct urb *), GFP_KERNEL); + if (ax_info == NULL) { + err("%s: Failed ax alloc\n", __FUNCTION__); + goto exit_err; + } + + memset(ax_info, 0, sizeof(struct ax8817x_info) + + n_rx_urbs * sizeof(struct urb *)); + + ax_info->drv_state = AX_DRV_STATE_INITIALIZING; + ax_info->rx_urbs = (struct urb **) (ax_info + 1); + ax_info->usb = usb; + + /* Set up the control URB queue */ + + INIT_LIST_HEAD(&ax_info->ctl_queue); + spin_lock_init(&ax_info->ctl_lock); + ax_info->ctl_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->ctl_urb == NULL) { + goto exit_err_free_ax; + } + + /* Toggle the GPIOs in a manufacturer/model specific way */ + + for (i = 2; i >= 0; i--) { + ret = ax_write_cmd(ax_info, AX_CMD_WRITE_GPIOS, + (gpio_bits >> (i * 8)) & 0xff, 0, 0, + buf); + if (ret < 0) { + goto exit_err_free_ax; + } + wait_ms(5); + } + + /* Set up the net device */ + + net = alloc_etherdev(0); + if (net == NULL) { + err("%s: Failed net alloc\n", __FUNCTION__); + goto exit_err_free_ax; + } + + ax_info->net = net; + + SET_MODULE_OWNER(net); + net->init = ax8817x_net_init; + net->priv = ax_info; + + ret = register_netdev(net); + if (ret < 0) { + err("%s: Failed net init (%d)\n", __FUNCTION__, ret); + goto exit_err_free_net; + } + + /* Setup mii structure */ + ax_info->mii.dev = net; + ax_info->mii.mdio_read = mdio_read; + ax_info->mii.mdio_write = mdio_write; + ax_info->mii.phy_id_mask = 0x1f; + ax_info->mii.reg_num_mask = 0x1f; + + /* Set up the interrupt URB, and start PHY state monitoring */ + + ax_info->int_urb = usb_alloc_urb(0, GFP_KERNEL); + if (ax_info->int_urb == NULL) { + goto exit_err_unregister_net; + } + ax_info->int_buf = kmalloc(8, GFP_KERNEL); + if (ax_info->int_buf == NULL) { + goto exit_err_free_int_urb; + } + ax_info->phy_req.data = kmalloc(2, GFP_KERNEL); + if (ax_info->phy_req.data == NULL) { + goto exit_err_free_int_buf; + } + + usb_fill_int_urb(ax_info->int_urb, usb, usb_rcvintpipe(usb, 1), + ax_info->int_buf, 8, ax_int_callback, ax_info, + 100); + + ret = usb_submit_urb(ax_info->int_urb, GFP_ATOMIC); + if (ret < 0) { + err("%s: Failed int URB submit (%d)\n", __FUNCTION__, ret); + goto exit_err_free_phy_buf; + } + + ax_info->drv_state = AX_DRV_STATE_RUNNING; + usb_set_intfdata(intf, ax_info); + + return 0; + + exit_err_free_phy_buf: + kfree(ax_info->phy_req.data); + + exit_err_free_int_buf: + kfree(ax_info->int_buf); + + exit_err_free_int_urb: + usb_free_urb(ax_info->int_urb); + + exit_err_unregister_net: + ax_info->drv_state = AX_DRV_STATE_EXITING; + unregister_netdev(net); + + exit_err_free_net: + kfree(net); + + exit_err_free_ax: + if (ax_info->ctl_urb != NULL) { + /* no need to unlink, since there should not be any ctl URBs + pending at this point */ + usb_free_urb(ax_info->ctl_urb); + } + + kfree(ax_info); + +exit_err: + err("%s: Failed to initialize\n", __FUNCTION__); + return -EIO; +} + +static void ax8817x_disconnect(struct usb_interface *intf) +{ + struct ax8817x_info *ax_info = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + if (ax_info) { + ax_info->drv_state = AX_DRV_STATE_EXITING; + + if (ax_info->int_urb != NULL) { + usb_unlink_urb(ax_info->int_urb); + usb_free_urb(ax_info->int_urb); + kfree(ax_info->int_buf); + } + + unregister_netdev(ax_info->net); + + /* XXX: hmmm... need to go through and clear out the ctl queue, too... */ + if (ax_info->ctl_urb != NULL) { + usb_unlink_urb(ax_info->ctl_urb); + usb_free_urb(ax_info->ctl_urb); + } + + kfree(ax_info); + } +} + +static struct usb_driver ax8817x_driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .probe = ax8817x_bind, + .disconnect = ax8817x_disconnect, + .id_table = ax8817x_id_table, +}; + +static int __init ax8817x_init(void) +{ + int ret; + + if (n_rx_urbs < 1) + n_rx_urbs = AX_RX_URBS_DEFAULT; + + ret = usb_register(&ax8817x_driver); + if (ret < 0) { + err("%s: Failed to register\n", __FUNCTION__); + } else { + info(DRIVER_DESC " " DRIVER_VERSION); + } + + return ret; +} + +static void __exit ax8817x_exit(void) +{ + usb_deregister(&ax8817x_driver); +} + +module_init(ax8817x_init); +module_exit(ax8817x_exit); diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c --- a/drivers/usb/net/catc.c Tue Jun 10 15:21:55 2003 +++ b/drivers/usb/net/catc.c Mon Jun 16 07:51:29 2003 @@ -667,7 +667,7 @@ /* * ioctl's */ -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { struct catc *catc = dev->priv; u32 cmd; @@ -726,7 +726,7 @@ { switch(cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(dev, (void __user *)rq->ifr_data); default: return -EOPNOTSUPP; } diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Tue Jun 10 15:21:55 2003 +++ b/drivers/usb/net/kaweth.c Wed Jun 18 03:23:55 2003 @@ -225,13 +225,17 @@ struct urb *rx_urb; struct urb *tx_urb; struct urb *irq_urb; + + dma_addr_t intbufferhandle; + __u8 *intbuffer; + dma_addr_t rxbufferhandle; + __u8 *rx_buf; + struct sk_buff *tx_skb; __u8 *firmware_buf; __u8 scratch[KAWETH_SCRATCH_SIZE]; - __u8 rx_buf[KAWETH_BUF_SIZE]; - __u8 intbuffer[INTBUFFERSIZE]; __u16 packet_filter_bitmap; struct kaweth_ethernet_configuration configuration; @@ -524,6 +528,8 @@ KAWETH_BUF_SIZE, kaweth_usb_receive, kaweth); + kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; if((result = usb_submit_urb(kaweth->rx_urb, mem_flags))) { if (result == -ENOMEM) @@ -532,7 +538,7 @@ } else { kaweth->suspend_lowmem = 0; } - + return result; } @@ -630,6 +636,8 @@ int_callback, kaweth, HZ/4); + kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; + kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL); if (res) { @@ -662,13 +670,13 @@ return 0; } -static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; - + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; - + switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; @@ -678,7 +686,7 @@ return 0; } } - + return -EOPNOTSUPP; } @@ -689,7 +697,7 @@ { switch (cmd) { case SIOCETHTOOL: - return netdev_ethtool_ioctl(net, (void *) rq->ifr_data); + return netdev_ethtool_ioctl(net, (void __user *)rq->ifr_data); } return -EOPNOTSUPP; } @@ -1033,6 +1041,19 @@ if (!kaweth->irq_urb) goto err_tx_and_rx; + kaweth->intbuffer = usb_buffer_alloc( kaweth->dev, + INTBUFFERSIZE, + GFP_KERNEL, + &kaweth->intbufferhandle); + if (!kaweth->intbuffer) + goto err_tx_and_rx_and_irq; + kaweth->rx_buf = usb_buffer_alloc( kaweth->dev, + KAWETH_BUF_SIZE, + GFP_KERNEL, + &kaweth->rxbufferhandle); + if (!kaweth->rx_buf) + goto err_all_but_rxbuf; + kaweth->net = netdev; memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr)); memcpy(kaweth->net->dev_addr, @@ -1053,7 +1074,7 @@ kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size); memset(&kaweth->stats, 0, sizeof(kaweth->stats)); - + SET_MODULE_OWNER(netdev); usb_set_intfdata(intf, kaweth); @@ -1071,6 +1092,12 @@ err_intfdata: usb_set_intfdata(intf, NULL); +err_all: + usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); +err_all_but_rxbuf: + usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); +err_tx_and_rx_and_irq: + usb_free_urb(kaweth->irq_urb); err_tx_and_rx: usb_free_urb(kaweth->rx_urb); err_only_tx: @@ -1123,6 +1150,11 @@ usb_free_urb(kaweth->rx_urb); usb_free_urb(kaweth->tx_urb); + usb_free_urb(kaweth->irq_urb); + + + usb_buffer_free(kaweth->dev, KAWETH_BUF_SIZE, (void *)kaweth->rx_buf, kaweth->rxbufferhandle); + usb_buffer_free(kaweth->dev, INTBUFFERSIZE, (void *)kaweth->intbuffer, kaweth->intbufferhandle); kfree(kaweth); } diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c Tue Jun 10 15:21:55 2003 +++ b/drivers/usb/net/pegasus.c Mon Jun 16 07:51:29 2003 @@ -945,7 +945,7 @@ return 0; } #ifdef CONFIG_MII -static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr) +static int pegasus_ethtool_ioctl(struct net_device *dev, void __user *useraddr) { u32 ethcmd; @@ -1024,7 +1024,7 @@ } #else -static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) +static int pegasus_ethtool_ioctl(struct net_device *net, void __user *uaddr) { pegasus_t *pegasus; int cmd; @@ -1113,7 +1113,7 @@ switch (cmd) { case SIOCETHTOOL: - res = pegasus_ethtool_ioctl(net, rq->ifr_data); + res = pegasus_ethtool_ioctl(net, (void __user *)rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = pegasus->phy; diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Tue Jun 10 15:21:56 2003 +++ b/drivers/usb/net/rtl8150.c Mon Jun 16 07:51:29 2003 @@ -673,7 +673,7 @@ return res; } -static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) +static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr) { rtl8150_t *dev; int cmd; @@ -758,7 +758,7 @@ switch (cmd) { case SIOCETHTOOL: - res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); + res = rtl8150_ethtool_ioctl(netdev, (void __user *)rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = dev->phy; diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Thu Jun 5 00:49:31 2003 +++ b/drivers/usb/net/usbnet.c Tue Jun 17 07:37:03 2003 @@ -1622,6 +1622,11 @@ .check_connect = always_connected, }; +static const struct driver_info blob_info = { + .description = "Boot Loader OBject", + .check_connect = always_connected, +}; + #endif /* CONFIG_USB_ARMLINUX */ @@ -2097,7 +2102,7 @@ /*-------------------------------------------------------------------------*/ static inline int -usbnet_ethtool_ioctl (struct net_device *net, void *useraddr) +usbnet_ethtool_ioctl (struct net_device *net, void __user *useraddr) { struct usbnet *dev = (struct usbnet *) net->priv; u32 cmd; @@ -2161,7 +2166,7 @@ { switch (cmd) { case SIOCETHTOOL: - return usbnet_ethtool_ioctl (net, (void *)rq->ifr_data); + return usbnet_ethtool_ioctl (net, (void __user *)rq->ifr_data); default: return -EOPNOTSUPP; } @@ -2707,6 +2712,9 @@ }, { USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" .driver_info = (unsigned long) &yopy_info, +}, { + USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader + .driver_info = (unsigned long) &blob_info, }, #endif diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Sun Jun 1 12:24:07 2003 +++ b/drivers/usb/storage/isd200.c Sun Jun 15 09:23:56 2003 @@ -548,10 +548,9 @@ /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("-- transport indicates command was aborted\n"); - srb->result = DID_ABORT << 16; - return; + if (us->sm_state == US_STATE_ABORTING) { + US_DEBUGP("-- command was aborted\n"); + goto Handle_Abort; } switch (transferStatus) { @@ -561,6 +560,11 @@ srb->result = SAM_STAT_GOOD; break; + case USB_STOR_TRANSPORT_NO_SENSE: + US_DEBUGP("-- transport indicates protocol failure\n"); + srb->result = SAM_STAT_CHECK_CONDITION; + return; + case USB_STOR_TRANSPORT_FAILED: US_DEBUGP("-- transport indicates command failure\n"); need_auto_sense = 1; @@ -591,10 +595,9 @@ if (need_auto_sense) { result = isd200_read_regs(us); - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- auto-sense aborted\n"); - srb->result = DID_ABORT << 16; - return; + goto Handle_Abort; } if (result == ISD200_GOOD) { isd200_build_sense(us, srb); @@ -603,8 +606,10 @@ /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) srb->result = SAM_STAT_GOOD; - } else + } else { srb->result = DID_ERROR << 16; + /* Need reset here */ + } } /* Regardless of auto-sense, if we _know_ we have an error @@ -612,6 +617,16 @@ */ if (transferStatus == USB_STOR_TRANSPORT_FAILED) srb->result = SAM_STAT_CHECK_CONDITION; + return; + + /* abort processing: the bulk-only transport requires a reset + * following an abort */ + Handle_Abort: + srb->result = DID_ABORT << 16; + + /* permit the reset transfer to take place */ + clear_bit(US_FLIDX_ABORTING, &us->flags); + /* Need reset here */ } #ifdef CONFIG_USB_STORAGE_DEBUG diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c Sun Jun 1 12:24:07 2003 +++ b/drivers/usb/storage/protocol.c Mon Jun 16 10:19:34 2003 @@ -82,6 +82,10 @@ if (srb->cmnd[0] != INQUIRY) return; + /* oddly short buffer -- bail out */ + if (srb->request_bufflen < 3) + return; + data_ptr = find_data_location(srb); if ((data_ptr[2] & 7) == 2) diff -Nru a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h --- a/drivers/usb/storage/protocol.h Sat Jan 25 05:27:28 2003 +++ b/drivers/usb/storage/protocol.h Sun Jun 15 09:23:52 2003 @@ -57,6 +57,8 @@ #define US_SC_MIN US_SC_RBC #define US_SC_MAX US_SC_ISD200 +#define US_SC_DEVICE 0xff /* Use device's value */ + extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Sun Jun 1 12:09:08 2003 +++ b/drivers/usb/storage/scsiglue.c Wed Jun 18 10:51:24 2003 @@ -57,100 +57,36 @@ * Host functions ***********************************************************************/ -static const char* usb_storage_info(struct Scsi_Host *host) +static const char* host_info(struct Scsi_Host *host) { return "SCSI emulation for USB Mass Storage devices"; } -#if 0 -/* detect a virtual adapter (always works) - * Synchronization: 2.4: with the io_request_lock - * 2.5: no locks. - * fortunately we don't care. - * */ -static int usb_storage_detect(struct SHT *sht) +static int slave_configure (struct scsi_device *sdev) { - struct us_data *us; - char local_name[32]; - - /* This is not nice at all, but how else are we to get the - * data here? */ - us = (struct us_data *)sht->proc_dir; - - /* set up the name of our subdirectory under /proc/scsi/ */ - sprintf(local_name, "usb-storage-%d", us->host_number); - sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_ATOMIC); - if (!sht->proc_name) - return 0; - strcpy(sht->proc_name, local_name); - - /* we start with no /proc directory entry */ - sht->proc_dir = NULL; - - /* register the host */ - us->host = scsi_register(sht, sizeof(us)); - if (us->host) { - struct usb_interface *iface; - us->host->hostdata[0] = (unsigned long)us; - us->host_no = us->host->host_no; - iface = usb_ifnum_to_if(us->pusb_dev, us->ifnum); - if (iface) - scsi_set_device(us->host, &iface->dev); - return 1; - } + /* set device to use 10-byte commands where possible */ + sdev->use_10_for_ms = 1; + sdev->use_10_for_rw = 1; - /* odd... didn't register properly. Abort and free pointers */ - kfree(sht->proc_name); - sht->proc_name = NULL; + /* this is to satisify the compiler, tho I don't think the + * return code is ever checked anywhere. */ return 0; } -/* Release all resources used by the virtual host - * - * NOTE: There is no contention here, because we're already deregistered - * the driver and we're doing each virtual host in turn, not in parallel - * Synchronization: BKL, no spinlock. - */ -static int usb_storage_release(struct Scsi_Host *psh) -{ - struct us_data *us = (struct us_data *)psh->hostdata[0]; - - US_DEBUGP("release() called for host %s\n", us->htmplt.name); - - /* Kill the control threads - * - * Enqueue the command, wake up the thread, and wait for - * notification that it has exited. - */ - US_DEBUGP("-- sending exit command to thread\n"); - BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); - us->srb = NULL; - up(&(us->sema)); - wait_for_completion(&(us->notify)); - - /* remove the pointer to the data structure we were using */ - (struct us_data*)psh->hostdata[0] = NULL; - - /* we always have a successful release */ - return 0; -} -#endif - /* queue a command */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); - US_DEBUGP("queuecommand() called\n"); + US_DEBUGP("%s called\n", __FUNCTION__); srb->host_scribble = (unsigned char *)us; /* enqueue the command */ - if (state != US_STATE_IDLE || us->srb != NULL) { + if (us->sm_state != US_STATE_IDLE || us->srb != NULL) { printk(KERN_ERR USB_STORAGE "Error in %s: " "state = %d, us->srb = %p\n", - __FUNCTION__, state, us->srb); + __FUNCTION__, us->sm_state, us->srb); return SCSI_MLQUEUE_HOST_BUSY; } @@ -169,11 +105,10 @@ /* Command abort */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_command_abort( Scsi_Cmnd *srb ) +static int command_abort( Scsi_Cmnd *srb ) { struct Scsi_Host *host = srb->device->host; struct us_data *us = (struct us_data *) host->hostdata[0]; - int state = atomic_read(&us->sm_state); US_DEBUGP("%s called\n", __FUNCTION__); @@ -186,20 +121,20 @@ /* Normally the current state is RUNNING. If the control thread * hasn't even started processing this command, the state will be * IDLE. Anything else is a bug. */ - if (state != US_STATE_RUNNING && state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_RUNNING + && us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* Set state to ABORTING, set the ABORTING bit, and release the lock */ - atomic_set(&us->sm_state, US_STATE_ABORTING); + us->sm_state = US_STATE_ABORTING; set_bit(US_FLIDX_ABORTING, &us->flags); scsi_unlock(host); - /* If the state was RUNNING, stop an ongoing USB transfer */ - if (state == US_STATE_RUNNING) - usb_stor_stop_transport(us); + /* Stop an ongoing USB transfer */ + usb_stor_stop_transport(us); /* Wait for the aborted command to finish */ wait_for_completion(&us->notify); @@ -213,35 +148,30 @@ /* This invokes the transport reset mechanism to reset the state of the * device */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_device_reset( Scsi_Cmnd *srb ) +static int device_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); int result; US_DEBUGP("%s called\n", __FUNCTION__); - if (state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RESETTING); + us->sm_state = US_STATE_RESETTING; scsi_unlock(srb->device->host); - /* lock the device pointers */ + /* lock the device pointers and do the reset */ down(&(us->dev_semaphore)); - - /* do the reset */ result = us->transport_reset(us); - - /* unlock */ up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(srb->device->host); - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; return result; } @@ -249,45 +179,42 @@ /* It refuses to work if there's more than one interface in * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -static int usb_storage_bus_reset( Scsi_Cmnd *srb ) +static int bus_reset( Scsi_Cmnd *srb ) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int state = atomic_read(&us->sm_state); int result; US_DEBUGP("%s called\n", __FUNCTION__); - if (state != US_STATE_IDLE) { + if (us->sm_state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); + "invalid state %d\n", __FUNCTION__, us->sm_state); return FAILED; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RESETTING); + us->sm_state = US_STATE_RESETTING; scsi_unlock(srb->device->host); /* The USB subsystem doesn't handle synchronisation between - a device's several drivers. Therefore we reset only devices - with just one interface, which we of course own. - */ - - //FIXME: needs locking against config changes - - if (us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + * a device's several drivers. Therefore we reset only devices + * with just one interface, which we of course own. */ - /* lock the device and attempt to reset the port */ - down(&(us->dev_semaphore)); - result = usb_reset_device(us->pusb_dev); - up(&(us->dev_semaphore)); - US_DEBUGP("usb_reset_device returns %d\n", result); - } else { + down(&(us->dev_semaphore)); + if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + result = -EIO; + US_DEBUGP("Attempt to reset during disconnect\n"); + } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { result = -EBUSY; US_DEBUGP("Refusing to reset a multi-interface device\n"); + } else { + result = usb_reset_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); } + up(&(us->dev_semaphore)); /* lock access to the state and clear it */ scsi_lock(srb->device->host); - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; return result < 0 ? FAILED : SUCCESS; } @@ -300,7 +227,7 @@ #define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) -static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, +static int proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, int length, int inout) { struct us_data *us; @@ -333,8 +260,6 @@ #define DO_FLAG(a) if (f & US_FL_##a) pos += sprintf(pos, " " #a) DO_FLAG(SINGLE_LUN); DO_FLAG(MODE_XLATE); - DO_FLAG(START_STOP); - DO_FLAG(IGNORE_SER); DO_FLAG(SCM_MULT_TARG); DO_FLAG(FIX_INQUIRY); DO_FLAG(FIX_CAPACITY); @@ -360,29 +285,20 @@ * this defines our host template, with which we'll allocate hosts */ -struct SHT usb_stor_host_template = { +struct scsi_host_template usb_stor_host_template = { /* basic userland interface stuff */ .name = "usb-storage", .proc_name = "usb-storage", - .proc_info = usb_storage_proc_info, - .proc_dir = NULL, - .info = usb_storage_info, - .ioctl = NULL, - - /* old-style detect and release */ - .detect = NULL, - .release = NULL, + .proc_info = proc_info, + .info = host_info, /* command interface -- queued only */ - .command = NULL, - .queuecommand = usb_storage_queuecommand, + .queuecommand = queuecommand, /* error and abort handlers */ - .eh_abort_handler = usb_storage_command_abort, - .eh_device_reset_handler = usb_storage_device_reset, - .eh_bus_reset_handler = usb_storage_bus_reset, - .eh_host_reset_handler = NULL, - .eh_strategy_handler = NULL, + .eh_abort_handler = command_abort, + .eh_device_reset_handler = device_reset, + .eh_bus_reset_handler = bus_reset, /* queue commands only, only one command per LUN */ .can_queue = 1, @@ -391,21 +307,11 @@ /* unknown initiator id */ .this_id = -1, - /* no limit on commands */ - .max_sectors = 0, - - /* pre- and post- device scan functions */ - .slave_alloc = NULL, - .slave_configure = NULL, - .slave_destroy = NULL, + .slave_configure = slave_configure, /* lots of sg segments can be handled */ .sg_tablesize = SG_ALL, - /* use 32-bit address space for DMA */ - .unchecked_isa_dma = FALSE, - .highmem_io = FALSE, - /* merge commands... this seems to help performance, but * periodically someone should test to see which setting is more * optimal. @@ -414,9 +320,6 @@ /* emulated HBA */ .emulated = TRUE, - - /* sorry, no BIOS to help us */ - .bios_param = NULL, /* module management */ .module = THIS_MODULE diff -Nru a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h --- a/drivers/usb/storage/scsiglue.h Sun Jan 19 06:10:31 2003 +++ b/drivers/usb/storage/scsiglue.h Thu Jun 5 11:52:51 2003 @@ -47,7 +47,7 @@ extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_invalidCDB[18]; -extern struct SHT usb_stor_host_template; +extern struct scsi_host_template usb_stor_host_template; extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Sun Jun 8 07:15:59 2003 +++ b/drivers/usb/storage/transport.c Sun Jun 15 09:23:56 2003 @@ -136,9 +136,9 @@ struct timer_list to_timer; int status; - /* don't submit URBS during abort/disconnect processing */ + /* don't submit URBs during abort/disconnect processing */ if (us->flags & DONT_SUBMIT) - return -ECONNRESET; + return -EIO; /* set up data structures for the wakeup system */ init_completion(&urb_done); @@ -299,17 +299,17 @@ return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; - /* NAK - that means we've retried this a few times already */ + /* timeout or excessively long NAK */ case -ETIMEDOUT: - US_DEBUGP("-- device NAKed\n"); + US_DEBUGP("-- timeout or NAK\n"); return USB_STOR_XFER_ERROR; /* babble - the device tried to send more than we wanted to read */ case -EOVERFLOW: - US_DEBUGP("-- Babble\n"); + US_DEBUGP("-- babble\n"); return USB_STOR_XFER_LONG; - /* the transfer was cancelled, presumably by an abort */ + /* the transfer was cancelled by abort, disconnect, or timeout */ case -ECONNRESET: US_DEBUGP("-- transfer cancelled\n"); return USB_STOR_XFER_ERROR; @@ -319,6 +319,11 @@ US_DEBUGP("-- short read transfer\n"); return USB_STOR_XFER_SHORT; + /* abort or disconnect in progress */ + case -EIO: + US_DEBUGP("-- abort or disconnect in progress\n"); + return USB_STOR_XFER_ERROR; + /* the catch-all error case */ default: US_DEBUGP("-- unknown error\n"); @@ -430,7 +435,7 @@ /* initialize the scatter-gather request block */ US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__, length, num_sg); - result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0, + result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, sg, num_sg, length, SLAB_NOIO); if (result) { US_DEBUGP("usb_sg_init returned %d\n", result); @@ -447,19 +452,19 @@ /* cancel the request, if it hasn't been cancelled already */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(us->current_sg); + usb_sg_cancel(&us->current_sg); } } /* wait for the completion of the transfer */ - usb_sg_wait(us->current_sg); + usb_sg_wait(&us->current_sg); clear_bit(US_FLIDX_SG_ACTIVE, &us->flags); - result = us->current_sg->status; + result = us->current_sg.status; if (act_len) - *act_len = us->current_sg->bytes; + *act_len = us->current_sg.bytes; return interpret_urb_result(us, pipe, length, result, - us->current_sg->bytes); + us->current_sg.bytes); } /* @@ -518,7 +523,7 @@ /* if the command gets aborted by the higher layers, we need to * short-circuit all other processing */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- command was aborted\n"); goto Handle_Abort; } @@ -650,7 +655,7 @@ srb->cmd_len = old_cmd_len; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { US_DEBUGP("-- auto-sense aborted\n"); goto Handle_Abort; } @@ -734,7 +739,7 @@ /* If we are waiting for a scatter-gather operation, cancel it. */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(us->current_sg); + usb_sg_cancel(&us->current_sg); } } diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Sun Jun 8 07:15:59 2003 +++ b/drivers/usb/storage/transport.h Sun Jun 15 09:23:52 2003 @@ -63,16 +63,18 @@ #define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ #ifdef CONFIG_USB_STORAGE_FREECOM -#define US_PR_FREECOM 0xf1 /* Freecom */ +#define US_PR_FREECOM 0xf1 /* Freecom */ #endif #ifdef CONFIG_USB_STORAGE_DATAFAB -#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ +#define US_PR_DATAFAB 0xf2 /* Datafab chipsets */ #endif #ifdef CONFIG_USB_STORAGE_JUMPSHOT -#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ +#define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ #endif + +#define US_PR_DEVICE 0xff /* Use device's value */ /* * Bulk only data structures diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Thu May 22 11:55:38 2003 +++ b/drivers/usb/storage/unusual_devs.h Tue Jun 17 10:44:19 2003 @@ -75,28 +75,26 @@ /* Deduced by Jonathan Woithe * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message - * always fails and confuses drive; without US_FL_START_STOP, drive accesses - * (read or write) all fail. + * always fails and confuses drive. */ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, "Buffalo", "DUB-P40G HDD", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY | US_FL_START_STOP), + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_INQUIRY ), #ifdef CONFIG_USB_STORAGE_DPCM UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), + US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), #endif /* Made with the help of Edd Dumbill */ UNUSUAL_DEV( 0x0451, 0x5409, 0x0001, 0x0001, "Frontier Labs", "Nex II Digital", - US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP), + US_SC_SCSI, US_PR_BULK, NULL, 0), /* Patch submitted by Philipp Friedrich */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, @@ -124,15 +122,6 @@ "785EPX Storage", US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN), -/* Reported by Jan Willamowius - * The device needs the flags only. - */ -UNUSUAL_DEV( 0x04c8, 0x0723, 0x0000, 0x9999, - "Konica", - "KD-200Z", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP), - UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, "Fujifilm", "FinePix 1400Zoom", @@ -144,7 +133,7 @@ UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074, "ScanLogic", "SL11R-IDE", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), /* Reported by Kriston Fincher @@ -183,14 +172,14 @@ "Sandisk", "ImageMate SDDR09", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* This entry is from Andries.Brouwer@cwi.nl */ UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, "SCM Microsystems", "eUSB SmartMedia / CompactFlash Adapter", US_SC_SCSI, US_PR_DPCM_USB, sddr09_init, - US_FL_START_STOP), + 0), #endif UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0205, @@ -247,40 +236,40 @@ "Iomega", "USB Clik! 40", US_SC_8070, US_PR_BULK, NULL, - US_FL_FIX_INQUIRY | US_FL_START_STOP ), + US_FL_FIX_INQUIRY ), /* This entry is needed because the device reports Sub=ff */ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, "Sony", "DSC-S30/S70/S75/505V/F505/F707/F717/P8", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), + US_FL_SINGLE_LUN | US_FL_MODE_XLATE ), /* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", "Memorystick NW-MS7", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, "Sony", "Memorystick MSAC-US1", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* Submitted by Klaus Mueller */ UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310, "Sony", "Handycam", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE), + US_FL_SINGLE_LUN | US_FL_MODE_XLATE), UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, "Sony", "Memorystick MSC-U01N", US_SC_UFI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), /* Submitted by Nathan Babb */ UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, @@ -316,7 +305,7 @@ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, "Pentax", "Optio 2/3/400", - US_SC_8070, US_PR_CBI, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Submitted by Per Winkvist */ @@ -380,7 +369,7 @@ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, "SIIG", "CompactFlash Card Reader", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Reported by Peter Marks @@ -393,7 +382,7 @@ UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001, "EagleTec", "External Hard Disk", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0x9999, @@ -402,6 +391,14 @@ US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), +/* Reported by Hanno Boeck + * Taken from the Lycoris Kernel */ +UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, + "Vivitar", + "Vivicam 35Xx", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY | US_FL_MODE_XLATE), + UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, "TEAC", "Floppy Drive", @@ -412,25 +409,9 @@ "Olympus", "Camedia MAUSB-2", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), #endif -/* Submitted by kedar@centillium - * Needed for START_STOP flag, but that is unconfirmed */ -UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - -/* Submitted by f.brugmans@hccnet.nl - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001, - "Minolta", - "Dimage S304", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), - UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", "FlashGate SmartMedia", @@ -445,13 +426,12 @@ "Sandisk", "ImageMate SDDR-05a", US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP), + US_FL_SINGLE_LUN ), UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk", "ImageMate SDDR-31", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_IGNORE_SER), + US_SC_SCSI, US_PR_BULK, NULL, 0 ), UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -464,7 +444,7 @@ "Sandisk", "ImageMate SDDR-09", US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP ), + US_FL_SINGLE_LUN ), #endif #ifdef CONFIG_USB_STORAGE_FREECOM @@ -490,8 +470,7 @@ UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, "Microtech", "CameraMate (DPCM_USB)", - US_SC_SCSI, US_PR_DPCM_USB, NULL, - US_FL_START_STOP ), + US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ), #endif #ifdef CONFIG_USB_STORAGE_DATAFAB @@ -568,7 +547,7 @@ UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, "Datafab", "KECF-USB", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant @@ -629,20 +608,7 @@ "Global Channel Solutions", "EasyDisk EDxxxx", US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), - -/* Submitted by Brian Hall - * Needed for START_STOP flag */ -UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, - "JMTek", - "USBDrive", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), -UNUSUAL_DEV( 0x0c76, 0x0005, 0x0100, 0x0100, - "JMTek", - "USBDrive", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_START_STOP ), + US_FL_MODE_XLATE | US_FL_FIX_INQUIRY ), /* Reported by Dan Pilone * The device needs the flags only. @@ -652,8 +618,8 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x9999, "CCYU TECHNOLOGY", "EasyDisk Portable Device", - US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP), + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MODE_XLATE ), #ifdef CONFIG_USB_STORAGE_SDDR55 UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999, @@ -670,5 +636,5 @@ "AIPTEK", "PocketCAM 3Mega", US_SC_SCSI, US_PR_BULK, NULL, - US_FL_MODE_XLATE | US_FL_START_STOP), + US_FL_MODE_XLATE ), diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Sun Jun 8 07:15:45 2003 +++ b/drivers/usb/storage/usb.c Wed Jun 18 10:45:25 2003 @@ -102,8 +102,6 @@ /* The entries in this table, except for final ones here * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, * line for line with the entries of us_unsuaul_dev_list[]. - * For now, we duplicate idVendor and idProduct in us_unsual_dev_list, - * just to avoid alignment bugs. */ #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ @@ -328,13 +326,13 @@ scsi_lock(host); /* has the command been aborted *already* ? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + if (us->sm_state == US_STATE_ABORTING) { us->srb->result = DID_ABORT << 16; goto SkipForAbort; } /* set the state and release the lock */ - atomic_set(&us->sm_state, US_STATE_RUNNING); + us->sm_state = US_STATE_RUNNING; scsi_unlock(host); /* lock the device pointers */ @@ -353,7 +351,7 @@ */ else if (us->srb->device->id && !(us->flags & US_FL_SCM_MULT_TARG)) { - US_DEBUGP("Bad target number (%d/%d)\n", + US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } @@ -404,12 +402,12 @@ * sm_state == US_STATE_ABORTING, not srb->result == DID_ABORT, * because an abort request might be received after all the * USB processing was complete. */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) + if (us->sm_state == US_STATE_ABORTING) complete(&(us->notify)); /* empty the queue, reset the state, and release the lock */ us->srb = NULL; - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; scsi_unlock(host); } /* for (;;) */ @@ -424,10 +422,13 @@ ***********************************************************************/ /* Get the unusual_devs entries and the string descriptors */ -static void get_device_info(struct us_data *us, - struct us_unusual_dev *unusual_dev) +static void get_device_info(struct us_data *us, int id_index) { struct usb_device *dev = us->pusb_dev; + struct usb_host_interface *altsetting = + &us->pusb_intf->altsetting[us->pusb_intf->act_altsetting]; + struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; + struct usb_device_id *id = &storage_usb_ids[id_index]; if (unusual_dev->vendorName) US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); @@ -436,10 +437,40 @@ /* Store the entries */ us->unusual_dev = unusual_dev; - us->subclass = unusual_dev->useProtocol; - us->protocol = unusual_dev->useTransport; + us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? + altsetting->desc.bInterfaceSubClass : + unusual_dev->useProtocol; + us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ? + altsetting->desc.bInterfaceProtocol : + unusual_dev->useTransport; us->flags = unusual_dev->flags; + /* Log a message if a non-generic unusual_dev entry contains an + * unnecessary subclass or protocol override. This may stimulate + * reports from users that will help us remove unneeded entries + * from the unusual_devs.h table. + */ + if (id->idVendor || id->idProduct) { + static char *msgs[3] = { + "an unneeded SubClass entry", + "an unneeded Protocol entry", + "unneeded SubClass and Protocol entries"}; + int msg = -1; + + if (unusual_dev->useProtocol != US_SC_DEVICE && + us->subclass == altsetting->desc.bInterfaceSubClass) + msg += 1; + if (unusual_dev->useTransport != US_PR_DEVICE && + us->protocol == altsetting->desc.bInterfaceProtocol) + msg += 2; + if (msg >= 0) + printk(KERN_NOTICE USB_STORAGE "This device " + "(%04x,%04x) has %s in unusual_devs.h\n" + " Please send a copy of this message to " + "\n", + id->idVendor, id->idProduct, msgs[msg]); + } + /* Read the device's string descriptors */ if (dev->descriptor.iManufacturer) usb_string(dev, dev->descriptor.iManufacturer, @@ -447,7 +478,7 @@ if (dev->descriptor.iProduct) usb_string(dev, dev->descriptor.iProduct, us->product, sizeof(us->product)); - if (dev->descriptor.iSerialNumber && !(us->flags & US_FL_IGNORE_SER)) + if (dev->descriptor.iSerialNumber) usb_string(dev, dev->descriptor.iSerialNumber, us->serial, sizeof(us->serial)); @@ -698,13 +729,6 @@ return -ENOMEM; } - US_DEBUGP("Allocating scatter-gather request block\n"); - us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL); - if (!us->current_sg) { - US_DEBUGP("allocation failed\n"); - return -ENOMEM; - } - /* Lock the device while we carry out the next two operations */ down(&us->dev_semaphore); @@ -720,7 +744,7 @@ up(&us->dev_semaphore); /* Start up our control thread */ - atomic_set(&us->sm_state, US_STATE_IDLE); + us->sm_state = US_STATE_IDLE; p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); if (p < 0) { printk(KERN_WARNING USB_STORAGE @@ -736,7 +760,7 @@ * Since this is a new device, we need to register a SCSI * host definition with the higher SCSI layers. */ - us->host = scsi_register(&usb_stor_host_template, sizeof(us)); + us->host = scsi_host_alloc(&usb_stor_host_template, sizeof(us)); if (!us->host) { printk(KERN_WARNING USB_STORAGE "Unable to register the scsi host\n"); @@ -772,7 +796,7 @@ /* Finish the SCSI host removal sequence */ if (us->host) { (struct us_data *) us->host->hostdata[0] = NULL; - scsi_unregister(us->host); + scsi_host_put(us->host); } /* Kill the control thread @@ -782,7 +806,7 @@ */ if (us->pid) { US_DEBUGP("-- sending exit command to thread\n"); - BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE); + BUG_ON(us->sm_state != US_STATE_IDLE); us->srb = NULL; up(&(us->sema)); wait_for_completion(&(us->notify)); @@ -800,8 +824,6 @@ } /* Free the USB control blocks */ - if (us->current_sg) - kfree(us->current_sg); if (us->current_urb) usb_free_urb(us->current_urb); if (us->dr) @@ -852,7 +874,7 @@ * of the match from the usb_device_id table, so we can find the * corresponding entry in the private table. */ - get_device_info(us, &us_unusual_dev_list[id_index]); + get_device_info(us, id_index); #ifdef CONFIG_USB_STORAGE_SDDR09 if (us->protocol == US_PR_EUSB_SDDR09 || diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Sun Jun 8 07:15:51 2003 +++ b/drivers/usb/storage/usb.h Sun Jun 15 09:23:52 2003 @@ -71,8 +71,6 @@ #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for Win/MacOS compatibility */ -#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ @@ -139,7 +137,7 @@ /* thread information */ int pid; /* control thread */ - atomic_t sm_state; /* what we are doing */ + int sm_state; /* what we are doing */ /* interrupt communications data */ unsigned char irqdata[2]; /* data from USB IRQ */ @@ -147,7 +145,7 @@ /* control and bulk communications data */ struct urb *current_urb; /* non-int USB requests */ struct usb_ctrlrequest *dr; /* control requests */ - struct usb_sg_request *current_sg; /* scatter-gather USB */ + struct usb_sg_request current_sg; /* scatter-gather USB */ /* the semaphore for sleeping the control thread */ struct semaphore sema; /* to sleep thread on */ diff -Nru a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/Kconfig.binfmt Sun Jun 15 09:07:21 2003 @@ -0,0 +1,116 @@ +config BINFMT_ELF + tristate "Kernel support for ELF binaries" + depends on MMU + default y + ---help--- + ELF (Executable and Linkable Format) is a format for libraries and + executables used across different architectures and operating + systems. Saying Y here will enable your kernel to run ELF binaries + and enlarge it by about 13 KB. ELF support under Linux has now all + but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating systems + however) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. + + Information about ELF is contained in the ELF HOWTO available from + . + + If you find that after upgrading from Linux kernel 1.2 and saying Y + here, you still can't run any ELF binaries (they just crash), then + you'll have to install the newest ELF runtime libraries, including + ld.so (check the file for location and + latest version). + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called binfmt_elf. Saying M or N here is dangerous because + some crucial programs on your system might be in ELF format. + +config BINFMT_FLAT + tristate "Kernel support for flat binaries" + depends on !MMU || SUPERH + help + Support uClinux FLAT format binaries. + +config BINFMT_ZFLAT + bool "Enable ZFLAT support" + depends on BINFMT_FLAT + help + Support FLAT format compressed binaries + +config BINFMT_AOUT + tristate "Kernel support for a.out and ECOFF binaries" + depends on X86 || ALPHA || ARM || M68K || MIPS || SPARC + ---help--- + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used + the a.out formats QMAGIC and ZMAGIC until they were replaced + with the ELF format. + + The conversion to ELF started in 1995. This option is primarily + provided for historical interest and for the benefit of those + who need to run binaries from that era. + + Most people should answer N here. If you think you may have + occasional use for this format, enable module support above + and answer M here to compile this support as a module called + binfmt_aout. + + If any crucial components of your system (such as /sbin/init + or /lib/ld.so) are still in a.out format, you will have to + say Y here. + +config OSF4_COMPAT + bool "OSF/1 v4 readv/writev compatibility" + depends on ALPHA && BINFMT_AOUT + help + Say Y if you are using OSF/1 binaries (like Netscape and Acrobat) + with v4 shared libraries freely available from Compaq. If you're + going to use shared libraries from Tru64 version 5.0 or later, say N. + +config BINFMT_EM86 + tristate "Kernel support for Linux/Intel ELF binaries" + depends on ALPHA + ---help--- + Say Y here if you want to be able to execute Linux/Intel ELF + binaries just like native Alpha binaries on your Alpha machine. For + this to work, you need to have the emulator /usr/bin/em86 in place. + + You can get the same functionality by saying N here and saying Y to + "Kernel support for MISC binaries". + + You may answer M to compile the emulation support as a module and + later load the module when you want to use a Linux/Intel binary. The + module will be called binfmt_em86. If unsure, say Y. + +config BINFMT_SOM + tristate "Kernel support for SOM binaries" + depends on PARISC && HPUX + help + SOM is a binary executable format inherited from HP/UX. Say + Y here to be able to load and execute SOM binaries directly. + +config BINFMT_MISC + tristate "Kernel support for MISC binaries" + ---help--- + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + ). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. + + You can do other nice things, too. Read the file + to learn how to use this + feature, and for information about how + to include Java support. + + You may say M here for module support and later load the module when + you have use for it; the module is called binfmt_misc. If you + don't know what to answer at this point, say Y. diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES Fri May 16 09:07:44 2003 +++ b/fs/cifs/CHANGES Wed Jun 18 00:03:00 2003 @@ -1,3 +1,17 @@ +Version 0.80 +----------- +Fix oops on stopping oplock thread when removing cifs when +built as module. + +Version 0.79 +------------ +Fix mount options for ro (readonly), uid, gid and file and directory mode. + +Version 0.78 +------------ +Fix errors displayed on failed mounts to be more understandable. +Fixed various incorrect or misleading smb to posix error code mappings. + Version 0.77 ------------ Fix display of NTFS DFS junctions to display as symlinks. diff -Nru a/fs/cifs/asn1.c b/fs/cifs/asn1.c --- a/fs/cifs/asn1.c Sat Feb 15 14:10:22 2003 +++ b/fs/cifs/asn1.c Tue Jun 10 17:29:01 2003 @@ -432,7 +432,7 @@ compare_oid(unsigned long *oid1, unsigned int oid1len, unsigned long *oid2, unsigned int oid2len) { - int i; + unsigned int i; if (oid1len != oid2len) return 0; diff -Nru a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h --- a/fs/cifs/cifs_fs_sb.h Sun Apr 27 14:44:53 2003 +++ b/fs/cifs/cifs_fs_sb.h Mon Jun 9 07:31:16 2003 @@ -24,5 +24,9 @@ struct nls_table *local_nls; unsigned int rsize; unsigned int wsize; + uid_t mnt_uid; + gid_t mnt_gid; + mode_t mnt_file_mode; + mode_t mnt_dir_mode; }; #endif /* _CIFS_FS_SB_H */ diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Tue May 27 07:50:56 2003 +++ b/fs/cifs/cifsfs.c Wed Jun 18 00:03:00 2003 @@ -62,6 +62,9 @@ void cifs_proc_init(void); void cifs_proc_clean(void); +static DECLARE_COMPLETION(cifs_oplock_exited); + + static int cifs_read_super(struct super_block *sb, void *data, const char *devname, int silent) @@ -427,7 +430,8 @@ "cifs_destroy_mids: error not all structures were freed\n"); if (kmem_cache_destroy(cifs_oplock_cachep)) printk(KERN_WARNING - "error not all oplock structures were freed\n");} + "error not all oplock structures were freed\n"); +} static int cifs_oplock_thread(void * dummyarg) { @@ -439,14 +443,13 @@ int rc; daemonize("cifsoplockd"); - allow_signal(SIGKILL); + allow_signal(SIGTERM); oplockThread = current; - while (1) { + do { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(100*HZ); /* BB add missing code */ - cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */ write_lock(&GlobalMid_Lock); list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) { oplock_item = list_entry(tmp, struct oplock_q_entry, @@ -466,11 +469,10 @@ write_lock(&GlobalMid_Lock); } else break; - cFYI(1,("next time through list")); /* BB remove */ } write_unlock(&GlobalMid_Lock); - cFYI(1,("next time through while loop")); /* BB remove */ - } + } while(!signal_pending(current)); + complete_and_exit (&cifs_oplock_exited, 0); } static int __init @@ -532,8 +534,10 @@ cifs_destroy_inodecache(); cifs_destroy_mids(); cifs_destroy_request_bufs(); - if(oplockThread) - send_sig(SIGKILL, oplockThread, 1); + if(oplockThread) { + send_sig(SIGTERM, oplockThread, 1); + wait_for_completion(&cifs_oplock_exited); + } } MODULE_AUTHOR("Steve French "); diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h Tue May 13 11:00:10 2003 +++ b/fs/cifs/cifsproto.h Tue May 27 17:41:17 2003 @@ -49,7 +49,7 @@ extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); -extern int smbCalcSize(struct smb_hdr *ptr); +extern unsigned int smbCalcSize(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int map_smb_to_linux_error(struct smb_hdr *smb); diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c Tue May 27 11:28:27 2003 +++ b/fs/cifs/connect.c Tue Jun 10 05:52:17 2003 @@ -53,7 +53,7 @@ char *UNC; char *UNCip; uid_t linux_uid; - uid_t linux_gid; + gid_t linux_gid; mode_t file_mode; mode_t dir_mode; int rw; @@ -136,8 +136,8 @@ int cifs_demultiplex_thread(struct TCP_Server_Info *server) { - int length, total_read; - unsigned int pdu_length; + int length; + unsigned int pdu_length, total_read; struct smb_hdr *smb_buffer = NULL; struct msghdr smb_msg; mm_segment_t temp_fs; @@ -351,6 +351,10 @@ memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; + vol->dir_mode = S_IRWXUGO; + /* 2767 perms indicate mandatory locking support */ + vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + vol->rw = TRUE; if (!options) @@ -466,6 +470,8 @@ /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; + } else if (strnicmp(data, "ro", 2) == 0) { + vol->rw = FALSE; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } @@ -929,8 +935,11 @@ cifs_sb->rsize = PAGE_CACHE_SIZE; cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); } - - + cifs_sb->mnt_uid = volume_info.linux_uid; + cifs_sb->mnt_gid = volume_info.linux_gid; + cifs_sb->mnt_file_mode = volume_info.file_mode; + cifs_sb->mnt_dir_mode = volume_info.dir_mode; + cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c Fri May 16 09:07:44 2003 +++ b/fs/cifs/file.c Tue Jun 10 17:29:01 2003 @@ -123,8 +123,8 @@ to problems creating new read-only files */ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, cifs_sb->local_nls); else {/* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -351,8 +351,8 @@ size_t write_size, loff_t * poffset) { int rc = 0; - int bytes_written = 0; - int total_written; + unsigned int bytes_written = 0; + unsigned int total_written; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; @@ -633,9 +633,9 @@ loff_t * poffset) { int rc = -EACCES; - int bytes_read = 0; - int total_read; - int current_read_size; + unsigned int bytes_read = 0; + unsigned int total_read; + unsigned int current_read_size; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid; @@ -742,13 +742,13 @@ struct list_head *page_list, unsigned num_pages) { int rc = -EACCES; - int xid,i; + int xid; loff_t offset; struct page * page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int bytes_read = 0; - unsigned int read_size; + unsigned int read_size,i; char * smb_read_data = 0; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; @@ -877,6 +877,8 @@ FILE_DIRECTORY_INFO * pfindData, int *pobject_type) { struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); + pfindData->ExtFileAttributes = le32_to_cpu(pfindData->ExtFileAttributes); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); @@ -894,7 +896,13 @@ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ - tmp_inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + tmp_inode->i_uid = cifs_sb->mnt_uid; + tmp_inode->i_gid = cifs_sb->mnt_gid; + /* set default mode. will override for dirs below */ + tmp_inode->i_mode = cifs_sb->mnt_file_mode; + cFYI(0, ("CIFS FFIRST: Attributes came in as 0x%x", pfindData->ExtFileAttributes)); @@ -905,7 +913,7 @@ } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { *pobject_type = DT_DIR; /* override default perms since we do not lock dirs */ - tmp_inode->i_mode = S_IRWXUGO; + tmp_inode->i_mode = cifs_sb->mnt_dir_mode; tmp_inode->i_mode |= S_IFDIR; } else { *pobject_type = DT_REG; @@ -1091,10 +1099,10 @@ cifs_readdir(struct file *file, void *direntry, filldir_t filldir) { int rc = 0; - int xid, i; + int xid; int Unicode = FALSE; int UnixSearch = FALSE; - unsigned int bufsize; + unsigned int bufsize, i; __u16 searchHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c Tue May 13 11:00:11 2003 +++ b/fs/cifs/inode.c Tue Jun 10 17:29:01 2003 @@ -224,16 +224,19 @@ cifs_NTtimeToUnix(le64_to_cpu(findData.LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.ChangeTime)); - inode->i_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); /* 2767 perms indicate mandatory locking - will override for dirs later */ cFYI(0, (" Attributes came in as 0x%x ", findData.Attributes)); - if (findData.Attributes & ATTR_REPARSE) { - /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ + + /* set default mode. will override for dirs below */ + inode->i_mode = cifs_sb->mnt_file_mode; + + if (findData.Attributes & ATTR_REPARSE) { + /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ inode->i_mode |= S_IFLNK; } else if (findData.Attributes & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking on dirs */ - inode->i_mode = S_IRWXUGO; - inode->i_mode |= S_IFDIR; + /* override default perms since we do not do byte range locking on dirs */ + inode->i_mode = cifs_sb->mnt_dir_mode; + inode->i_mode |= S_IFDIR; } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only mode e.g. 555 */ @@ -250,8 +253,11 @@ (unsigned long) inode->i_size, inode->i_blocks)); inode->i_nlink = le32_to_cpu(findData.NumberOfLinks); - /* BB fill in uid and gid here? with help from winbind? */ - + /* BB fill in uid and gid here? with help from winbind? + or retrieve from NTFS stream extended attribute */ + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + if (S_ISREG(inode->i_mode)) { cFYI(1, (" File inode ")); inode->i_op = &cifs_file_inode_ops; @@ -389,8 +395,8 @@ direntry->d_inode->i_nlink = 2; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - 0xFFFFFFFFFFFFFFFF, - 0xFFFFFFFFFFFFFFFF, + (__u64)-1, + (__u64)-1, cifs_sb->local_nls); else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ diff -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c --- a/fs/cifs/misc.c Mon Mar 31 19:52:27 2003 +++ b/fs/cifs/misc.c Tue May 27 17:41:17 2003 @@ -274,12 +274,12 @@ cFYI(0, ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, ntohl(smb->smb_buf_length))); - if ((length < 2 + sizeof (struct smb_hdr)) + if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || (4 + ntohl(smb->smb_buf_length) > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) { - if (length < 2 + sizeof (struct smb_hdr)) { + if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); - if ((length >= sizeof (struct smb_hdr) - 1) + if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) return 0; /* some error cases do not return wct and bcc */ @@ -298,7 +298,7 @@ return 1; if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) - || (4 + ntohl(smb->smb_buf_length) != length)) { + || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { return 0; } else { cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c Tue May 20 07:48:11 2003 +++ b/fs/cifs/netmisc.c Tue May 27 17:41:17 2003 @@ -791,7 +791,7 @@ int map_smb_to_linux_error(struct smb_hdr *smb) { - int i; + unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ __u8 smberrclass; __u16 smberrcode; @@ -859,10 +859,10 @@ * calculate the size of the SMB message based on the fixed header * portion, the number of word parameters and the data portion of the message */ -int +unsigned int smbCalcSize(struct smb_hdr *ptr) { - return (sizeof (struct smb_hdr) + (int) (2 * ptr->WordCount) + + return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + BCC(ptr)); } diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c --- a/fs/cifs/transport.c Fri May 16 09:07:44 2003 +++ b/fs/cifs/transport.c Tue May 27 17:41:17 2003 @@ -186,7 +186,7 @@ int *pbytes_returned, const int long_op) { int rc = 0; - int receive_len; + unsigned int receive_len; long timeout; struct mid_q_entry *midQ; diff -Nru a/fs/ext3/acl.c b/fs/ext3/acl.c --- a/fs/ext3/acl.c Sat Mar 22 22:14:52 2003 +++ b/fs/ext3/acl.c Tue Jun 17 23:04:18 2003 @@ -416,12 +416,14 @@ handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); if (IS_ERR(handle)) { + error = PTR_ERR(handle); ext3_std_error(inode->i_sb, error); - return PTR_ERR(handle); + goto out; } error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone); ext3_journal_stop(handle); } +out: posix_acl_release(clone); return error; } diff -Nru a/fs/ext3/balloc.c b/fs/ext3/balloc.c --- a/fs/ext3/balloc.c Fri Feb 14 18:24:09 2003 +++ b/fs/ext3/balloc.c Tue Jun 17 23:04:10 2003 @@ -110,6 +110,7 @@ struct super_block * sb; struct ext3_group_desc * gdp; struct ext3_super_block * es; + struct ext3_sb_info *sbi; int err = 0, ret; int dquot_freed_blocks = 0; @@ -118,7 +119,7 @@ printk ("ext3_free_blocks: nonexistent device"); return; } - lock_super (sb); + sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; if (block < le32_to_cpu(es->s_first_data_block) || block + count < block || @@ -170,7 +171,7 @@ */ /* @@@ check errors */ BUFFER_TRACE(bitmap_bh, "getting undo access"); - err = ext3_journal_get_undo_access(handle, bitmap_bh); + err = ext3_journal_get_undo_access(handle, bitmap_bh, NULL); if (err) goto error_return; @@ -184,16 +185,14 @@ if (err) goto error_return; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (err) - goto error_return; - + jbd_lock_bh_state(bitmap_bh); + for (i = 0; i < count; i++) { /* * An HJ special. This is expensive... */ #ifdef CONFIG_JBD_DEBUG + jbd_unlock_bh_state(bitmap_bh); { struct buffer_head *debug_bh; debug_bh = sb_find_get_block(sb, block + i); @@ -206,20 +205,8 @@ __brelse(debug_bh); } } + jbd_lock_bh_state(bitmap_bh); #endif - BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!ext3_clear_bit (bit + i, bitmap_bh->b_data)) { - ext3_error (sb, __FUNCTION__, - "bit already cleared for block %lu", - block + i); - BUFFER_TRACE(bitmap_bh, "bit already cleared"); - } else { - dquot_freed_blocks++; - gdp->bg_free_blocks_count = - cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); - es->s_free_blocks_count = - cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1); - } /* @@@ This prevents newly-allocated data from being * freed and then reallocated within the same * transaction. @@ -238,11 +225,36 @@ * activity on the buffer any more and so it is safe to * reallocate it. */ - BUFFER_TRACE(bitmap_bh, "clear in b_committed_data"); + BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data != NULL); - ext3_set_bit(bit + i, bh2jh(bitmap_bh)->b_committed_data); + ext3_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, + bh2jh(bitmap_bh)->b_committed_data); + + /* + * We clear the bit in the bitmap after setting the committed + * data bit, because this is the reverse order to that which + * the allocator uses. + */ + BUFFER_TRACE(bitmap_bh, "clear bit"); + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit + i, bitmap_bh->b_data)) { + ext3_error (sb, __FUNCTION__, + "bit already cleared for block %lu", + block + i); + BUFFER_TRACE(bitmap_bh, "bit already cleared"); + } else { + dquot_freed_blocks++; + } } + jbd_unlock_bh_state(bitmap_bh); + + spin_lock(sb_bgl_lock(sbi, block_group)); + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + + dquot_freed_blocks); + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_mod(&sbi->s_freeblocks_counter, count); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); @@ -253,11 +265,6 @@ ret = ext3_journal_dirty_metadata(handle, gd_bh); if (!err) err = ret; - /* And the superblock */ - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "dirtied superblock"); - ret = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!err) err = ret; - if (overflow && !err) { block += count; count = overflow; @@ -267,7 +274,6 @@ error_return: brelse(bitmap_bh); ext3_std_error(sb, err); - unlock_super(sb); if (dquot_freed_blocks) DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); return; @@ -288,11 +294,12 @@ * data-writes at some point, and disable it for metadata allocations or * sync-data inodes. */ -static int ext3_test_allocatable(int nr, struct buffer_head *bh) +static inline int ext3_test_allocatable(int nr, struct buffer_head *bh, + int have_access) { if (ext3_test_bit(nr, bh->b_data)) return 0; - if (!buffer_jbd(bh) || !bh2jh(bh)->b_committed_data) + if (!have_access || !buffer_jbd(bh) || !bh2jh(bh)->b_committed_data) return 1; return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data); } @@ -304,8 +311,8 @@ * the initial goal; then for a free byte somewhere in the bitmap; then * for any free bit in the bitmap. */ -static int find_next_usable_block(int start, - struct buffer_head *bh, int maxblocks) +static int find_next_usable_block(int start, struct buffer_head *bh, + int maxblocks, int have_access) { int here, next; char *p, *r; @@ -321,7 +328,8 @@ */ int end_goal = (start + 63) & ~63; here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); - if (here < end_goal && ext3_test_allocatable(here, bh)) + if (here < end_goal && + ext3_test_allocatable(here, bh, have_access)) return here; ext3_debug ("Bit not found near goal\n"); @@ -344,7 +352,7 @@ r = memscan(p, 0, (maxblocks - here + 7) >> 3); next = (r - ((char *) bh->b_data)) << 3; - if (next < maxblocks && ext3_test_allocatable(next, bh)) + if (next < maxblocks && ext3_test_allocatable(next, bh, have_access)) return next; /* The bitmap search --- search forward alternately @@ -356,17 +364,115 @@ maxblocks, here); if (next >= maxblocks) return -1; - if (ext3_test_allocatable(next, bh)) + if (ext3_test_allocatable(next, bh, have_access)) return next; - J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data); - here = ext3_find_next_zero_bit - ((unsigned long *) bh2jh(bh)->b_committed_data, - maxblocks, next); + if (have_access) + here = ext3_find_next_zero_bit + ((unsigned long *) bh2jh(bh)->b_committed_data, + maxblocks, next); + } + return -1; +} + +/* + * We think we can allocate this block in this bitmap. Try to set the bit. + * If that succeeds then check that nobody has allocated and then freed the + * block since we saw that is was not marked in b_committed_data. If it _was_ + * allocated and freed then clear the bit in the bitmap again and return + * zero (failure). + */ +static inline int +claim_block(spinlock_t *lock, int block, struct buffer_head *bh) +{ + if (ext3_set_bit_atomic(lock, block, bh->b_data)) + return 0; + if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data && + ext3_test_bit(block, bh2jh(bh)->b_committed_data)) { + ext3_clear_bit_atomic(lock, block, bh->b_data); + return 0; + } + return 1; +} + +/* + * If we failed to allocate the desired block then we may end up crossing to a + * new bitmap. In that case we must release write access to the old one via + * ext3_journal_release_buffer(), else we'll run out of credits. + */ +static int +ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, + struct buffer_head *bitmap_bh, int goal, int *errp) +{ + int i, fatal = 0; + int have_access = 0; + int credits = 0; + + *errp = 0; + + if (goal >= 0 && ext3_test_allocatable(goal, bitmap_bh, 0)) + goto got; + +repeat: + goal = find_next_usable_block(goal, bitmap_bh, + EXT3_BLOCKS_PER_GROUP(sb), have_access); + if (goal < 0) + goto fail; + + for (i = 0; + i < 7 && goal > 0 && + ext3_test_allocatable(goal - 1, bitmap_bh, have_access); + i++, goal--); + +got: + if (!have_access) { + /* + * Make sure we use undo access for the bitmap, because it is + * critical that we do the frozen_data COW on bitmap buffers in + * all cases even if the buffer is in BJ_Forget state in the + * committing transaction. + */ + BUFFER_TRACE(bitmap_bh, "get undo access for new block"); + fatal = ext3_journal_get_undo_access(handle, bitmap_bh, + &credits); + if (fatal) { + *errp = fatal; + goto fail; + } + jbd_lock_bh_state(bitmap_bh); + have_access = 1; + } + + if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) { + /* + * The block was allocated by another thread, or it was + * allocated and then freed by another thread + */ + goal++; + if (goal >= EXT3_BLOCKS_PER_GROUP(sb)) + goto fail; + goto repeat; + } + + BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); + jbd_unlock_bh_state(bitmap_bh); + fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); + if (fatal) { + *errp = fatal; + goto fail; + } + + return goal; +fail: + if (have_access) { + BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); + jbd_unlock_bh_state(bitmap_bh); + ext3_journal_release_buffer(handle, bitmap_bh, credits); } return -1; } + /* * ext3_new_block uses a goal block to assist allocation. If the goal is * free, or there is a free block within 32 blocks of the goal, that block @@ -383,13 +489,15 @@ struct buffer_head *gdp_bh; /* bh2 */ int group_no; /* i */ int ret_block; /* j */ - int bit; /* k */ + int bgi; /* blockgroup iteration index */ int target_block; /* tmp */ int fatal = 0, err; int performed_allocation = 0; + int free_blocks, root_blocks; struct super_block *sb; struct ext3_group_desc *gdp; struct ext3_super_block *es; + struct ext3_sb_info *sbi; #ifdef EXT3FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif @@ -408,18 +516,19 @@ return 0; } - lock_super(sb); + sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; - if (le32_to_cpu(es->s_free_blocks_count) <= - le32_to_cpu(es->s_r_blocks_count) && - ((EXT3_SB(sb)->s_resuid != current->fsuid) && - (EXT3_SB(sb)->s_resgid == 0 || - !in_group_p(EXT3_SB(sb)->s_resgid)) && - !capable(CAP_SYS_RESOURCE))) - goto out; - ext3_debug("goal=%lu.\n", goal); + free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + root_blocks = le32_to_cpu(es->s_r_blocks_count); + if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + sbi->s_resuid != current->fsuid && + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { + *errp = -ENOSPC; + return 0; + } + /* * First, test whether the goal block is free. */ @@ -432,40 +541,26 @@ if (!gdp) goto io_error; - if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (free_blocks > 0) { ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb)); -#ifdef EXT3FS_DEBUG - if (ret_block) - goal_attempts++; -#endif bitmap_bh = read_block_bitmap(sb, group_no); if (!bitmap_bh) - goto io_error; - - ext3_debug("goal is at %d:%d.\n", group_no, ret_block); - - if (ext3_test_allocatable(ret_block, bitmap_bh)) { -#ifdef EXT3FS_DEBUG - goal_hits++; - ext3_debug("goal bit allocated.\n"); -#endif - goto got_block; - } - - ret_block = find_next_usable_block(ret_block, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); + goto io_error; + ret_block = ext3_try_to_allocate(sb, handle, group_no, + bitmap_bh, ret_block, &fatal); + if (fatal) + goto out; if (ret_block >= 0) - goto search_back; + goto allocated; } - - ext3_debug("Bit not found in block group %d.\n", group_no); - + /* * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ - for (bit = 0; bit < EXT3_SB(sb)->s_groups_count; bit++) { + for (bgi = 0; bgi < EXT3_SB(sb)->s_groups_count; bgi++) { group_no++; if (group_no >= EXT3_SB(sb)->s_groups_count) group_no = 0; @@ -474,57 +569,36 @@ *errp = -EIO; goto out; } - if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - ret_block = find_next_usable_block(-1, bitmap_bh, - EXT3_BLOCKS_PER_GROUP(sb)); - if (ret_block >= 0) - goto search_back; - } + free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); + if (free_blocks <= 0) + continue; + + brelse(bitmap_bh); + bitmap_bh = read_block_bitmap(sb, group_no); + if (!bitmap_bh) + goto io_error; + ret_block = ext3_try_to_allocate(sb, handle, group_no, + bitmap_bh, -1, &fatal); + if (fatal) + goto out; + if (ret_block >= 0) + goto allocated; } /* No space left on the device */ + *errp = -ENOSPC; goto out; -search_back: - /* - * We have succeeded in finding a free byte in the block - * bitmap. Now search backwards up to 7 bits to find the - * start of this group of free blocks. - */ - for ( bit = 0; - bit < 7 && ret_block > 0 && - ext3_test_allocatable(ret_block - 1, bitmap_bh); - bit++, ret_block--) - ; - -got_block: +allocated: ext3_debug("using block group %d(%d)\n", group_no, gdp->bg_free_blocks_count); - /* Make sure we use undo access for the bitmap, because it is - critical that we do the frozen_data COW on bitmap buffers in - all cases even if the buffer is in BJ_Forget state in the - committing transaction. */ - BUFFER_TRACE(bitmap_bh, "get undo access for marking new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh); - if (fatal) - goto out; - BUFFER_TRACE(gdp_bh, "get_write_access"); fatal = ext3_journal_get_write_access(handle, gdp_bh); if (fatal) goto out; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (fatal) - goto out; - target_block = ret_block + group_no * EXT3_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); @@ -536,11 +610,6 @@ "Allocating block in system zone - " "block = %u", target_block); - /* The superblock lock should guard against anybody else beating - * us to this point! */ - J_ASSERT_BH(bitmap_bh, !ext3_test_bit(ret_block, bitmap_bh->b_data)); - BUFFER_TRACE(bitmap_bh, "setting bitmap bit"); - ext3_set_bit(ret_block, bitmap_bh->b_data); performed_allocation = 1; #ifdef CONFIG_JBD_DEBUG @@ -555,21 +624,23 @@ brelse(debug_bh); } } -#endif - if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) - J_ASSERT_BH(bitmap_bh, - !ext3_test_bit(ret_block, - bh2jh(bitmap_bh)->b_committed_data)); + jbd_lock_bh_state(bitmap_bh); + spin_lock(sb_bgl_lock(sbi, group_no)); + if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { + if (ext3_test_bit(ret_block, + bh2jh(bitmap_bh)->b_committed_data)) { + printk("%s: block was unexpectedly set in " + "b_committed_data\n", __FUNCTION__); + } + } ext3_debug("found bit %d\n", ret_block); + spin_unlock(sb_bgl_lock(sbi, group_no)); + jbd_unlock_bh_state(bitmap_bh); +#endif /* ret_block was blockgroup-relative. Now it becomes fs-relative */ ret_block = target_block; - BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (!fatal) - fatal = err; - if (ret_block >= le32_to_cpu(es->s_blocks_count)) { ext3_error(sb, "ext3_new_block", "block(%d) >= blocks count(%d) - " @@ -586,27 +657,21 @@ ext3_debug("allocating block %d. Goal hits %d of %d.\n", ret_block, goal_hits, goal_attempts); + spin_lock(sb_bgl_lock(sbi, group_no)); gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); - es->s_free_blocks_count = - cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1); + spin_unlock(sb_bgl_lock(sbi, group_no)); + percpu_counter_mod(&sbi->s_freeblocks_counter, -1); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext3_journal_dirty_metadata(handle, gdp_bh); if (!fatal) fatal = err; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, - "journal_dirty_metadata for superblock"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!fatal) - fatal = err; - sb->s_dirt = 1; if (fatal) goto out; - unlock_super(sb); *errp = 0; brelse(bitmap_bh); return ret_block; @@ -618,7 +683,6 @@ *errp = fatal; ext3_std_error(sb, fatal); } - unlock_super(sb); /* * Undo the block allocation */ @@ -631,12 +695,13 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) { + unsigned long desc_count; + struct ext3_group_desc *gdp; + int i; #ifdef EXT3FS_DEBUG struct ext3_super_block *es; - unsigned long desc_count, bitmap_count, x; + unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - struct ext3_group_desc *gdp; - int i; lock_super(sb); es = EXT3_SB(sb)->s_es; @@ -664,7 +729,15 @@ unlock_super(sb); return bitmap_count; #else - return le32_to_cpu(EXT3_SB(sb)->s_es->s_free_blocks_count); + desc_count = 0; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc(sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + } + + return desc_count; #endif } diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c --- a/fs/ext3/ialloc.c Sun Mar 16 22:33:16 2003 +++ b/fs/ext3/ialloc.c Tue Jun 17 23:04:10 2003 @@ -97,6 +97,7 @@ unsigned long bit; struct ext3_group_desc * gdp; struct ext3_super_block * es; + struct ext3_sb_info *sbi = EXT3_SB(sb); int fatal = 0, err; if (atomic_read(&inode->i_count) > 1) { @@ -131,7 +132,6 @@ /* Do this BEFORE marking the inode not in use or returning an error */ clear_inode (inode); - lock_super (sb); es = EXT3_SB(sb)->s_es; if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_free_inode", @@ -150,7 +150,8 @@ goto error_return; /* Ok, now we can actually update the inode bitmaps.. */ - if (!ext3_clear_bit(bit, bitmap_bh->b_data)) + if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), + bit, bitmap_bh->b_data)) ext3_error (sb, "ext3_free_inode", "bit already cleared for inode %lu", ino); else { @@ -160,28 +161,22 @@ fatal = ext3_journal_get_write_access(handle, bh2); if (fatal) goto error_return; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get write access"); - fatal = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (fatal) goto error_return; - if (gdp) { + spin_lock(sb_bgl_lock(sbi, block_group)); gdp->bg_free_inodes_count = cpu_to_le16( le16_to_cpu(gdp->bg_free_inodes_count) + 1); - if (is_directory) { + if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16( le16_to_cpu(gdp->bg_used_dirs_count) - 1); - EXT3_SB(sb)->s_dir_count--; - } + spin_unlock(sb_bgl_lock(sbi, block_group)); + percpu_counter_inc(&sbi->s_freeinodes_counter); + if (is_directory) + percpu_counter_dec(&sbi->s_dirs_counter); + } BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (!fatal) fatal = err; - es->s_free_inodes_count = - cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, - "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (!fatal) fatal = err; } BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bitmap_bh); @@ -191,7 +186,6 @@ error_return: brelse(bitmap_bh); ext3_std_error(sb, fatal); - unlock_super(sb); } /* @@ -206,13 +200,15 @@ */ static int find_group_dir(struct super_block *sb, struct inode *parent) { - struct ext3_super_block * es = EXT3_SB(sb)->s_es; int ngroups = EXT3_SB(sb)->s_groups_count; - int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; + int freei, avefreei; struct ext3_group_desc *desc, *best_desc = NULL; struct buffer_head *bh; int group, best_group = -1; + freei = percpu_counter_read_positive(&EXT3_SB(sb)->s_freeinodes_counter); + avefreei = freei / ngroups; + for (group = 0; group < ngroups; group++) { desc = ext3_get_group_desc (sb, group, &bh); if (!desc || !desc->bg_free_inodes_count) @@ -264,15 +260,20 @@ struct ext3_super_block *es = sbi->s_es; int ngroups = sbi->s_groups_count; int inodes_per_group = EXT3_INODES_PER_GROUP(sb); - int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups; - int avefreeb = le32_to_cpu(es->s_free_blocks_count) / ngroups; - int blocks_per_dir; - int ndirs = sbi->s_dir_count; + int freei, avefreei; + int freeb, avefreeb; + int blocks_per_dir, ndirs; int max_debt, max_dirs, min_blocks, min_inodes; int group = -1, i; struct ext3_group_desc *desc; struct buffer_head *bh; + freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); + avefreei = freei / ngroups; + freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); + avefreeb = freeb / ngroups; + ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); + if ((parent == sb->s_root->d_inode) || (parent->i_flags & EXT3_TOPDIR_FL)) { int best_ndir = inodes_per_group; @@ -299,8 +300,7 @@ goto fallback; } - blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_free_blocks_count)) / ndirs; + blocks_per_dir = (le32_to_cpu(es->s_blocks_count) - freeb) / ndirs; max_dirs = ndirs / ngroups + inodes_per_group / 16; min_inodes = avefreei - inodes_per_group / 4; @@ -340,6 +340,15 @@ return group; } + if (avefreei) { + /* + * The free-inodes counter is approximate, and for really small + * filesystems the above test can fail to find any blockgroups + */ + avefreei = 0; + goto fallback; + } + return -1; } @@ -417,13 +426,15 @@ struct buffer_head *bitmap_bh = NULL; struct buffer_head *bh2; int group; - unsigned long ino; + unsigned long ino = 0; struct inode * inode; - struct ext3_group_desc * gdp; + struct ext3_group_desc * gdp = NULL; struct ext3_super_block * es; struct ext3_inode_info *ei; + struct ext3_sb_info *sbi; int err = 0; struct inode *ret; + int i; /* Cannot create files in a deleted directory */ if (!dir || !dir->i_nlink) @@ -435,9 +446,8 @@ return ERR_PTR(-ENOMEM); ei = EXT3_I(inode); - lock_super (sb); es = EXT3_SB(sb)->s_es; -repeat: + sbi = EXT3_SB(sb); if (S_ISDIR(mode)) { if (test_opt (sb, OLDALLOC)) group = find_group_dir(sb, dir); @@ -450,48 +460,55 @@ if (group == -1) goto out; - err = -EIO; - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) - goto fail; - gdp = ext3_get_group_desc (sb, group, &bh2); - - if ((ino = ext3_find_first_zero_bit((unsigned long *)bitmap_bh->b_data, - EXT3_INODES_PER_GROUP(sb))) < - EXT3_INODES_PER_GROUP(sb)) { - BUFFER_TRACE(bitmap_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bitmap_bh); - if (err) goto fail; - - if (ext3_set_bit(ino, bitmap_bh->b_data)) { - ext3_error (sb, "ext3_new_inode", - "bit already set for inode %lu", ino); - goto repeat; - } - BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (err) goto fail; - } else { - if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { - ext3_error (sb, "ext3_new_inode", - "Free inodes count corrupted in group %d", - group); - /* Is it really ENOSPC? */ - err = -ENOSPC; - if (sb->s_flags & MS_RDONLY) + for (i = 0; i < sbi->s_groups_count; i++) { + gdp = ext3_get_group_desc(sb, group, &bh2); + + err = -EIO; + brelse(bitmap_bh); + bitmap_bh = read_inode_bitmap(sb, group); + if (!bitmap_bh) + goto fail; + + ino = ext3_find_first_zero_bit((unsigned long *) + bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb)); + if (ino < EXT3_INODES_PER_GROUP(sb)) { + int credits = 0; + + BUFFER_TRACE(bitmap_bh, "get_write_access"); + err = ext3_journal_get_write_access_credits(handle, + bitmap_bh, &credits); + if (err) goto fail; - BUFFER_TRACE(bh2, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh2); - if (err) goto fail; - gdp->bg_free_inodes_count = 0; - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); - if (err) goto fail; + if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group), + ino, bitmap_bh->b_data)) { + /* we won it */ + BUFFER_TRACE(bitmap_bh, + "call ext3_journal_dirty_metadata"); + err = ext3_journal_dirty_metadata(handle, + bitmap_bh); + if (err) + goto fail; + goto got; + } + /* we lost it */ + journal_release_buffer(handle, bitmap_bh, credits); } - goto repeat; + + /* + * This case is possible in concurrent environment. It is very + * rare. We cannot repeat the find_group_xxx() call because + * that will simply return the same blockgroup, because the + * group descriptor metadata has not yet been updated. + * So we just go onto the next blockgroup. + */ + if (++group == sbi->s_groups_count) + group = 0; } + err = -ENOSPC; + goto out; + +got: ino += group * EXT3_INODES_PER_GROUP(sb) + 1; if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { ext3_error (sb, "ext3_new_inode", @@ -504,26 +521,22 @@ BUFFER_TRACE(bh2, "get_write_access"); err = ext3_journal_get_write_access(handle, bh2); if (err) goto fail; + spin_lock(sb_bgl_lock(sbi, group)); gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); if (S_ISDIR(mode)) { gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); - EXT3_SB(sb)->s_dir_count++; } + spin_unlock(sb_bgl_lock(sbi, group)); BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh2); if (err) goto fail; - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (err) goto fail; - es->s_free_inodes_count = - cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1); - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); + percpu_counter_dec(&sbi->s_freeinodes_counter); + if (S_ISDIR(mode)) + percpu_counter_inc(&sbi->s_dirs_counter); sb->s_dirt = 1; - if (err) goto fail; inode->i_uid = current->fsuid; if (test_opt (sb, GRPID)) @@ -576,7 +589,6 @@ ei->i_state = EXT3_STATE_NEW; - unlock_super(sb); ret = inode; if(DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); @@ -600,7 +612,6 @@ fail: ext3_std_error(sb, err); out: - unlock_super(sb); iput(inode); ret = ERR_PTR(err); really_out: @@ -673,12 +684,13 @@ unsigned long ext3_count_free_inodes (struct super_block * sb) { + unsigned long desc_count; + struct ext3_group_desc *gdp; + int i; #ifdef EXT3FS_DEBUG struct ext3_super_block *es; - unsigned long desc_count, bitmap_count, x; - struct ext3_group_desc *gdp; + unsigned long bitmap_count, x; struct buffer_head *bitmap_bh = NULL; - int i; lock_super (sb); es = EXT3_SB(sb)->s_es; @@ -706,7 +718,14 @@ unlock_super(sb); return desc_count; #else - return le32_to_cpu(EXT3_SB(sb)->s_es->s_free_inodes_count); + desc_count = 0; + for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + gdp = ext3_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + } + return desc_count; #endif } diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Sun Jun 1 14:12:55 2003 +++ b/fs/ext3/inode.c Tue Jun 17 23:04:27 2003 @@ -199,7 +199,6 @@ if (is_bad_inode(inode)) goto no_delete; - lock_kernel(); handle = start_transaction(inode); if (IS_ERR(handle)) { /* If we're going to skip the normal cleanup, we still @@ -208,7 +207,6 @@ ext3_orphan_del(NULL, inode); ext3_std_error(inode->i_sb, PTR_ERR(handle)); - unlock_kernel(); goto no_delete; } @@ -241,7 +239,6 @@ else ext3_free_inode(handle, inode); ext3_journal_stop(handle); - unlock_kernel(); return; no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ @@ -251,7 +248,6 @@ { #ifdef EXT3_PREALLOCATE struct ext3_inode_info *ei = EXT3_I(inode); - lock_kernel(); /* Writer: ->i_prealloc* */ if (ei->i_prealloc_count) { unsigned short total = ei->i_prealloc_count; @@ -261,7 +257,6 @@ /* Writer: end */ ext3_free_blocks (inode, block, total); } - unlock_kernel(); #endif } @@ -781,7 +776,6 @@ if (depth == 0) goto out; - lock_kernel(); reread: partial = ext3_get_branch(inode, depth, offsets, chain, &err); @@ -806,7 +800,6 @@ partial--; } BUFFER_TRACE(bh_result, "returned"); - unlock_kernel(); out: return err; } @@ -894,7 +887,6 @@ handle_t *handle = journal_current_handle(); int ret = 0; - lock_kernel(); if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { /* * Getting low on buffer credits... @@ -911,7 +903,6 @@ bh_result, create, 0); if (ret == 0) bh_result->b_size = (1 << inode->i_blkbits); - unlock_kernel(); return ret; } @@ -944,7 +935,6 @@ For now, regular file writes use ext3_get_block instead, so it's not a problem. */ - lock_kernel(); lock_buffer(bh); BUFFER_TRACE(bh, "call get_create_access"); fatal = ext3_journal_get_create_access(handle, bh); @@ -957,7 +947,6 @@ BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); err = ext3_journal_dirty_metadata(handle, bh); if (!fatal) fatal = err; - unlock_kernel(); } else { BUFFER_TRACE(bh, "not a new buffer"); } @@ -1037,11 +1026,13 @@ unsigned block_start, block_end; unsigned blocksize = head->b_size; int err, ret = 0; + struct buffer_head *next; for ( bh = head, block_start = 0; ret == 0 && (bh != head || !block_start); - block_start = block_end, bh = bh->b_this_page) + block_start = block_end, bh = next) { + next = bh->b_this_page; block_end = block_start + blocksize; if (block_end <= from || block_start >= to) { if (partial && !buffer_uptodate(bh)) @@ -1084,6 +1075,8 @@ static int do_journal_get_write_access(handle_t *handle, struct buffer_head *bh) { + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; return ext3_journal_get_write_access(handle, bh); } @@ -1094,15 +1087,12 @@ int ret, needed_blocks = ext3_writepage_trans_blocks(inode); handle_t *handle; - lock_kernel(); handle = ext3_journal_start(inode, needed_blocks); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } - unlock_kernel(); ret = block_prepare_write(page, from, to, ext3_get_block); - lock_kernel(); if (ret != 0) goto prepare_write_failed; @@ -1114,7 +1104,6 @@ if (ret) ext3_journal_stop(handle); out: - unlock_kernel(); return ret; } @@ -1131,6 +1120,8 @@ /* For commit_write() in data=journal mode */ static int commit_write_fn(handle_t *handle, struct buffer_head *bh) { + if (!buffer_mapped(bh) || buffer_freed(bh)) + return 0; set_buffer_uptodate(bh); return ext3_journal_dirty_metadata(handle, bh); } @@ -1143,56 +1134,81 @@ * buffers are managed internally. */ -static int ext3_commit_write(struct file *file, struct page *page, +static int ext3_ordered_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { handle_t *handle = ext3_journal_current_handle(); struct inode *inode = page->mapping->host; int ret = 0, ret2; - lock_kernel(); - if (ext3_should_journal_data(inode)) { + ret = walk_page_buffers(handle, page_buffers(page), + from, to, NULL, ext3_journal_dirty_data); + + if (ret == 0) { /* - * Here we duplicate the generic_commit_write() functionality + * generic_commit_write() will run mark_inode_dirty() if i_size + * changes. So let's piggyback the i_disksize mark_inode_dirty + * into that. */ - int partial = 0; - loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + loff_t new_i_size; - ret = walk_page_buffers(handle, page_buffers(page), - from, to, &partial, commit_write_fn); - if (!partial) - SetPageUptodate(page); - if (pos > inode->i_size) - inode->i_size = pos; - EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; - if (inode->i_size > EXT3_I(inode)->i_disksize) { - EXT3_I(inode)->i_disksize = inode->i_size; - ret2 = ext3_mark_inode_dirty(handle, inode); - if (!ret) - ret = ret2; - } - } else { - if (ext3_should_order_data(inode)) { - ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, ext3_journal_dirty_data); - } - /* Be careful here if generic_commit_write becomes a - * required invocation after block_prepare_write. */ - if (ret == 0) { - /* - * generic_commit_write() will run mark_inode_dirty() - * if i_size changes. So let's piggyback the - * i_disksize mark_inode_dirty into that. - */ - loff_t new_i_size = - ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - if (new_i_size > EXT3_I(inode)->i_disksize) - EXT3_I(inode)->i_disksize = new_i_size; - ret = generic_commit_write(file, page, from, to); - } + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + ret = generic_commit_write(file, page, from, to); + } + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_writeback_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + loff_t new_i_size; + + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + if (new_i_size > EXT3_I(inode)->i_disksize) + EXT3_I(inode)->i_disksize = new_i_size; + ret = generic_commit_write(file, page, from, to); + ret2 = ext3_journal_stop(handle); + if (!ret) + ret = ret2; + return ret; +} + +static int ext3_journalled_commit_write(struct file *file, + struct page *page, unsigned from, unsigned to) +{ + handle_t *handle = ext3_journal_current_handle(); + struct inode *inode = page->mapping->host; + int ret = 0, ret2; + int partial = 0; + loff_t pos; + + /* + * Here we duplicate the generic_commit_write() functionality + */ + pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + + ret = walk_page_buffers(handle, page_buffers(page), from, + to, &partial, commit_write_fn); + if (!partial) + SetPageUptodate(page); + if (pos > inode->i_size) + inode->i_size = pos; + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + if (inode->i_size > EXT3_I(inode)->i_disksize) { + EXT3_I(inode)->i_disksize = inode->i_size; + ret2 = ext3_mark_inode_dirty(handle, inode); + if (!ret) + ret = ret2; } ret2 = ext3_journal_stop(handle); - unlock_kernel(); if (!ret) ret = ret2; return ret; @@ -1317,55 +1333,44 @@ * We don't honour synchronous mounts for writepage(). That would be * disastrous. Any write() or metadata operation will sync the fs for * us. + * + * AKPM2: if all the page's buffers are mapped to disk and !data=journal, + * we don't need to open a transaction here. */ -static int ext3_writepage(struct page *page, struct writeback_control *wbc) +static int ext3_ordered_writepage(struct page *page, + struct writeback_control *wbc) { struct inode *inode = page->mapping->host; struct buffer_head *page_bufs; handle_t *handle = NULL; - int ret = 0, err; - int needed; - int order_data; + int ret = 0; + int err; J_ASSERT(PageLocked(page)); /* - * We give up here if we're reentered, because it might be - * for a different filesystem. One *could* look for a - * nested transaction opportunity. + * We give up here if we're reentered, because it might be for a + * different filesystem. */ - lock_kernel(); if (ext3_journal_current_handle()) goto out_fail; - needed = ext3_writepage_trans_blocks(inode); - handle = ext3_journal_start(inode, needed); + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out_fail; } - order_data = ext3_should_order_data(inode) || - ext3_should_journal_data(inode); - - unlock_kernel(); - - page_bufs = NULL; /* Purely to prevent compiler warning */ - - /* bget() all the buffers */ - if (order_data) { - if (!page_has_buffers(page)) { - if (!PageUptodate(page)) - buffer_error(); - create_empty_buffers(page, - inode->i_sb->s_blocksize, + if (!page_has_buffers(page)) { + if (!PageUptodate(page)) + buffer_error(); + create_empty_buffers(page, inode->i_sb->s_blocksize, (1 << BH_Dirty)|(1 << BH_Uptodate)); - } - page_bufs = page_buffers(page); - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bget_one); } + page_bufs = page_buffers(page); + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bget_one); ret = block_write_full_page(page, ext3_get_block, wbc); @@ -1376,46 +1381,116 @@ * safe due to elevated refcount. */ - handle = ext3_journal_current_handle(); - lock_kernel(); - /* * And attach them to the current transaction. But only if * block_write_full_page() succeeded. Otherwise they are unmapped, * and generally junk. */ - if (order_data) { - if (ret == 0) { - err = walk_page_buffers(handle, page_bufs, - 0, PAGE_CACHE_SIZE, NULL, - journal_dirty_data_fn); - if (!ret) - ret = err; - } - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bput_one); + if (ret == 0) { + err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, + NULL, journal_dirty_data_fn); + if (!ret) + ret = err; } - + walk_page_buffers(handle, page_bufs, 0, + PAGE_CACHE_SIZE, NULL, bput_one); err = ext3_journal_stop(handle); if (!ret) ret = err; - unlock_kernel(); return ret; out_fail: - - unlock_kernel(); + __set_page_dirty_nobuffers(page); + unlock_page(page); + return ret; +} - /* - * We have to fail this writepage to avoid cross-fs transactions. - * Put the page back on mapping->dirty_pages. The page's buffers' - * dirty state will be left as-is. - */ +static int ext3_writeback_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto out_fail; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out_fail; + } + + ret = block_write_full_page(page, ext3_get_block, wbc); + err = ext3_journal_stop(handle); + if (!ret) + ret = err; + return ret; + +out_fail: __set_page_dirty_nobuffers(page); unlock_page(page); return ret; } +static int ext3_journalled_writepage(struct page *page, + struct writeback_control *wbc) +{ + struct inode *inode = page->mapping->host; + handle_t *handle = NULL; + int ret = 0; + int err; + + if (ext3_journal_current_handle()) + goto no_write; + + handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto no_write; + } + + if (!page_has_buffers(page) || PageChecked(page)) { + /* + * It's mmapped pagecache. Add buffers and journal it. There + * doesn't seem much point in redirtying the page here. + */ + ClearPageChecked(page); + ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, + ext3_get_block); + if (ret != 0) + goto out_unlock; + ret = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); + + err = walk_page_buffers(handle, page_buffers(page), 0, + PAGE_CACHE_SIZE, NULL, commit_write_fn); + if (ret == 0) + ret = err; + EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; + unlock_page(page); + } else { + /* + * It may be a page full of checkpoint-mode buffers. We don't + * really know unless we go poke around in the buffer_heads. + * But block_write_full_page will do the right thing. + */ + ret = block_write_full_page(page, ext3_get_block, wbc); + } + err = ext3_journal_stop(handle); + if (!ret) + ret = err; +out: + return ret; + +no_write: + __set_page_dirty_nobuffers(page); +out_unlock: + unlock_page(page); + goto out; +} + static int ext3_readpage(struct file *file, struct page *page) { return mpage_readpage(page, ext3_get_block); @@ -1431,12 +1506,21 @@ static int ext3_invalidatepage(struct page *page, unsigned long offset) { journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + /* + * If it's a full truncate we just forget about the pending dirtying + */ + if (offset == 0) + ClearPageChecked(page); + return journal_invalidatepage(journal, page, offset); } static int ext3_releasepage(struct page *page, int wait) { journal_t *journal = EXT3_JOURNAL(page->mapping->host); + + WARN_ON(PageChecked(page)); return journal_try_to_free_buffers(journal, page, wait); } @@ -1463,17 +1547,13 @@ if (rw == WRITE) { loff_t final_size = offset + count; - lock_kernel(); handle = ext3_journal_start(inode, DIO_CREDITS); - unlock_kernel(); if (IS_ERR(handle)) { ret = PTR_ERR(handle); goto out; } if (final_size > inode->i_size) { - lock_kernel(); ret = ext3_orphan_add(handle, inode); - unlock_kernel(); if (ret) goto out_stop; orphan = 1; @@ -1488,7 +1568,6 @@ if (handle) { int err; - lock_kernel(); if (orphan) ext3_orphan_del(handle, inode); if (orphan && ret > 0) { @@ -1504,47 +1583,79 @@ err = ext3_journal_stop(handle); if (ret == 0) ret = err; - unlock_kernel(); } out: return ret; } -struct address_space_operations ext3_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ +/* + * Pages can be marked dirty completely asynchronously from ext3's journalling + * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do + * much here because ->set_page_dirty is called under VFS locks. The page is + * not necessarily locked. + * + * We cannot just dirty the page and leave attached buffers clean, because the + * buffers' dirty state is "definitive". We cannot just set the buffers dirty + * or jbddirty because all the journalling code will explode. + * + * So what we do is to mark the page "pending dirty" and next time writepage + * is called, propagate that into the buffers appropriately. + */ +static int ext3_journalled_set_page_dirty(struct page *page) +{ + SetPageChecked(page); + return __set_page_dirty_nobuffers(page); +} + +static struct address_space_operations ext3_ordered_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_ordered_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ - .commit_write = ext3_commit_write, /* BKL not held. We take it */ - .bmap = ext3_bmap, /* BKL held */ - .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ - .releasepage = ext3_releasepage, /* BKL not held. Don't need */ - .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ + .prepare_write = ext3_prepare_write, + .commit_write = ext3_ordered_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, }; -/* For writeback mode, we can use mpage_writepages() */ -#if 0 /* Doesn't work for shared mappings */ -static int -ext3_writepages(struct address_space *mapping, struct writeback_control *wbc) -{ - return mpage_writepages(mapping, wbc, ext3_get_block); -} -#endif +static struct address_space_operations ext3_writeback_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_writeback_writepage, + .sync_page = block_sync_page, + .prepare_write = ext3_prepare_write, + .commit_write = ext3_writeback_commit_write, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, + .direct_IO = ext3_direct_IO, +}; -struct address_space_operations ext3_writeback_aops = { - .readpage = ext3_readpage, /* BKL not held. Don't need */ - .readpages = ext3_readpages, /* BKL not held. Don't need */ - .writepage = ext3_writepage, /* BKL not held. We take it */ +static struct address_space_operations ext3_journalled_aops = { + .readpage = ext3_readpage, + .readpages = ext3_readpages, + .writepage = ext3_journalled_writepage, .sync_page = block_sync_page, - .prepare_write = ext3_prepare_write, /* BKL not held. We take it */ - .commit_write = ext3_commit_write, /* BKL not held. We take it */ - .bmap = ext3_bmap, /* BKL held */ - .invalidatepage = ext3_invalidatepage, /* BKL not held. Don't need */ - .releasepage = ext3_releasepage, /* BKL not held. Don't need */ - .direct_IO = ext3_direct_IO, /* BKL not held. Don't need */ + .prepare_write = ext3_prepare_write, + .commit_write = ext3_journalled_commit_write, + .set_page_dirty = ext3_journalled_set_page_dirty, + .bmap = ext3_bmap, + .invalidatepage = ext3_invalidatepage, + .releasepage = ext3_releasepage, }; +void ext3_set_aops(struct inode *inode) +{ + if (ext3_should_order_data(inode)) + inode->i_mapping->a_ops = &ext3_ordered_aops; + else if (ext3_should_writeback_data(inode)) + inode->i_mapping->a_ops = &ext3_writeback_aops; + else + inode->i_mapping->a_ops = &ext3_journalled_aops; +} + /* * ext3_block_truncate_page() zeroes out a mapping from file offset `from' * up to the end of the block which corresponds to `from'. @@ -1591,11 +1702,19 @@ } err = 0; + if (buffer_freed(bh)) { + BUFFER_TRACE(bh, "freed: skip"); + goto unlock; + } + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "unmapped"); ext3_get_block(inode, iblock, bh, 0); /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) + if (!buffer_mapped(bh)) { + BUFFER_TRACE(bh, "still unmapped"); goto unlock; + } } /* Ok, it's mapped. Make sure it's up-to-date */ @@ -2034,12 +2153,10 @@ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - lock_kernel(); ext3_discard_prealloc(inode); handle = start_transaction(inode); if (IS_ERR(handle)) { - unlock_kernel(); return; /* AKPM: return what? */ } @@ -2163,7 +2280,6 @@ ext3_orphan_del(handle, inode); ext3_journal_stop(handle); - unlock_kernel(); } /* @@ -2338,10 +2454,7 @@ if (S_ISREG(inode->i_mode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ext3_dir_inode_operations; inode->i_fop = &ext3_dir_operations; @@ -2350,10 +2463,7 @@ inode->i_op = &ext3_fast_symlink_inode_operations; else { inode->i_op = &ext3_symlink_inode_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); } } else { inode->i_op = &ext3_special_inode_operations; @@ -2517,6 +2627,7 @@ if (ext3_journal_current_handle()) { jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); + dump_stack(); return; } @@ -2560,8 +2671,6 @@ return error; } - lock_kernel(); - if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { handle_t *handle; @@ -2593,7 +2702,6 @@ err_out: ext3_std_error(inode->i_sb, error); - unlock_kernel(); if (!error) error = rc; return error; @@ -2739,7 +2847,6 @@ handle_t *current_handle = ext3_journal_current_handle(); handle_t *handle; - lock_kernel(); handle = ext3_journal_start(inode, 2); if (IS_ERR(handle)) goto out; @@ -2755,7 +2862,7 @@ } ext3_journal_stop(handle); out: - unlock_kernel(); + return; } #ifdef AKPM @@ -2839,61 +2946,3 @@ return err; } - - -/* - * ext3_aops_journal_start(). - * - * - * - * We need to take the inode semaphore *outside* the - * journal_start/journal_stop. Otherwise, a different task could do a - * wait_for_commit() while holding ->i_sem, which deadlocks. The rule - * is: transaction open/closes are considered to be a locking operation - * and they nest *inside* ->i_sem. - * ---------------------------------------------------------------------------- - * Possible problem: - * ext3_file_write() - * -> generic_file_write() - * -> __alloc_pages() - * -> page_launder() - * -> ext3_writepage() - * - * And the writepage can be on a different fs while we have a - * transaction open against this one! Bad. - * - * I tried making the task PF_MEMALLOC here, but that simply results in - * 0-order allocation failures passed back to generic_file_write(). - * Instead, we rely on the reentrancy protection in ext3_writepage(). - * ---------------------------------------------------------------------------- - * When we do the journal_start() here we don't really need to reserve - * any blocks - we won't need any until we hit ext3_prepare_write(), - * which does all the needed journal extending. However! There is a - * problem with quotas: - * - * Thread 1: - * sys_sync - * ->sync_dquots - * ->commit_dquot - * ->lock_dquot - * ->write_dquot - * ->ext3_file_write - * ->journal_start - * ->ext3_prepare_write - * ->journal_extend - * ->journal_start - * Thread 2: - * ext3_create (for example) - * ->ext3_new_inode - * ->dquot_initialize - * ->lock_dquot - * - * Deadlock. Thread 1's journal_start blocks because thread 2 has a - * transaction open. Thread 2's transaction will never close because - * thread 2 is stuck waiting for the dquot lock. - * - * So. We must ensure that thread 1 *never* needs to extend the journal - * for quota writes. We do that by reserving enough journal blocks - * here, in ext3_aops_journal_start() to ensure that the forthcoming "see if we - * need to extend" test in ext3_prepare_write() succeeds. - */ diff -Nru a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c --- a/fs/ext3/ioctl.c Sat Mar 22 22:14:52 2003 +++ b/fs/ext3/ioctl.c Tue Jun 17 23:04:18 2003 @@ -119,13 +119,11 @@ if (IS_ERR(handle)) return PTR_ERR(handle); err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err) - return err; - - inode->i_ctime = CURRENT_TIME; - inode->i_generation = generation; - - err = ext3_mark_iloc_dirty(handle, inode, &iloc); + if (err == 0) { + inode->i_ctime = CURRENT_TIME; + inode->i_generation = generation; + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + } ext3_journal_stop(handle); return err; } diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c --- a/fs/ext3/namei.c Mon May 12 21:23:28 2003 +++ b/fs/ext3/namei.c Tue Jun 17 23:04:16 2003 @@ -981,7 +981,6 @@ if (dentry->d_name.len > EXT3_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); - lock_kernel(); bh = ext3_find_entry(dentry, &de); inode = NULL; if (bh) { @@ -989,12 +988,9 @@ brelse (bh); inode = iget(dir->i_sb, ino); - if (!inode) { - unlock_kernel(); + if (!inode) return ERR_PTR(-EACCES); - } } - unlock_kernel(); if (inode) return d_splice_alias(inode, dentry); d_add(dentry, inode); @@ -1015,17 +1011,13 @@ dotdot.d_name.len = 2; dotdot.d_parent = child; /* confusing, isn't it! */ - lock_kernel(); bh = ext3_find_entry(&dotdot, &de); inode = NULL; - if (!bh) { - unlock_kernel(); + if (!bh) return ERR_PTR(-ENOENT); - } ino = le32_to_cpu(de->inode); brelse(bh); inode = iget(child->d_inode->i_sb, ino); - unlock_kernel(); if (!inode) return ERR_PTR(-EACCES); @@ -1639,13 +1631,10 @@ struct inode * inode; int err; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1655,14 +1644,10 @@ if (!IS_ERR(inode)) { inode->i_op = &ext3_file_inode_operations; inode->i_fop = &ext3_file_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1673,13 +1658,10 @@ struct inode *inode; int err; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1694,7 +1676,6 @@ err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1709,13 +1690,10 @@ if (dir->i_nlink >= EXT3_LINK_MAX) return -EMLINK; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -1768,7 +1746,6 @@ d_instantiate(dentry, inode); out_stop: ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -1993,12 +1970,9 @@ struct ext3_dir_entry_2 * de; handle_t *handle; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } retval = -ENOENT; bh = ext3_find_entry (dentry, &de); @@ -2042,7 +2016,6 @@ end_rmdir: ext3_journal_stop(handle); brelse (bh); - unlock_kernel(); return retval; } @@ -2054,12 +2027,9 @@ struct ext3_dir_entry_2 * de; handle_t *handle; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2097,7 +2067,6 @@ end_unlink: ext3_journal_stop(handle); - unlock_kernel(); brelse (bh); return retval; } @@ -2113,13 +2082,10 @@ if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; - lock_kernel(); handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2131,10 +2097,7 @@ if (l > sizeof (EXT3_I(inode)->i_data)) { inode->i_op = &ext3_symlink_inode_operations; - if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_aops; + ext3_set_aops(inode); /* * page_symlink() calls into ext3_prepare/commit_write. * We have a transaction open. All is sweetness. It also sets @@ -2156,7 +2119,6 @@ err = ext3_add_nondir(handle, dentry, inode); out_stop: ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -2167,18 +2129,13 @@ struct inode *inode = old_dentry->d_inode; int err; - lock_kernel(); - if (inode->i_nlink >= EXT3_LINK_MAX) { - unlock_kernel(); + if (inode->i_nlink >= EXT3_LINK_MAX) return -EMLINK; - } handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(dir)) handle->h_sync = 1; @@ -2189,7 +2146,6 @@ err = ext3_add_nondir(handle, dentry, inode); ext3_journal_stop(handle); - unlock_kernel(); return err; } @@ -2212,13 +2168,10 @@ old_bh = new_bh = dir_bh = NULL; - lock_kernel(); handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); - if (IS_ERR(handle)) { - unlock_kernel(); + if (IS_ERR(handle)) return PTR_ERR(handle); - } if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) handle->h_sync = 1; @@ -2346,7 +2299,6 @@ brelse (old_bh); brelse (new_bh); ext3_journal_stop(handle); - unlock_kernel(); return retval; } @@ -2378,6 +2330,4 @@ .listxattr = ext3_listxattr, .removexattr = ext3_removexattr, .permission = ext3_permission, -}; - - +}; diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c --- a/fs/ext3/super.c Sun May 25 18:42:20 2003 +++ b/fs/ext3/super.c Tue Jun 17 23:04:25 2003 @@ -947,6 +947,9 @@ block += EXT3_BLOCKS_PER_GROUP(sb); gdp++; } + + sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); + sbi->s_es->s_free_inodes_count=cpu_to_le32(ext3_count_free_inodes(sb)); return 1; } @@ -1307,13 +1310,19 @@ printk (KERN_ERR "EXT3-fs: not enough memory\n"); goto failed_mount; } - sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), + sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(u8), GFP_KERNEL); if (!sbi->s_debts) { - printk ("EXT3-fs: not enough memory\n"); + printk("EXT3-fs: not enough memory to allocate s_bgi\n"); goto failed_mount2; } - memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts)); + memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(u8)); + + percpu_counter_init(&sbi->s_freeblocks_counter); + percpu_counter_init(&sbi->s_freeinodes_counter); + percpu_counter_init(&sbi->s_dirs_counter); + bgl_lock_init(&sbi->s_blockgroup_lock); + for (i = 0; i < db_count; i++) { block = descriptor_loc(sb, logic_sb_block, i); sbi->s_group_desc[i] = sb_bread(sb, block); @@ -1329,7 +1338,6 @@ goto failed_mount2; } sbi->s_gdb_count = db_count; - sbi->s_dir_count = ext3_count_dirs(sb); /* * set up enough so that it can read an inode */ @@ -1427,13 +1435,19 @@ test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": "writeback"); + percpu_counter_mod(&sbi->s_freeblocks_counter, + ext3_count_free_blocks(sb)); + percpu_counter_mod(&sbi->s_freeinodes_counter, + ext3_count_free_inodes(sb)); + percpu_counter_mod(&sbi->s_dirs_counter, + ext3_count_dirs(sb)); + return 0; failed_mount3: journal_destroy(sbi->s_journal); failed_mount2: - if (sbi->s_debts) - kfree(sbi->s_debts); + kfree(sbi->s_debts); for (i = 0; i < db_count; i++) brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); @@ -1702,6 +1716,8 @@ if (!sbh) return; es->s_wtime = cpu_to_le32(get_seconds()); + es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); + es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); BUFFER_TRACE(sbh, "marking dirty"); mark_buffer_dirty(sbh); if (sync) @@ -1777,9 +1793,7 @@ journal = EXT3_SB(sb)->s_journal; sb->s_dirt = 0; - lock_kernel(); /* important: lock down j_running_transaction */ ret = ext3_journal_force_commit(journal); - unlock_kernel(); return ret; } @@ -1794,24 +1808,21 @@ void ext3_write_super (struct super_block * sb) { - lock_kernel(); if (down_trylock(&sb->s_lock) == 0) BUG(); sb->s_dirt = 0; - log_start_commit(EXT3_SB(sb)->s_journal, NULL); - unlock_kernel(); + journal_start_commit(EXT3_SB(sb)->s_journal, NULL); } static int ext3_sync_fs(struct super_block *sb, int wait) { tid_t target; - lock_kernel(); sb->s_dirt = 0; - target = log_start_commit(EXT3_SB(sb)->s_journal, NULL); - if (wait) - log_wait_commit(EXT3_SB(sb)->s_journal, target); - unlock_kernel(); + if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { + if (wait) + log_wait_commit(EXT3_SB(sb)->s_journal, target); + } return 0; } @@ -1823,7 +1834,6 @@ { sb->s_dirt = 0; - lock_kernel(); /* 2.4.5 forgot to do this for us */ if (!(sb->s_flags & MS_RDONLY)) { journal_t *journal = EXT3_SB(sb)->s_journal; @@ -1835,7 +1845,6 @@ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); } - unlock_kernel(); } /* @@ -1845,14 +1854,12 @@ void ext3_unlockfs(struct super_block *sb) { if (!(sb->s_flags & MS_RDONLY)) { - lock_kernel(); lock_super(sb); /* Reser the needs_recovery flag before the fs is unlocked. */ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); unlock_super(sb); journal_unlock_updates(EXT3_SB(sb)->s_journal); - unlock_kernel(); } } @@ -1997,7 +2004,9 @@ static int ext3_sync_dquot(struct dquot *dquot) { - int nblocks, ret; + int nblocks; + int ret; + int err; handle_t *handle; struct quota_info *dqops = sb_dqopt(dquot->dq_sb); struct inode *qinode; @@ -2012,18 +2021,17 @@ default: nblocks = EXT3_MAX_TRANS_DATA; } - lock_kernel(); qinode = dqops->files[dquot->dq_type]->f_dentry->d_inode; handle = ext3_journal_start(qinode, nblocks); if (IS_ERR(handle)) { - unlock_kernel(); - return PTR_ERR(handle); + ret = PTR_ERR(handle); + goto out; } - unlock_kernel(); ret = old_sync_dquot(dquot); - lock_kernel(); - ret = ext3_journal_stop(handle); - unlock_kernel(); + err = ext3_journal_stop(handle); + if (ret == 0) + ret = err; +out: return ret; } #endif diff -Nru a/fs/ext3/xattr.c b/fs/ext3/xattr.c --- a/fs/ext3/xattr.c Mon May 5 06:18:48 2003 +++ b/fs/ext3/xattr.c Tue Jun 17 23:03:30 2003 @@ -849,7 +849,6 @@ handle_t *handle; int error, error2; - lock_kernel(); handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); if (IS_ERR(handle)) error = PTR_ERR(handle); @@ -857,7 +856,6 @@ error = ext3_xattr_set_handle(handle, inode, name_index, name, value, value_len, flags); error2 = ext3_journal_stop(handle); - unlock_kernel(); return error ? error : error2; } diff -Nru a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c --- a/fs/jbd/checkpoint.c Thu Mar 27 21:16:17 2003 +++ b/fs/jbd/checkpoint.c Tue Jun 17 23:04:25 2003 @@ -23,12 +23,10 @@ #include #include -extern spinlock_t journal_datalist_lock; - /* * Unlink a buffer from a transaction. * - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ static inline void __buffer_unlink(struct journal_head *jh) @@ -49,7 +47,8 @@ /* * Try to release a checkpointed buffer from its transaction. * Returns 1 if we released it. - * Requires journal_datalist_lock + * Requires j_list_lock + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ static int __try_to_free_cp_buf(struct journal_head *jh) { @@ -59,40 +58,63 @@ if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) { JBUFFER_TRACE(jh, "remove from checkpoint list"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); BUFFER_TRACE(bh, "release"); __brelse(bh); ret = 1; + } else { + jbd_unlock_bh_state(bh); } return ret; } /* - * log_wait_for_space: wait until there is space in the journal. + * __log_wait_for_space: wait until there is space in the journal. * - * Called with the journal already locked, but it will be unlocked if we have - * to wait for a checkpoint to free up some space in the log. + * Called under j-state_lock *only*. It will be unlocked if we have to wait + * for a checkpoint to free up some space in the log. */ -void log_wait_for_space(journal_t *journal, int nblocks) +void __log_wait_for_space(journal_t *journal, int nblocks) { - while (log_space_left(journal) < nblocks) { + assert_spin_locked(&journal->j_state_lock); + + while (__log_space_left(journal) < nblocks) { if (journal->j_flags & JFS_ABORT) return; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); down(&journal->j_checkpoint_sem); - lock_journal(journal); - /* Test again, another process may have checkpointed - * while we were waiting for the checkpoint lock */ - if (log_space_left(journal) < nblocks) { + /* + * Test again, another process may have checkpointed while we + * were waiting for the checkpoint lock + */ + spin_lock(&journal->j_state_lock); + if (__log_space_left(journal) < nblocks) { + spin_unlock(&journal->j_state_lock); log_do_checkpoint(journal, nblocks); + spin_lock(&journal->j_state_lock); } up(&journal->j_checkpoint_sem); } } /* + * We were unable to perform jbd_trylock_bh_state() inside j_list_lock. + * The caller must restart a list walk. Wait for someone else to run + * jbd_unlock_bh_state(). + */ +static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh) +{ + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_lock_bh_state(bh); + jbd_unlock_bh_state(bh); + put_bh(bh); +} + +/* * Clean up a transaction's checkpoint list. * * We wait for any pending IO to complete and make sure any clean @@ -102,8 +124,7 @@ * checkpoint. (journal_remove_checkpoint() deletes the transaction when * the last checkpoint buffer is cleansed) * - * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ static int __cleanup_transaction(journal_t *journal, transaction_t *transaction) { @@ -111,7 +132,7 @@ struct buffer_head *bh; int ret = 0; - assert_spin_locked(&journal_datalist_lock); + assert_spin_locked(&journal->j_list_lock); jh = transaction->t_checkpoint_list; if (!jh) return 0; @@ -123,67 +144,70 @@ bh = jh2bh(jh); if (buffer_locked(bh)) { atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); /* the journal_head may have gone by now */ BUFFER_TRACE(bh, "brelse"); __brelse(bh); goto out_return_1; } - + + /* + * This is foul + */ + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + goto out_return_1; + } + if (jh->b_transaction != NULL) { - transaction_t *transaction = jh->b_transaction; - tid_t tid = transaction->t_tid; + transaction_t *t = jh->b_transaction; + tid_t tid = t->t_tid; - spin_unlock(&journal_datalist_lock); - log_start_commit(journal, transaction); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + log_start_commit(journal, tid); log_wait_commit(journal, tid); goto out_return_1; } /* - * We used to test for (jh->b_list != BUF_CLEAN) here. - * But unmap_underlying_metadata() can place buffer onto - * BUF_CLEAN. - */ - /* - * AKPM: I think the buffer_jdirty test is redundant - it + * AKPM: I think the buffer_jbddirty test is redundant - it * shouldn't have NULL b_transaction? */ next_jh = jh->b_cpnext; - if (!buffer_dirty(bh) && !buffer_jdirty(bh)) { + if (!buffer_dirty(bh) && !buffer_jbddirty(bh)) { BUFFER_TRACE(bh, "remove from checkpoint"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); __brelse(bh); ret = 1; + } else { + jbd_unlock_bh_state(bh); } - jh = next_jh; } while (jh != last_jh); return ret; out_return_1: - lock_journal(journal); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); return 1; } #define NR_BATCH 64 -static void __flush_batch(struct buffer_head **bhs, int *batch_count) +static void +__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) { int i; - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); ll_rw_block(WRITE, *batch_count, bhs); - blk_run_queues(); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); for (i = 0; i < *batch_count; i++) { struct buffer_head *bh = bhs[i]; - clear_bit(BH_JWrite, &bh->b_state); + clear_buffer_jwrite(bh); BUFFER_TRACE(bh, "brelse"); __brelse(bh); } @@ -196,7 +220,8 @@ * Return 1 if something happened which requires us to abort the current * scan of the checkpoint list. * - * Called with journal_datalist_lock held. + * Called with j_list_lock held. + * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it */ static int __flush_buffer(journal_t *journal, struct journal_head *jh, struct buffer_head **bhs, int *batch_count, @@ -216,13 +241,14 @@ * disk, as that would break recoverability. */ BUFFER_TRACE(bh, "queue"); - atomic_inc(&bh->b_count); - J_ASSERT_BH(bh, !test_bit(BH_JWrite, &bh->b_state)); - set_bit(BH_JWrite, &bh->b_state); + get_bh(bh); + J_ASSERT_BH(bh, !buffer_jwrite(bh)); + set_buffer_jwrite(bh); bhs[*batch_count] = bh; + jbd_unlock_bh_state(bh); (*batch_count)++; if (*batch_count == NR_BATCH) { - __flush_batch(bhs, batch_count); + __flush_batch(journal, bhs, batch_count); ret = 1; } } else { @@ -246,7 +272,7 @@ * Perform an actual checkpoint. We don't write out only enough to * satisfy the current blocked requests: rather we submit a reasonably * sized chunk of the outstanding data to disk at once for - * efficiency. log_wait_for_space() will retry if we didn't free enough. + * efficiency. __log_wait_for_space() will retry if we didn't free enough. * * However, we _do_ take into account the amount requested so that once * the IO has been queued, we can return as soon as enough of it has @@ -256,9 +282,8 @@ */ /* @@@ `nblocks' is unused. Should it be used? */ -int log_do_checkpoint (journal_t *journal, int nblocks) +int log_do_checkpoint(journal_t *journal, int nblocks) { - transaction_t *transaction, *last_transaction, *next_transaction; int result; int batch_count = 0; struct buffer_head *bhs[NR_BATCH]; @@ -283,36 +308,59 @@ * AKPM: check this code. I had a feeling a while back that it * degenerates into a busy loop at unmount time. */ - spin_lock(&journal_datalist_lock); -repeat: - transaction = journal->j_checkpoint_transactions; - if (transaction == NULL) - goto done; - last_transaction = transaction->t_cpprev; - next_transaction = transaction; - - do { + spin_lock(&journal->j_list_lock); + while (journal->j_checkpoint_transactions) { + transaction_t *transaction; struct journal_head *jh, *last_jh, *next_jh; int drop_count = 0; int cleanup_ret, retry = 0; + tid_t this_tid; - transaction = next_transaction; - next_transaction = transaction->t_cpnext; + transaction = journal->j_checkpoint_transactions->t_cpnext; + this_tid = transaction->t_tid; jh = transaction->t_checkpoint_list; last_jh = jh->b_cpprev; next_jh = jh; do { + struct buffer_head *bh; + jh = next_jh; next_jh = jh->b_cpnext; + bh = jh2bh(jh); + if (!jbd_trylock_bh_state(bh)) { + jbd_sync_bh(journal, bh); + spin_lock(&journal->j_list_lock); + retry = 1; + break; + } retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count); } while (jh != last_jh && !retry); if (batch_count) { - __flush_batch(bhs, &batch_count); - goto repeat; + __flush_batch(journal, bhs, &batch_count); + continue; } if (retry) - goto repeat; + continue; + + /* + * If someone emptied the checkpoint list while we slept, we're + * done. + */ + if (!journal->j_checkpoint_transactions) + break; + /* + * If someone cleaned up this transaction while we slept, we're + * done + */ + if (journal->j_checkpoint_transactions->t_cpnext != transaction) + continue; + /* + * Maybe it's a new transaction, but it fell at the same + * address + */ + if (transaction->t_tid != this_tid) + continue; /* * We have walked the whole transaction list without * finding anything to write to disk. We had better be @@ -320,11 +368,8 @@ */ cleanup_ret = __cleanup_transaction(journal, transaction); J_ASSERT(drop_count != 0 || cleanup_ret != 0); - goto repeat; /* __cleanup may have dropped lock */ - } while (transaction != last_transaction); - -done: - spin_unlock(&journal_datalist_lock); + } + spin_unlock(&journal->j_list_lock); result = cleanup_journal_tail(journal); if (result < 0) return result; @@ -362,8 +407,8 @@ * next transaction ID we will write, and where it will * start. */ - /* j_checkpoint_transactions needs locking */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); transaction = journal->j_checkpoint_transactions; if (transaction) { first_tid = transaction->t_tid; @@ -378,13 +423,15 @@ first_tid = journal->j_transaction_sequence; blocknr = journal->j_head; } - spin_unlock(&journal_datalist_lock); - J_ASSERT (blocknr != 0); + spin_unlock(&journal->j_list_lock); + J_ASSERT(blocknr != 0); /* If the oldest pinned transaction is at the tail of the log already then there's not much we can do right now. */ - if (journal->j_tail_sequence == first_tid) + if (journal->j_tail_sequence == first_tid) { + spin_unlock(&journal->j_state_lock); return 1; + } /* OK, update the superblock to recover the freed space. * Physical blocks come first: have we wrapped beyond the end of @@ -401,6 +448,7 @@ journal->j_free += freed; journal->j_tail_sequence = first_tid; journal->j_tail = blocknr; + spin_unlock(&journal->j_state_lock); if (!(journal->j_flags & JFS_ABORT)) journal_update_superblock(journal, 1); return 0; @@ -415,7 +463,7 @@ * Find all the written-back checkpoint buffers in the journal and release them. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. * Returns number of bufers reaped (for debug) */ @@ -439,10 +487,13 @@ if (jh) { struct journal_head *last_jh = jh->b_cpprev; struct journal_head *next_jh = jh; + do { jh = next_jh; next_jh = jh->b_cpnext; - ret += __try_to_free_cp_buf(jh); + /* Use trylock because of the ranknig */ + if (jbd_trylock_bh_state(jh2bh(jh))) + ret += __try_to_free_cp_buf(jh); } while (jh != last_jh); } } while (transaction != last_transaction); @@ -464,7 +515,7 @@ * checkpoint list. * * This function is called with the journal locked. - * This function is called with journal_datalist_lock held. + * This function is called with j_list_lock held. */ void __journal_remove_checkpoint(struct journal_head *jh) @@ -478,7 +529,6 @@ JBUFFER_TRACE(jh, "not on transaction"); goto out; } - journal = transaction->t_journal; __buffer_unlink(jh); @@ -487,11 +537,15 @@ goto out; JBUFFER_TRACE(jh, "transaction has no more buffers"); - /* There is one special case to worry about: if we have just - pulled the buffer off a committing transaction's forget list, - then even if the checkpoint list is empty, the transaction - obviously cannot be dropped! */ - + /* + * There is one special case to worry about: if we have just pulled the + * buffer off a committing transaction's forget list, then even if the + * checkpoint list is empty, the transaction obviously cannot be + * dropped! + * + * The locking here around j_committing_transaction is a bit sleazy. + * See the comment at the end of journal_commit_transaction(). + */ if (transaction == journal->j_committing_transaction) { JBUFFER_TRACE(jh, "belongs to committing transaction"); goto out; @@ -509,29 +563,21 @@ JBUFFER_TRACE(jh, "exit"); } -void journal_remove_checkpoint(struct journal_head *jh) -{ - spin_lock(&journal_datalist_lock); - __journal_remove_checkpoint(jh); - spin_unlock(&journal_datalist_lock); -} - /* * journal_insert_checkpoint: put a committed buffer onto a checkpoint * list so that we know when it is safe to clean the transaction out of * the log. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ void __journal_insert_checkpoint(struct journal_head *jh, transaction_t *transaction) { JBUFFER_TRACE(jh, "entry"); - J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jdirty(jh2bh(jh))); + J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - assert_spin_locked(&journal_datalist_lock); jh->b_cp_transaction = transaction; if (!transaction->t_checkpoint_list) { @@ -545,14 +591,6 @@ transaction->t_checkpoint_list = jh; } -void journal_insert_checkpoint(struct journal_head *jh, - transaction_t *transaction) -{ - spin_lock(&journal_datalist_lock); - __journal_insert_checkpoint(jh, transaction); - spin_unlock(&journal_datalist_lock); -} - /* * We've finished with this transaction structure: adios... * @@ -560,12 +598,12 @@ * point. * * Called with the journal locked. - * Called with journal_datalist_lock held. + * Called with j_list_lock held. */ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) { - assert_spin_locked(&journal_datalist_lock); + assert_spin_locked(&journal->j_list_lock); if (transaction->t_cpnext) { transaction->t_cpnext->t_cpprev = transaction->t_cpprev; transaction->t_cpprev->t_cpnext = transaction->t_cpnext; @@ -576,22 +614,19 @@ journal->j_checkpoint_transactions = NULL; } - J_ASSERT (transaction->t_ilist == NULL); - J_ASSERT (transaction->t_buffers == NULL); - J_ASSERT (transaction->t_sync_datalist == NULL); - J_ASSERT (transaction->t_forget == NULL); - J_ASSERT (transaction->t_iobuf_list == NULL); - J_ASSERT (transaction->t_shadow_list == NULL); - J_ASSERT (transaction->t_log_list == NULL); - J_ASSERT (transaction->t_checkpoint_list == NULL); - J_ASSERT (transaction->t_updates == 0); - J_ASSERT (list_empty(&transaction->t_jcb)); + J_ASSERT(transaction->t_state == T_FINISHED); + J_ASSERT(transaction->t_buffers == NULL); + J_ASSERT(transaction->t_sync_datalist == NULL); + J_ASSERT(transaction->t_forget == NULL); + J_ASSERT(transaction->t_iobuf_list == NULL); + J_ASSERT(transaction->t_shadow_list == NULL); + J_ASSERT(transaction->t_log_list == NULL); + J_ASSERT(transaction->t_checkpoint_list == NULL); + J_ASSERT(transaction->t_updates == 0); + J_ASSERT(list_empty(&transaction->t_jcb)); + J_ASSERT(journal->j_committing_transaction != transaction); + J_ASSERT(journal->j_running_transaction != transaction); - J_ASSERT (transaction->t_journal->j_committing_transaction != - transaction); - - jbd_debug (1, "Dropping transaction %d, all done\n", - transaction->t_tid); - kfree (transaction); + jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); + kfree(transaction); } - diff -Nru a/fs/jbd/commit.c b/fs/jbd/commit.c --- a/fs/jbd/commit.c Wed Apr 2 22:51:44 2003 +++ b/fs/jbd/commit.c Tue Jun 17 23:04:24 2003 @@ -18,10 +18,10 @@ #include #include #include +#include +#include #include -extern spinlock_t journal_datalist_lock; - /* * Default IO end handler for temporary BJ_IO buffer_heads. */ @@ -36,6 +36,49 @@ } /* + * When an ext3-ordered file is truncated, it is possible that many pages are + * not sucessfully freed, because they are attached to a committing transaction. + * After the transaction commits, these pages are left on the LRU, with no + * ->mapping, and with attached buffers. These pages are trivially reclaimable + * by the VM, but their apparent absence upsets the VM accounting, and it makes + * the numbers in /proc/meminfo look odd. + * + * So here, we have a buffer which has just come off the forget list. Look to + * see if we can strip all buffers from the backing page. + * + * Called under lock_journal(), and possibly under journal_datalist_lock. The + * caller provided us with a ref against the buffer, and we drop that here. + */ +static void release_buffer_page(struct buffer_head *bh) +{ + struct page *page; + + if (buffer_dirty(bh)) + goto nope; + if (atomic_read(&bh->b_count) != 1) + goto nope; + page = bh->b_page; + if (!page) + goto nope; + if (page->mapping) + goto nope; + + /* OK, it's a truncated page */ + if (TestSetPageLocked(page)) + goto nope; + + page_cache_get(page); + __brelse(bh); + try_to_free_buffers(page); + unlock_page(page); + page_cache_release(page); + return; + +nope: + __brelse(bh); +} + +/* * journal_commit_transaction * * The primary function for committing a transaction to the log. This @@ -64,43 +107,52 @@ * all outstanding updates to complete. */ - lock_journal(journal); /* Protect journal->j_running_transaction */ - #ifdef COMMIT_STATS - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); summarise_journal_usage(journal); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); #endif - lock_kernel(); + /* Do we need to erase the effects of a prior journal_flush? */ + if (journal->j_flags & JFS_FLUSHED) { + jbd_debug(3, "super block updated\n"); + journal_update_superblock(journal, 1); + } else { + jbd_debug(3, "superblock not updated\n"); + } - J_ASSERT (journal->j_running_transaction != NULL); - J_ASSERT (journal->j_committing_transaction == NULL); + J_ASSERT(journal->j_running_transaction != NULL); + J_ASSERT(journal->j_committing_transaction == NULL); commit_transaction = journal->j_running_transaction; - J_ASSERT (commit_transaction->t_state == T_RUNNING); + J_ASSERT(commit_transaction->t_state == T_RUNNING); - jbd_debug (1, "JBD: starting commit of transaction %d\n", - commit_transaction->t_tid); + jbd_debug(1, "JBD: starting commit of transaction %d\n", + commit_transaction->t_tid); + spin_lock(&journal->j_state_lock); commit_transaction->t_state = T_LOCKED; - while (commit_transaction->t_updates != 0) { - unlock_journal(journal); - sleep_on(&journal->j_wait_updates); - lock_journal(journal); + + spin_lock(&commit_transaction->t_handle_lock); + while (commit_transaction->t_updates) { + DEFINE_WAIT(wait); + + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + if (commit_transaction->t_updates) { + spin_unlock(&commit_transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); + spin_lock(&commit_transaction->t_handle_lock); + } + finish_wait(&journal->j_wait_updates, &wait); } + spin_unlock(&commit_transaction->t_handle_lock); J_ASSERT (commit_transaction->t_outstanding_credits <= journal->j_max_transaction_buffers); - /* Do we need to erase the effects of a prior journal_flush? */ - if (journal->j_flags & JFS_FLUSHED) { - jbd_debug(3, "super block updated\n"); - journal_update_superblock(journal, 1); - } else { - jbd_debug(3, "superblock not updated\n"); - } - /* * First thing we are allowed to do is to discard any remaining * BJ_Reserved buffers. Note, it is _not_ permissible to assume @@ -117,11 +169,10 @@ * that multiple journal_get_write_access() calls to the same * buffer are perfectly permissable. */ - while (commit_transaction->t_reserved_list) { jh = commit_transaction->t_reserved_list; JBUFFER_TRACE(jh, "reserved, unused: refile"); - journal_refile_buffer(jh); + journal_refile_buffer(journal, jh); } /* @@ -129,42 +180,23 @@ * checkpoint lists. We do this *before* commit because it potentially * frees some memory */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); __journal_clean_checkpoint_list(journal); - spin_unlock(&journal_datalist_lock); - - /* First part of the commit: force the revoke list out to disk. - * The revoke code generates its own metadata blocks on disk for this. - * - * It is important that we do this while the transaction is - * still locked. Generating the revoke records should not - * generate any IO stalls, so this should be quick; and doing - * the work while we have the transaction locked means that we - * only ever have to maintain the revoke list for one - * transaction at a time. - */ + spin_unlock(&journal->j_list_lock); jbd_debug (3, "JBD: commit phase 1\n"); - journal_write_revoke_records(journal, commit_transaction); - /* - * Now that we have built the revoke records, we can start - * reusing the revoke list for a new running transaction. We - * can now safely start committing the old transaction: time to - * get a new running transaction for incoming filesystem updates + * Switch to a new revoke table. */ + journal_switch_revoke_table(journal); commit_transaction->t_state = T_FLUSH; - - wake_up(&journal->j_wait_transaction_locked); - journal->j_committing_transaction = commit_transaction; journal->j_running_transaction = NULL; - commit_transaction->t_log_start = journal->j_head; - - unlock_kernel(); + wake_up(&journal->j_wait_transaction_locked); + spin_unlock(&journal->j_state_lock); jbd_debug (3, "JBD: commit phase 2\n"); @@ -185,10 +217,10 @@ * Cleanup any flushed data buffers from the data list. Even in * abort mode, we want to flush this out as soon as possible. * - * We take journal_datalist_lock to protect the lists from + * We take j_list_lock to protect the lists from * journal_try_to_free_buffers(). */ - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); write_out_data_locked: bufs = 0; @@ -210,9 +242,19 @@ wbuf[bufs++] = bh; } else { BUFFER_TRACE(bh, "writeout complete: unfile"); + /* + * We have a lock ranking problem.. + */ + if (!jbd_trylock_bh_state(bh)) { + spin_unlock(&journal->j_list_lock); + schedule(); + spin_lock(&journal->j_list_lock); + break; + } __journal_unfile_buffer(jh); jh->b_transaction = NULL; - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); __brelse(bh); } } @@ -228,14 +270,12 @@ if (bufs || need_resched()) { jbd_debug(2, "submit %d writes\n", bufs); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); if (bufs) ll_rw_block(WRITE, bufs, wbuf); cond_resched(); journal_brelse_array(wbuf, bufs); - lock_journal(journal); - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); if (bufs) goto write_out_data_locked; } @@ -253,14 +293,12 @@ bh = jh2bh(jh); if (buffer_locked(bh)) { get_bh(bh); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; put_bh(bh); /* the journal_head may have been removed now */ - lock_journal(journal); goto write_out_data; } else if (buffer_dirty(bh)) { goto write_out_data_locked; @@ -269,7 +307,11 @@ goto write_out_data_locked; sync_datalist_empty: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + + journal_write_revoke_records(journal, commit_transaction); + + jbd_debug(3, "JBD: commit phase 2\n"); /* * If we found any dirty or locked buffers, then we should have @@ -301,7 +343,7 @@ if (is_journal_aborted(journal)) { JBUFFER_TRACE(jh, "journal is aborting: refile"); - journal_refile_buffer(jh); + journal_refile_buffer(journal, jh); /* If that was the last one, we need to clean up * any descriptor buffers which may have been * already allocated, even if we are now @@ -345,7 +387,7 @@ completion later */ BUFFER_TRACE(bh, "ph3: file as descriptor"); journal_file_buffer(descriptor, commit_transaction, - BJ_LogCtl); + BJ_LogCtl); } /* Where is the buffer to be written? */ @@ -419,8 +461,7 @@ tag->t_flags |= htonl(JFS_FLAG_LAST_TAG); start_journal_io: - unlock_journal(journal); - for (i=0; it_iobuf_list != NULL) { struct buffer_head *bh; + jh = commit_transaction->t_iobuf_list->b_tprev; bh = jh2bh(jh); if (buffer_locked(bh)) { - unlock_journal(journal); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; - lock_journal(journal); goto wait_for_iobuf; } - clear_bit(BH_JWrite, &jh2bh(jh)->b_state); + clear_buffer_jwrite(bh); JBUFFER_TRACE(jh, "ph4: unfile after journal write"); - journal_unfile_buffer(jh); + journal_unfile_buffer(journal, jh); /* * akpm: don't put back a buffer_head with stale pointers @@ -485,9 +524,8 @@ * ->t_iobuf_list should contain only dummy buffer_heads * which were created by journal_write_metadata_buffer(). */ - bh = jh2bh(jh); BUFFER_TRACE(bh, "dumping temporary bh"); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); __brelse(bh); J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); free_buffer_head(bh); @@ -497,7 +535,7 @@ jh = commit_transaction->t_shadow_list->b_tprev; bh = jh2bh(jh); clear_bit(BH_JWrite, &bh->b_state); - J_ASSERT_BH(bh, buffer_jdirty(bh)); + J_ASSERT_BH(bh, buffer_jbddirty(bh)); /* The metadata is now released for reuse, but we need to remember it against this transaction so that when @@ -524,29 +562,25 @@ jh = commit_transaction->t_log_list->b_tprev; bh = jh2bh(jh); if (buffer_locked(bh)) { - unlock_journal(journal); wait_on_buffer(bh); if (unlikely(!buffer_uptodate(bh))) err = -EIO; - lock_journal(journal); goto wait_for_ctlbuf; } BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); - clear_bit(BH_JWrite, &bh->b_state); - journal_unfile_buffer(jh); + clear_buffer_jwrite(bh); + journal_unfile_buffer(journal, jh); jh->b_transaction = NULL; - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); __brelse(bh); /* One for getblk */ /* AKPM: bforget here */ } jbd_debug(3, "JBD: commit phase 6\n"); - if (is_journal_aborted(journal)) { - unlock_journal(journal); + if (is_journal_aborted(journal)) goto skip_commit; - } /* Done it all: now write the commit record. We should have * cleaned up our previous buffers by now, so if we are in abort @@ -556,7 +590,6 @@ descriptor = journal_get_descriptor_buffer(journal); if (!descriptor) { __journal_abort_hard(journal); - unlock_journal(journal); goto skip_commit; } @@ -569,7 +602,6 @@ tmp->h_sequence = htonl(commit_transaction->t_tid); } - unlock_journal(journal); JBUFFER_TRACE(descriptor, "write commit block"); { struct buffer_head *bh = jh2bh(descriptor); @@ -578,7 +610,7 @@ if (unlikely(!buffer_uptodate(bh))) err = -EIO; put_bh(bh); /* One for getblk() */ - journal_unlock_journal_head(descriptor); + journal_put_journal_head(descriptor); } /* End of a transaction! Finally, we can do checkpoint @@ -588,16 +620,17 @@ skip_commit: /* The journal should be unlocked by now. */ - if (err) { - lock_journal(journal); + if (err) __journal_abort_hard(journal); - unlock_journal(journal); - } - /* Call any callbacks that had been registered for handles in this + /* + * Call any callbacks that had been registered for handles in this * transaction. It is up to the callback to free any allocated * memory. + * + * The spinlocking (t_jcb_lock) here is surely unnecessary... */ + spin_lock(&commit_transaction->t_jcb_lock); if (!list_empty(&commit_transaction->t_jcb)) { struct list_head *p, *n; int error = is_journal_aborted(journal); @@ -607,11 +640,12 @@ jcb = list_entry(p, struct journal_callback, jcb_list); list_del(p); + spin_unlock(&commit_transaction->t_jcb_lock); jcb->jcb_func(jcb, error); + spin_lock(&commit_transaction->t_jcb_lock); } } - - lock_journal(journal); + spin_unlock(&commit_transaction->t_jcb_lock); jbd_debug(3, "JBD: commit phase 7\n"); @@ -627,6 +661,8 @@ struct buffer_head *bh; jh = commit_transaction->t_forget; + bh = jh2bh(jh); + jbd_lock_bh_state(bh); J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || jh->b_transaction == journal->j_running_transaction); @@ -652,7 +688,7 @@ jh->b_frozen_data = NULL; } - spin_lock(&journal_datalist_lock); + spin_lock(&journal->j_list_lock); cp_transaction = jh->b_cp_transaction; if (cp_transaction) { JBUFFER_TRACE(jh, "remove from old cp transaction"); @@ -665,7 +701,6 @@ * by journal_forget, it may no longer be dirty and * there's no point in keeping a checkpoint record for * it. */ - bh = jh2bh(jh); /* A buffer which has been freed while still being * journaled by a previous transaction may end up still @@ -680,34 +715,45 @@ clear_buffer_jbddirty(bh); } - if (buffer_jdirty(bh)) { + if (buffer_jbddirty(bh)) { JBUFFER_TRACE(jh, "add to new checkpointing trans"); __journal_insert_checkpoint(jh, commit_transaction); JBUFFER_TRACE(jh, "refile for checkpoint writeback"); __journal_refile_buffer(jh); + jbd_unlock_bh_state(bh); } else { J_ASSERT_BH(bh, !buffer_dirty(bh)); J_ASSERT_JH(jh, jh->b_next_transaction == NULL); __journal_unfile_buffer(jh); jh->b_transaction = 0; - __journal_remove_journal_head(bh); - __brelse(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); + if (buffer_freed(bh)) + release_buffer_page(bh); } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); } /* Done with this transaction! */ jbd_debug(3, "JBD: commit phase 8\n"); - J_ASSERT (commit_transaction->t_state == T_COMMIT); - commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction->t_state == T_COMMIT); - J_ASSERT (commit_transaction == journal->j_committing_transaction); + /* + * This is a bit sleazy. We borrow j_list_lock to protect + * journal->j_committing_transaction in __journal_remove_checkpoint. + * Really, __jornal_remove_checkpoint should be using j_state_lock but + * it's a bit hassle to hold that across __journal_remove_checkpoint + */ + spin_lock(&journal->j_state_lock); + spin_lock(&journal->j_list_lock); + commit_transaction->t_state = T_FINISHED; + J_ASSERT(commit_transaction == journal->j_committing_transaction); journal->j_commit_sequence = commit_transaction->t_tid; journal->j_committing_transaction = NULL; + spin_unlock(&journal->j_state_lock); - spin_lock(&journal_datalist_lock); if (commit_transaction->t_checkpoint_list == NULL) { __journal_drop_transaction(journal, commit_transaction); } else { @@ -726,11 +772,10 @@ commit_transaction; } } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); jbd_debug(1, "JBD: commit %d complete, head %d\n", journal->j_commit_sequence, journal->j_tail_sequence); - unlock_journal(journal); wake_up(&journal->j_wait_done_commit); } diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c --- a/fs/jbd/journal.c Wed Jun 4 00:50:40 2003 +++ b/fs/jbd/journal.c Tue Jun 17 23:04:25 2003 @@ -48,9 +48,7 @@ EXPORT_SYMBOL(journal_get_undo_access); EXPORT_SYMBOL(journal_dirty_data); EXPORT_SYMBOL(journal_dirty_metadata); -#if 0 EXPORT_SYMBOL(journal_release_buffer); -#endif EXPORT_SYMBOL(journal_forget); #if 0 EXPORT_SYMBOL(journal_sync_buffer); @@ -75,7 +73,7 @@ EXPORT_SYMBOL(journal_ack_err); EXPORT_SYMBOL(journal_clear_err); EXPORT_SYMBOL(log_wait_commit); -EXPORT_SYMBOL(log_start_commit); +EXPORT_SYMBOL(journal_start_commit); EXPORT_SYMBOL(journal_wipe); EXPORT_SYMBOL(journal_blocks_per_page); EXPORT_SYMBOL(journal_invalidatepage); @@ -86,76 +84,6 @@ static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); /* - * journal_datalist_lock is used to protect data buffers: - * - * bh->b_transaction - * bh->b_tprev - * bh->b_tnext - * - * journal_free_buffer() is called from journal_try_to_free_buffer(), and is - * async wrt everything else. - * - * It is also used for checkpoint data, also to protect against - * journal_try_to_free_buffer(): - * - * bh->b_cp_transaction - * bh->b_cpnext - * bh->b_cpprev - * transaction->t_checkpoint_list - * transaction->t_cpnext - * transaction->t_cpprev - * journal->j_checkpoint_transactions - * - * It is global at this time rather than per-journal because it's - * impossible for __journal_free_buffer to go from a buffer_head - * back to a journal_t unracily (well, not true. Fix later) - * - * - * The `datalist' and `checkpoint list' functions are quite - * separate and we could use two spinlocks here. - * - * lru_list_lock nests inside journal_datalist_lock. - */ -spinlock_t journal_datalist_lock = SPIN_LOCK_UNLOCKED; - -/* - * jh_splice_lock needs explantion. - * - * In a number of places we want to do things like: - * - * if (buffer_jbd(bh) && bh2jh(bh)->foo) - * - * This is racy on SMP, because another CPU could remove the journal_head - * in the middle of this expression. We need locking. - * - * But we can greatly optimise the locking cost by testing BH_JBD - * outside the lock. So, effectively: - * - * ret = 0; - * if (buffer_jbd(bh)) { - * spin_lock(&jh_splice_lock); - * if (buffer_jbd(bh)) { (* Still there? *) - * ret = bh2jh(bh)->foo; - * } - * spin_unlock(&jh_splice_lock); - * } - * return ret; - * - * Now, that protects us from races where another CPU can remove the - * journal_head. But it doesn't defend us from the situation where another - * CPU can *add* a journal_head. This is a correctness issue. But it's not - * a problem because a) the calling code was *already* racy and b) it often - * can't happen at the call site and c) the places where we add journal_heads - * tend to be under external locking. - */ -spinlock_t jh_splice_lock = SPIN_LOCK_UNLOCKED; - -/* - * List of all journals in the system. Protected by the BKL. - */ -static LIST_HEAD(all_journals); - -/* * Helper function used to manage commit timeouts */ @@ -204,8 +132,6 @@ daemonize("kjournald"); - lock_kernel(); - /* Set up an interval timer which can be used to trigger a commit wakeup after the commit interval expires */ init_timer(&timer); @@ -219,68 +145,87 @@ printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", journal->j_commit_interval / HZ); - list_add(&journal->j_all_journals, &all_journals); - /* And now, wait forever for commit wakeup events. */ - while (1) { - if (journal->j_flags & JFS_UNMOUNT) - break; - - jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", - journal->j_commit_sequence, journal->j_commit_request); - - if (journal->j_commit_sequence != journal->j_commit_request) { - jbd_debug(1, "OK, requests differ\n"); - if (journal->j_commit_timer_active) { - journal->j_commit_timer_active = 0; - del_timer(journal->j_commit_timer); - } + /* + * And now, wait forever for commit wakeup events. + */ + spin_lock(&journal->j_state_lock); - journal_commit_transaction(journal); - continue; - } +loop: + jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", + journal->j_commit_sequence, journal->j_commit_request); + + if (journal->j_commit_sequence != journal->j_commit_request) { + jbd_debug(1, "OK, requests differ\n"); + spin_unlock(&journal->j_state_lock); + del_timer_sync(journal->j_commit_timer); + journal_commit_transaction(journal); + spin_lock(&journal->j_state_lock); + goto loop; + } - wake_up(&journal->j_wait_done_commit); - if (current->flags & PF_FREEZE) { /* The simpler the better. Flushing journal isn't a - good idea, because that depends on threads that - may be already stopped. */ - jbd_debug(1, "Now suspending kjournald\n"); - refrigerator(PF_IOTHREAD); - jbd_debug(1, "Resuming kjournald\n"); - } else /* we assume on resume that commits are already there, - so we don't sleep */ - interruptible_sleep_on(&journal->j_wait_commit); - - jbd_debug(1, "kjournald wakes\n"); - - /* Were we woken up by a commit wakeup event? */ - if ((transaction = journal->j_running_transaction) != NULL && - time_after_eq(jiffies, transaction->t_expires)) { - journal->j_commit_request = transaction->t_tid; - jbd_debug(1, "woke because of timeout\n"); + wake_up(&journal->j_wait_done_commit); + if (current->flags & PF_FREEZE) { + /* + * The simpler the better. Flushing journal isn't a + * good idea, because that depends on threads that may + * be already stopped. + */ + jbd_debug(1, "Now suspending kjournald\n"); + spin_unlock(&journal->j_state_lock); + refrigerator(PF_IOTHREAD); + spin_lock(&journal->j_state_lock); + jbd_debug(1, "Resuming kjournald\n"); + } else { + /* + * We assume on resume that commits are already there, + * so we don't sleep + */ + DEFINE_WAIT(wait); + int should_sleep = 1; + + prepare_to_wait(&journal->j_wait_commit, &wait, + TASK_INTERRUPTIBLE); + if (journal->j_commit_sequence != journal->j_commit_request) + should_sleep = 0; + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, + transaction->t_expires)) + should_sleep = 0; + if (should_sleep) { + spin_unlock(&journal->j_state_lock); + schedule(); + spin_lock(&journal->j_state_lock); } + finish_wait(&journal->j_wait_commit, &wait); } - if (journal->j_commit_timer_active) { - journal->j_commit_timer_active = 0; - del_timer_sync(journal->j_commit_timer); + jbd_debug(1, "kjournald wakes\n"); + + /* + * Were we woken up by a commit wakeup event? + */ + transaction = journal->j_running_transaction; + if (transaction && time_after_eq(jiffies, transaction->t_expires)) { + journal->j_commit_request = transaction->t_tid; + jbd_debug(1, "woke because of timeout\n"); } - list_del(&journal->j_all_journals); + if (!(journal->j_flags & JFS_UNMOUNT)) + goto loop; + spin_unlock(&journal->j_state_lock); + del_timer_sync(journal->j_commit_timer); journal->j_task = NULL; wake_up(&journal->j_wait_done_commit); jbd_debug(1, "Journal thread exiting.\n"); - unlock_kernel(); return 0; } static void journal_start_thread(journal_t *journal) { - kernel_thread(kjournald, (void *) journal, - CLONE_VM | CLONE_FS | CLONE_FILES); - while (!journal->j_task) - sleep_on(&journal->j_wait_done_commit); + kernel_thread(kjournald, journal, CLONE_VM|CLONE_FS|CLONE_FILES); + wait_event(journal->j_wait_done_commit, journal->j_task != 0); } static void journal_kill_thread(journal_t *journal) @@ -289,60 +234,10 @@ while (journal->j_task) { wake_up(&journal->j_wait_commit); - sleep_on(&journal->j_wait_done_commit); + wait_event(journal->j_wait_done_commit, journal->j_task == 0); } } -#if 0 - -This is no longer needed - we do it in commit quite efficiently. -Note that if this function is resurrected, the loop needs to -be reorganised into the next_jh/last_jh algorithm. - -/* - * journal_clean_data_list: cleanup after data IO. - * - * Once the IO system has finished writing the buffers on the transaction's - * data list, we can remove those buffers from the list. This function - * scans the list for such buffers and removes them cleanly. - * - * We assume that the journal is already locked. - * We are called with journal_datalist_lock held. - * - * AKPM: This function looks inefficient. Approximately O(n^2) - * for potentially thousands of buffers. It no longer shows on profiles - * because these buffers are mainly dropped in journal_commit_transaction(). - */ - -void __journal_clean_data_list(transaction_t *transaction) -{ - struct journal_head *jh, *next; - - assert_spin_locked(&journal_datalist_lock); - -restart: - jh = transaction->t_sync_datalist; - if (!jh) - goto out; - do { - next = jh->b_tnext; - if (!buffer_locked(jh2bh(jh)) && !buffer_dirty(jh2bh(jh))) { - struct buffer_head *bh = jh2bh(jh); - BUFFER_TRACE(bh, "data writeout complete: unfile"); - __journal_unfile_buffer(jh); - jh->b_transaction = NULL; - __journal_remove_journal_head(bh); - __brelse(bh); - goto restart; - } - jh = next; - } while (transaction->t_sync_datalist && - jh != transaction->t_sync_datalist); -out: - return; -} -#endif - /* * journal_write_metadata_buffer: write a metadata buffer to the journal. * @@ -393,9 +288,10 @@ int do_escape = 0; char *mapped_data; struct buffer_head *new_bh; - struct journal_head * new_jh; + struct journal_head *new_jh; struct page *new_page; unsigned int new_offset; + struct buffer_head *bh_in = jh2bh(jh_in); /* * The buffer really shouldn't be locked: only the current committing @@ -406,13 +302,16 @@ * also part of a shared mapping, and another thread has * decided to launch a writepage() against this buffer. */ - J_ASSERT_JH(jh_in, buffer_jdirty(jh2bh(jh_in))); + J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); + + new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); /* * If a new transaction has already done a buffer copy-out, then * we use that version of the data for the commit. */ - + jbd_lock_bh_state(bh_in); +repeat: if (jh_in->b_frozen_data) { done_copy_out = 1; new_page = virt_to_page(jh_in->b_frozen_data); @@ -422,12 +321,13 @@ new_offset = virt_to_offset(jh2bh(jh_in)->b_data); } - mapped_data = ((char *) kmap(new_page)) + new_offset; + mapped_data = kmap_atomic(new_page, KM_USER0); /* * Check for escaping */ - if (* ((unsigned int *) mapped_data) == htonl(JFS_MAGIC_NUMBER)) { + if (*((unsigned int *)(mapped_data + new_offset)) == + htonl(JFS_MAGIC_NUMBER)) { need_copy_out = 1; do_escape = 1; } @@ -435,38 +335,47 @@ /* * Do we need to do a data copy? */ - if (need_copy_out && !done_copy_out) { char *tmp; - tmp = jbd_rep_kmalloc(jh2bh(jh_in)->b_size, GFP_NOFS); + + kunmap_atomic(mapped_data, KM_USER0); + jbd_unlock_bh_state(bh_in); + tmp = jbd_rep_kmalloc(bh_in->b_size, GFP_NOFS); + jbd_lock_bh_state(bh_in); + if (jh_in->b_frozen_data) { + kfree(new_page); + goto repeat; + } jh_in->b_frozen_data = tmp; - memcpy (tmp, mapped_data, jh2bh(jh_in)->b_size); - + mapped_data = kmap_atomic(new_page, KM_USER0); + memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); + /* If we get to this path, we'll always need the new address kmapped so that we can clear the escaped magic number below. */ - kunmap(new_page); new_page = virt_to_page(tmp); new_offset = virt_to_offset(tmp); - mapped_data = ((char *) kmap(new_page)) + new_offset; - done_copy_out = 1; } /* - * Right, time to make up the new buffer_head. + * Did we need to do an escaping? Now we've done all the + * copying, we can finally do so. */ - new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); + if (do_escape) + *((unsigned int *)(mapped_data + new_offset)) = 0; + kunmap_atomic(mapped_data, KM_USER0); /* keep subsequent assertions sane */ new_bh->b_state = 0; init_buffer(new_bh, NULL, NULL); atomic_set(&new_bh->b_count, 1); - new_jh = journal_add_journal_head(new_bh); + jbd_unlock_bh_state(bh_in); - set_bh_page(new_bh, new_page, new_offset); + new_jh = journal_add_journal_head(new_bh); /* This sleeps */ + set_bh_page(new_bh, new_page, new_offset); new_jh->b_transaction = NULL; new_bh->b_size = jh2bh(jh_in)->b_size; new_bh->b_bdev = transaction->t_journal->j_dev; @@ -477,15 +386,6 @@ *jh_out = new_jh; /* - * Did we need to do an escaping? Now we've done all the - * copying, we can finally do so. - */ - - if (do_escape) - * ((unsigned int *) mapped_data) = 0; - kunmap(new_page); - - /* * The to-be-written buffer needs to get moved to the io queue, * and the original buffer whose contents we are shadowing or * copying is moved to the transaction's shadow queue. @@ -504,17 +404,23 @@ */ /* - * log_space_left: Return the number of free blocks left in the journal. + * __log_space_left: Return the number of free blocks left in the journal. * * Called with the journal already locked. + * + * Called under j_state_lock */ -int log_space_left (journal_t *journal) +int __log_space_left(journal_t *journal) { int left = journal->j_free; - /* Be pessimistic here about the number of those free blocks - * which might be required for log descriptor control blocks. */ + assert_spin_locked(&journal->j_state_lock); + + /* + * Be pessimistic here about the number of those free blocks which + * might be required for log descriptor control blocks. + */ #define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ @@ -527,80 +433,92 @@ } /* - * This function must be non-allocating for PF_MEMALLOC tasks + * Called under j_state_lock. Returns true if a transaction was started. */ -tid_t log_start_commit (journal_t *journal, transaction_t *transaction) +int __log_start_commit(journal_t *journal, tid_t target) { - tid_t target = journal->j_commit_request; - - lock_kernel(); /* Protect journal->j_running_transaction */ - - /* - * A NULL transaction asks us to commit the currently running - * transaction, if there is one. - */ - if (transaction) - target = transaction->t_tid; - else { - transaction = journal->j_running_transaction; - if (!transaction) - goto out; - target = transaction->t_tid; - } - /* * Are we already doing a recent enough commit? */ - if (tid_geq(journal->j_commit_request, target)) - goto out; + if (!tid_geq(journal->j_commit_request, target)) { + /* + * We want a new commit: OK, mark the request and wakup the + * commit thread. We do _not_ do the commit ourselves. + */ - /* - * We want a new commit: OK, mark the request and wakup the - * commit thread. We do _not_ do the commit ourselves. - */ + journal->j_commit_request = target; + jbd_debug(1, "JBD: requesting commit %d/%d\n", + journal->j_commit_request, + journal->j_commit_sequence); + wake_up(&journal->j_wait_commit); + return 1; + } + return 0; +} - journal->j_commit_request = target; - jbd_debug(1, "JBD: requesting commit %d/%d\n", - journal->j_commit_request, - journal->j_commit_sequence); - wake_up(&journal->j_wait_commit); +int log_start_commit(journal_t *journal, tid_t tid) +{ + int ret; -out: - unlock_kernel(); - return target; + spin_lock(&journal->j_state_lock); + ret = __log_start_commit(journal, tid); + spin_unlock(&journal->j_state_lock); + return ret; +} + +/* + * Start a commit of the current running transaction (if any). Returns true + * if a transaction was started, and fills its tid in at *ptid + */ +int journal_start_commit(journal_t *journal, tid_t *ptid) +{ + int ret = 0; + + spin_lock(&journal->j_state_lock); + if (journal->j_running_transaction) { + tid_t tid = journal->j_running_transaction->t_tid; + + ret = __log_start_commit(journal, tid); + if (ret && ptid) + *ptid = tid; + } + spin_unlock(&journal->j_state_lock); + return ret; } /* * Wait for a specified commit to complete. * The caller may not hold the journal lock. */ -int log_wait_commit (journal_t *journal, tid_t tid) +int log_wait_commit(journal_t *journal, tid_t tid) { int err = 0; - lock_kernel(); #ifdef CONFIG_JBD_DEBUG - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (!tid_geq(journal->j_commit_request, tid)) { printk(KERN_EMERG "%s: error: j_commit_request=%d, tid=%d\n", __FUNCTION__, journal->j_commit_request, tid); } - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); #endif + spin_lock(&journal->j_state_lock); while (tid_gt(tid, journal->j_commit_sequence)) { jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n", tid, journal->j_commit_sequence); wake_up(&journal->j_wait_commit); - sleep_on(&journal->j_wait_done_commit); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_done_commit, + !tid_gt(tid, journal->j_commit_sequence)); + spin_lock(&journal->j_state_lock); } + spin_unlock(&journal->j_state_lock); if (unlikely(is_journal_aborted(journal))) { printk(KERN_EMERG "journal commit I/O error\n"); err = -EIO; } - - unlock_kernel(); return err; } @@ -612,6 +530,7 @@ { unsigned long blocknr; + spin_lock(&journal->j_state_lock); J_ASSERT(journal->j_free > 1); blocknr = journal->j_head; @@ -619,6 +538,7 @@ journal->j_free--; if (journal->j_head == journal->j_last) journal->j_head = journal->j_first; + spin_unlock(&journal->j_state_lock); return journal_bmap(journal, blocknr, retp); } @@ -706,7 +626,9 @@ init_waitqueue_head(&journal->j_wait_updates); init_MUTEX(&journal->j_barrier); init_MUTEX(&journal->j_checkpoint_sem); - init_MUTEX(&journal->j_sem); + spin_lock_init(&journal->j_revoke_lock); + spin_lock_init(&journal->j_list_lock); + spin_lock_init(&journal->j_state_lock); journal->j_commit_interval = (HZ * 5); @@ -835,7 +757,7 @@ * subsequent use. */ -static int journal_reset (journal_t *journal) +static int journal_reset(journal_t *journal) { journal_superblock_t *sb = journal->j_superblock; unsigned int first, last; @@ -858,11 +780,7 @@ /* Add the dynamic fields and write it to disk. */ journal_update_superblock(journal, 1); - - lock_journal(journal); journal_start_thread(journal); - unlock_journal(journal); - return 0; } @@ -950,12 +868,14 @@ journal_superblock_t *sb = journal->j_superblock; struct buffer_head *bh = journal->j_sb_buffer; + spin_lock(&journal->j_state_lock); jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n", journal->j_tail, journal->j_tail_sequence, journal->j_errno); sb->s_sequence = htonl(journal->j_tail_sequence); sb->s_start = htonl(journal->j_tail); sb->s_errno = htonl(journal->j_errno); + spin_unlock(&journal->j_state_lock); BUFFER_TRACE(bh, "marking dirty"); mark_buffer_dirty(bh); @@ -968,13 +888,14 @@ * any future commit will have to be careful to update the * superblock again to re-record the true start of the log. */ + spin_lock(&journal->j_state_lock); if (sb->s_start) journal->j_flags &= ~JFS_FLUSHED; else journal->j_flags |= JFS_FLUSHED; + spin_unlock(&journal->j_state_lock); } - /* * Read the superblock for a given journal, performing initial * validation of the format. @@ -1116,11 +1037,11 @@ /** * void journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. -* + * * Release a journal_t structure once it is no longer in use by the * journaled object. */ -void journal_destroy (journal_t *journal) +void journal_destroy(journal_t *journal) { /* Wait for the commit thread to wake up and die. */ journal_kill_thread(journal); @@ -1130,13 +1051,19 @@ journal_commit_transaction(journal); /* Force any old transactions to disk */ - lock_journal(journal); - while (journal->j_checkpoint_transactions != NULL) + + /* Totally anal locking here... */ + spin_lock(&journal->j_list_lock); + while (journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); log_do_checkpoint(journal, 1); + spin_lock(&journal->j_list_lock); + } J_ASSERT(journal->j_running_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL); J_ASSERT(journal->j_checkpoint_transactions == NULL); + spin_unlock(&journal->j_list_lock); /* We can now mark the journal as empty. */ journal->j_tail = 0; @@ -1150,8 +1077,6 @@ iput(journal->j_inode); if (journal->j_revoke) journal_destroy_revoke(journal); - - unlock_journal(journal); kfree(journal); } @@ -1310,29 +1235,39 @@ * recovery does not need to happen on remount. */ -int journal_flush (journal_t *journal) +int journal_flush(journal_t *journal) { int err = 0; transaction_t *transaction = NULL; unsigned long old_tail; - lock_kernel(); + spin_lock(&journal->j_state_lock); /* Force everything buffered to the log... */ if (journal->j_running_transaction) { transaction = journal->j_running_transaction; - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); } else if (journal->j_committing_transaction) transaction = journal->j_committing_transaction; /* Wait for the log commit to complete... */ - if (transaction) - log_wait_commit(journal, transaction->t_tid); + if (transaction) { + tid_t tid = transaction->t_tid; + + spin_unlock(&journal->j_state_lock); + log_wait_commit(journal, tid); + } else { + spin_unlock(&journal->j_state_lock); + } /* ...and flush everything in the log out to disk. */ - lock_journal(journal); - while (!err && journal->j_checkpoint_transactions != NULL) + spin_lock(&journal->j_list_lock); + while (!err && journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); err = log_do_checkpoint(journal, journal->j_maxlen); + spin_lock(&journal->j_list_lock); + } + spin_unlock(&journal->j_list_lock); cleanup_journal_tail(journal); /* Finally, mark the journal as really needing no recovery. @@ -1340,21 +1275,20 @@ * the magic code for a fully-recovered superblock. Any future * commits of data to the journal will restore the current * s_start value. */ + spin_lock(&journal->j_state_lock); old_tail = journal->j_tail; journal->j_tail = 0; + spin_unlock(&journal->j_state_lock); journal_update_superblock(journal, 1); + spin_lock(&journal->j_state_lock); journal->j_tail = old_tail; - unlock_journal(journal); - J_ASSERT(!journal->j_running_transaction); J_ASSERT(!journal->j_committing_transaction); J_ASSERT(!journal->j_checkpoint_transactions); J_ASSERT(journal->j_head == journal->j_tail); J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); - - unlock_kernel(); - + spin_unlock(&journal->j_state_lock); return err; } @@ -1371,7 +1305,7 @@ * we merely suppress recovery. */ -int journal_wipe (journal_t *journal, int write) +int journal_wipe(journal_t *journal, int write) { journal_superblock_t *sb; int err = 0; @@ -1423,10 +1357,12 @@ * itself are here. */ -/* Quick version for internal journal use (doesn't lock the journal). +/* + * Quick version for internal journal use (doesn't lock the journal). * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, - * and don't attempt to make any other journal updates. */ -void __journal_abort_hard (journal_t *journal) + * and don't attempt to make any other journal updates. + */ +void __journal_abort_hard(journal_t *journal) { transaction_t *transaction; char b[BDEVNAME_SIZE]; @@ -1434,13 +1370,15 @@ if (journal->j_flags & JFS_ABORT) return; - printk (KERN_ERR "Aborting journal on device %s.\n", + printk(KERN_ERR "Aborting journal on device %s.\n", journal_dev_name(journal, b)); + spin_lock(&journal->j_state_lock); journal->j_flags |= JFS_ABORT; transaction = journal->j_running_transaction; if (transaction) - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); } /* Soft abort: record the abort error status in the journal superblock, @@ -1505,11 +1443,9 @@ * */ -void journal_abort (journal_t *journal, int errno) +void journal_abort(journal_t *journal, int errno) { - lock_journal(journal); __journal_abort_soft(journal, errno); - unlock_journal(journal); } /** @@ -1523,53 +1459,50 @@ * If the journal has been aborted on this mount time -EROFS will * be returned. */ -int journal_errno (journal_t *journal) +int journal_errno(journal_t *journal) { int err; - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_flags & JFS_ABORT) err = -EROFS; else err = journal->j_errno; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); return err; } - - /** * int journal_clear_err () - clears the journal's error state * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -int journal_clear_err (journal_t *journal) +int journal_clear_err(journal_t *journal) { int err = 0; - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_flags & JFS_ABORT) err = -EROFS; else journal->j_errno = 0; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); return err; } - /** * void journal_ack_err() - Ack journal err. * * An error must be cleared or Acked to take a FS out of readonly * mode. */ -void journal_ack_err (journal_t *journal) +void journal_ack_err(journal_t *journal) { - lock_journal(journal); + spin_lock(&journal->j_state_lock); if (journal->j_errno) journal->j_flags |= JFS_ACK_ERR; - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); } int journal_blocks_per_page(struct inode *inode) @@ -1578,26 +1511,6 @@ } /* - * shrink_journal_memory(). - * Called when we're under memory pressure. Free up all the written-back - * checkpointed metadata buffers. - */ -void shrink_journal_memory(void) -{ - struct list_head *list; - - lock_kernel(); - list_for_each(list, &all_journals) { - journal_t *journal = - list_entry(list, journal_t, j_all_journals); - spin_lock(&journal_datalist_lock); - __journal_clean_checkpoint_list(journal); - spin_unlock(&journal_datalist_lock); - } - unlock_kernel(); -} - -/* * Simple support for retying memory allocations. Introduced to help to * debug different VM deadlock avoidance strategies. */ @@ -1703,7 +1616,7 @@ * _before_ attaching the journal_head to a transaction. To protect the * journal_head in this situation, journal_add_journal_head elevates the * journal_head's b_jcount refcount by one. The caller must call - * journal_unlock_journal_head() to undo this. + * journal_put_journal_head() to undo this. * * So the typical usage would be: * @@ -1711,7 +1624,7 @@ * struct journal_head *jh = journal_add_journal_head(bh); * ... * jh->b_transaction = xxx; - * journal_unlock_journal_head(jh); + * journal_put_journal_head(jh); * * Now, the journal_head's b_jcount is zero, but it is safe from being released * because it has a non-zero b_transaction. @@ -1722,70 +1635,70 @@ * * Doesn't need the journal lock. * May sleep. - * Cannot be called with journal_datalist_lock held. */ struct journal_head *journal_add_journal_head(struct buffer_head *bh) { struct journal_head *jh; + struct journal_head *new_jh = NULL; + +repeat: + if (!buffer_jbd(bh)) { + new_jh = journal_alloc_journal_head(); + memset(new_jh, 0, sizeof(*new_jh)); + } - spin_lock(&journal_datalist_lock); + jbd_lock_bh_journal_head(bh); if (buffer_jbd(bh)) { jh = bh2jh(bh); } else { J_ASSERT_BH(bh, (atomic_read(&bh->b_count) > 0) || (bh->b_page && bh->b_page->mapping)); - spin_unlock(&journal_datalist_lock); - jh = journal_alloc_journal_head(); - memset(jh, 0, sizeof(*jh)); - spin_lock(&journal_datalist_lock); - - if (buffer_jbd(bh)) { - /* Someone did it for us! */ - J_ASSERT_BH(bh, bh->b_private != NULL); - journal_free_journal_head(jh); - jh = bh->b_private; - } else { - /* - * We actually don't need jh_splice_lock when - * adding a journal_head - only on removal. - */ - spin_lock(&jh_splice_lock); - set_bit(BH_JBD, &bh->b_state); - bh->b_private = jh; - jh->b_bh = bh; - atomic_inc(&bh->b_count); - spin_unlock(&jh_splice_lock); - BUFFER_TRACE(bh, "added journal_head"); + + if (!new_jh) { + jbd_unlock_bh_journal_head(bh); + goto repeat; } + + jh = new_jh; + new_jh = NULL; /* We consumed it */ + set_buffer_jbd(bh); + bh->b_private = jh; + jh->b_bh = bh; + get_bh(bh); + BUFFER_TRACE(bh, "added journal_head"); } jh->b_jcount++; - spin_unlock(&journal_datalist_lock); + jbd_unlock_bh_journal_head(bh); + if (new_jh) + journal_free_journal_head(new_jh); return bh->b_private; } /* - * journal_remove_journal_head(): if the buffer isn't attached to a transaction - * and has a zero b_jcount then remove and release its journal_head. If we did - * see that the buffer is not used by any transaction we also "logically" - * decrement ->b_count. - * - * We in fact take an additional increment on ->b_count as a convenience, - * because the caller usually wants to do additional things with the bh - * after calling here. - * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some - * time. Once the caller has run __brelse(), the buffer is eligible for - * reaping by try_to_free_buffers(). - * - * Requires journal_datalist_lock. + * Grab a ref against this buffer_head's journal_head. If it ended up not + * having a journal_head, return NULL */ -void __journal_remove_journal_head(struct buffer_head *bh) +struct journal_head *journal_grab_journal_head(struct buffer_head *bh) +{ + struct journal_head *jh = NULL; + + jbd_lock_bh_journal_head(bh); + if (buffer_jbd(bh)) { + jh = bh2jh(bh); + jh->b_jcount++; + } + jbd_unlock_bh_journal_head(bh); + return jh; +} + +static void __journal_remove_journal_head(struct buffer_head *bh) { struct journal_head *jh = bh2jh(bh); - assert_spin_locked(&journal_datalist_lock); J_ASSERT_JH(jh, jh->b_jcount >= 0); - atomic_inc(&bh->b_count); + + get_bh(bh); if (jh->b_jcount == 0) { if (jh->b_transaction == NULL && jh->b_next_transaction == NULL && @@ -1793,12 +1706,10 @@ J_ASSERT_BH(bh, buffer_jbd(bh)); J_ASSERT_BH(bh, jh2bh(jh) == bh); BUFFER_TRACE(bh, "remove journal_head"); - spin_lock(&jh_splice_lock); bh->b_private = NULL; jh->b_bh = NULL; /* debug, really */ - clear_bit(BH_JBD, &bh->b_state); + clear_buffer_jbd(bh); __brelse(bh); - spin_unlock(&jh_splice_lock); journal_free_journal_head(jh); } else { BUFFER_TRACE(bh, "journal_head was locked"); @@ -1806,26 +1717,42 @@ } } -void journal_unlock_journal_head(struct journal_head *jh) +/* + * journal_remove_journal_head(): if the buffer isn't attached to a transaction + * and has a zero b_jcount then remove and release its journal_head. If we did + * see that the buffer is not used by any transaction we also "logically" + * decrement ->b_count. + * + * We in fact take an additional increment on ->b_count as a convenience, + * because the caller usually wants to do additional things with the bh + * after calling here. + * The caller of journal_remove_journal_head() *must* run __brelse(bh) at some + * time. Once the caller has run __brelse(), the buffer is eligible for + * reaping by try_to_free_buffers(). + */ +void journal_remove_journal_head(struct buffer_head *bh) +{ + jbd_lock_bh_journal_head(bh); + __journal_remove_journal_head(bh); + jbd_unlock_bh_journal_head(bh); +} + +/* + * Drop a reference on the passed journal_head. If it fell to zero then try to + * release the journal_head from the buffer_head. + */ +void journal_put_journal_head(struct journal_head *jh) { - spin_lock(&journal_datalist_lock); + struct buffer_head *bh = jh2bh(jh); + + jbd_lock_bh_journal_head(bh); J_ASSERT_JH(jh, jh->b_jcount > 0); --jh->b_jcount; if (!jh->b_jcount && !jh->b_transaction) { - struct buffer_head *bh; - bh = jh2bh(jh); __journal_remove_journal_head(bh); __brelse(bh); } - - spin_unlock(&journal_datalist_lock); -} - -void journal_remove_journal_head(struct buffer_head *bh) -{ - spin_lock(&journal_datalist_lock); - __journal_remove_journal_head(bh); - spin_unlock(&journal_datalist_lock); + jbd_unlock_bh_journal_head(bh); } /* diff -Nru a/fs/jbd/revoke.c b/fs/jbd/revoke.c --- a/fs/jbd/revoke.c Mon Feb 24 10:22:54 2003 +++ b/fs/jbd/revoke.c Tue Jun 17 23:04:08 2003 @@ -129,7 +129,9 @@ record->sequence = seq; record->blocknr = blocknr; hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + spin_lock(&journal->j_revoke_lock); list_add(&record->hash, hash_list); + spin_unlock(&journal->j_revoke_lock); return 0; oom: @@ -150,12 +152,16 @@ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + spin_lock(&journal->j_revoke_lock); record = (struct jbd_revoke_record_s *) hash_list->next; while (&(record->hash) != hash_list) { - if (record->blocknr == blocknr) + if (record->blocknr == blocknr) { + spin_unlock(&journal->j_revoke_lock); return record; + } record = (struct jbd_revoke_record_s *) record->hash.next; } + spin_unlock(&journal->j_revoke_lock); return NULL; } @@ -192,27 +198,29 @@ { int shift, tmp; - J_ASSERT (journal->j_revoke == NULL); + J_ASSERT (journal->j_revoke_table[0] == NULL); - journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); - if (!journal->j_revoke) + shift = 0; + tmp = hash_size; + while((tmp >>= 1UL) != 0UL) + shift++; + + journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[0]) return -ENOMEM; + journal->j_revoke = journal->j_revoke_table[0]; /* Check that the hash_size is a power of two */ J_ASSERT ((hash_size & (hash_size-1)) == 0); journal->j_revoke->hash_size = hash_size; - shift = 0; - tmp = hash_size; - while((tmp >>= 1UL) != 0UL) - shift++; journal->j_revoke->hash_shift = shift; journal->j_revoke->hash_table = kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); if (!journal->j_revoke->hash_table) { - kmem_cache_free(revoke_table_cache, journal->j_revoke); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); journal->j_revoke = NULL; return -ENOMEM; } @@ -220,6 +228,37 @@ for (tmp = 0; tmp < hash_size; tmp++) INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); + if (!journal->j_revoke_table[1]) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + return -ENOMEM; + } + + journal->j_revoke = journal->j_revoke_table[1]; + + /* Check that the hash_size is a power of two */ + J_ASSERT ((hash_size & (hash_size-1)) == 0); + + journal->j_revoke->hash_size = hash_size; + + journal->j_revoke->hash_shift = shift; + + journal->j_revoke->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); + if (!journal->j_revoke->hash_table) { + kfree(journal->j_revoke_table[0]->hash_table); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); + kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); + journal->j_revoke = NULL; + return -ENOMEM; + } + + for (tmp = 0; tmp < hash_size; tmp++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); + + spin_lock_init(&journal->j_revoke_lock); + return 0; } @@ -231,7 +270,20 @@ struct list_head *hash_list; int i; - table = journal->j_revoke; + table = journal->j_revoke_table[0]; + if (!table) + return; + + for (i=0; ihash_size; i++) { + hash_list = &table->hash_table[i]; + J_ASSERT (list_empty(hash_list)); + } + + kfree(table->hash_table); + kmem_cache_free(revoke_table_cache, table); + journal->j_revoke = NULL; + + table = journal->j_revoke_table[1]; if (!table) return; @@ -337,11 +389,9 @@ } } - lock_journal(journal); jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); err = insert_revoke_hash(journal, blocknr, handle->h_transaction->t_tid); - unlock_journal(journal); BUFFER_TRACE(bh_in, "exit"); return err; } @@ -389,7 +439,9 @@ if (record) { jbd_debug(4, "cancelled existing revoke on " "blocknr %llu\n", (u64)bh->b_blocknr); + spin_lock(&journal->j_revoke_lock); list_del(&record->hash); + spin_unlock(&journal->j_revoke_lock); kmem_cache_free(revoke_record_cache, record); did_revoke = 1; } @@ -418,6 +470,22 @@ return did_revoke; } +/* journal_switch_revoke table select j_revoke for next transaction + * we do not want to suspend any processing until all revokes are + * written -bzzz + */ +void journal_switch_revoke_table(journal_t *journal) +{ + int i; + + if (journal->j_revoke == journal->j_revoke_table[0]) + journal->j_revoke = journal->j_revoke_table[1]; + else + journal->j_revoke = journal->j_revoke_table[0]; + + for (i = 0; i < journal->j_revoke->hash_size; i++) + INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); +} /* * Write revoke records to the journal for all entries in the current @@ -438,7 +506,10 @@ descriptor = NULL; offset = 0; count = 0; - revoke = journal->j_revoke; + + /* select revoke table for committing transaction */ + revoke = journal->j_revoke == journal->j_revoke_table[0] ? + journal->j_revoke_table[1] : journal->j_revoke_table[0]; for (i = 0; i < revoke->hash_size; i++) { hash_list = &revoke->hash_table[i]; diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c --- a/fs/jbd/transaction.c Wed Apr 2 22:51:44 2003 +++ b/fs/jbd/transaction.c Tue Jun 17 23:04:26 2003 @@ -27,8 +27,6 @@ #include #include -extern spinlock_t journal_datalist_lock; - /* * get_transaction: obtain a new transaction_t object. * @@ -41,31 +39,26 @@ * The journal MUST be locked. We don't perform atomic mallocs on the * new transaction and we can't block without protecting against other * processes trying to touch the journal while it is in transition. + * + * Called under j_state_lock */ -static transaction_t * get_transaction (journal_t * journal, int is_try) +static transaction_t * +get_transaction(journal_t *journal, transaction_t *transaction) { - transaction_t * transaction; - - transaction = jbd_kmalloc (sizeof (transaction_t), GFP_NOFS); - if (!transaction) - return NULL; - - memset (transaction, 0, sizeof (transaction_t)); - transaction->t_journal = journal; transaction->t_state = T_RUNNING; transaction->t_tid = journal->j_transaction_sequence++; transaction->t_expires = jiffies + journal->j_commit_interval; INIT_LIST_HEAD(&transaction->t_jcb); + spin_lock_init(&transaction->t_handle_lock); + spin_lock_init(&transaction->t_jcb_lock); /* Set up the commit timer for the new transaction. */ - J_ASSERT (!journal->j_commit_timer_active); - journal->j_commit_timer_active = 1; journal->j_commit_timer->expires = transaction->t_expires; add_timer(journal->j_commit_timer); - J_ASSERT (journal->j_running_transaction == NULL); + J_ASSERT(journal->j_running_transaction == NULL); journal->j_running_transaction = transaction; return transaction; @@ -91,69 +84,101 @@ transaction_t *transaction; int needed; int nblocks = handle->h_buffer_credits; + transaction_t *new_transaction = NULL; + int ret; if (nblocks > journal->j_max_transaction_buffers) { printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", current->comm, nblocks, journal->j_max_transaction_buffers); - return -ENOSPC; + ret = -ENOSPC; + goto out; + } + +alloc_transaction: + if (!journal->j_running_transaction) { + new_transaction = jbd_kmalloc(sizeof(*new_transaction), + GFP_NOFS); + if (!new_transaction) { + ret = -ENOMEM; + goto out; + } + memset(new_transaction, 0, sizeof(*new_transaction)); } jbd_debug(3, "New handle %p going live.\n", handle); repeat: - lock_journal(journal); - + /* + * We need to hold j_state_lock until t_updates has been incremented, + * for proper journal barrier handling + */ + spin_lock(&journal->j_state_lock); +repeat_locked: if (is_journal_aborted(journal) || (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { - unlock_journal(journal); - return -EROFS; + spin_unlock(&journal->j_state_lock); + ret = -EROFS; + goto out; } /* Wait on the journal's transaction barrier if necessary */ if (journal->j_barrier_count) { - unlock_journal(journal); - sleep_on(&journal->j_wait_transaction_locked); + spin_unlock(&journal->j_state_lock); + wait_event(journal->j_wait_transaction_locked, + journal->j_barrier_count == 0); goto repeat; } -repeat_locked: - if (!journal->j_running_transaction) - get_transaction(journal, 0); - /* @@@ Error? */ - J_ASSERT(journal->j_running_transaction); - - transaction = journal->j_running_transaction; + if (!journal->j_running_transaction) { + if (!new_transaction) { + spin_unlock(&journal->j_state_lock); + goto alloc_transaction; + } + get_transaction(journal, new_transaction); + new_transaction = NULL; + } - /* If the current transaction is locked down for commit, wait - * for the lock to be released. */ + transaction = journal->j_running_transaction; + /* + * If the current transaction is locked down for commit, wait for the + * lock to be released. + */ if (transaction->t_state == T_LOCKED) { - unlock_journal(journal); + spin_unlock(&journal->j_state_lock); jbd_debug(3, "Handle %p stalling...\n", handle); - sleep_on(&journal->j_wait_transaction_locked); + wait_event(journal->j_wait_transaction_locked, + transaction->t_state != T_LOCKED); goto repeat; } - /* If there is not enough space left in the log to write all - * potential buffers requested by this operation, we need to - * stall pending a log checkpoint to free some more log - * space. */ - + /* + * If there is not enough space left in the log to write all potential + * buffers requested by this operation, we need to stall pending a log + * checkpoint to free some more log space. + */ + spin_lock(&transaction->t_handle_lock); needed = transaction->t_outstanding_credits + nblocks; if (needed > journal->j_max_transaction_buffers) { - /* If the current transaction is already too large, then - * start to commit it: we can then go back and attach - * this handle to a new transaction. */ - + /* + * If the current transaction is already too large, then start + * to commit it: we can then go back and attach this handle to + * a new transaction. + */ + DEFINE_WAIT(wait); + jbd_debug(2, "Handle %p starting new commit...\n", handle); - log_start_commit(journal, transaction); - unlock_journal(journal); - sleep_on(&journal->j_wait_transaction_locked); - lock_journal(journal); - goto repeat_locked; + spin_unlock(&transaction->t_handle_lock); + prepare_to_wait(&journal->j_wait_transaction_locked, &wait, + TASK_UNINTERRUPTIBLE); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_transaction_locked, &wait); + goto repeat; } /* @@ -186,9 +211,10 @@ needed += journal->j_committing_transaction-> t_outstanding_credits; - if (log_space_left(journal) < needed) { + if (__log_space_left(journal) < needed) { jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); - log_wait_for_space(journal, needed); + spin_unlock(&transaction->t_handle_lock); + __log_wait_for_space(journal, needed); goto repeat_locked; } @@ -201,10 +227,12 @@ transaction->t_handle_count++; jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", handle, nblocks, transaction->t_outstanding_credits, - log_space_left(journal)); - - unlock_journal(journal); - + __log_space_left(journal)); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); +out: + if (new_transaction) + kfree(new_transaction); return 0; } @@ -260,9 +288,8 @@ if (err < 0) { jbd_free_handle(handle); current->journal_info = NULL; - return ERR_PTR(err); + handle = ERR_PTR(err); } - return handle; } @@ -286,40 +313,41 @@ * return code < 0 implies an error * return code > 0 implies normal transaction-full status. */ -int journal_extend (handle_t *handle, int nblocks) +int journal_extend(handle_t *handle, int nblocks) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int result; int wanted; - lock_journal (journal); - result = -EIO; if (is_handle_aborted(handle)) goto error_out; result = 1; - + + spin_lock(&journal->j_state_lock); + /* Don't extend a locked-down transaction! */ if (handle->h_transaction->t_state != T_RUNNING) { jbd_debug(3, "denied handle %p %d blocks: " "transaction not running\n", handle, nblocks); goto error_out; } - + + spin_lock(&transaction->t_handle_lock); wanted = transaction->t_outstanding_credits + nblocks; if (wanted > journal->j_max_transaction_buffers) { jbd_debug(3, "denied handle %p %d blocks: " "transaction too large\n", handle, nblocks); - goto error_out; + goto unlock; } - if (wanted > log_space_left(journal)) { + if (wanted > __log_space_left(journal)) { jbd_debug(3, "denied handle %p %d blocks: " "insufficient log space\n", handle, nblocks); - goto error_out; + goto unlock; } handle->h_buffer_credits += nblocks; @@ -327,9 +355,10 @@ result = 0; jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); - +unlock: + spin_unlock(&transaction->t_handle_lock); error_out: - unlock_journal (journal); + spin_unlock(&journal->j_state_lock); return result; } @@ -360,20 +389,25 @@ if (is_handle_aborted(handle)) return 0; - /* First unlink the handle from its current transaction, and - * start the commit on that. */ - - J_ASSERT (transaction->t_updates > 0); - J_ASSERT (journal_current_handle() == handle); + /* + * First unlink the handle from its current transaction, and start the + * commit on that. + */ + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) wake_up(&journal->j_wait_updates); + spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "restarting handle %p\n", handle); - log_start_commit(journal, transaction); + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); handle->h_buffer_credits = nblocks; ret = start_this_handle(journal, handle); @@ -391,30 +425,41 @@ * * The journal lock should not be held on entry. */ -void journal_lock_updates (journal_t *journal) +void journal_lock_updates(journal_t *journal) { - lock_journal(journal); + DEFINE_WAIT(wait); + + spin_lock(&journal->j_state_lock); ++journal->j_barrier_count; /* Wait until there are no running updates */ while (1) { transaction_t *transaction = journal->j_running_transaction; + if (!transaction) break; - if (!transaction->t_updates) + + spin_lock(&transaction->t_handle_lock); + if (!transaction->t_updates) { + spin_unlock(&transaction->t_handle_lock); break; - - unlock_journal(journal); - sleep_on(&journal->j_wait_updates); - lock_journal(journal); + } + prepare_to_wait(&journal->j_wait_updates, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); + schedule(); + finish_wait(&journal->j_wait_updates, &wait); + spin_lock(&journal->j_state_lock); } + spin_unlock(&journal->j_state_lock); - unlock_journal(journal); - - /* We have now established a barrier against other normal - * updates, but we also need to barrier against other - * journal_lock_updates() calls to make sure that we serialise - * special journal-locked operations too. */ + /* + * We have now established a barrier against other normal updates, but + * we also need to barrier against other journal_lock_updates() calls + * to make sure that we serialise special journal-locked operations + * too. + */ down(&journal->j_barrier); } @@ -428,14 +473,13 @@ */ void journal_unlock_updates (journal_t *journal) { - lock_journal(journal); + J_ASSERT(journal->j_barrier_count != 0); - J_ASSERT (journal->j_barrier_count != 0); - up(&journal->j_barrier); + spin_lock(&journal->j_state_lock); --journal->j_barrier_count; + spin_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_transaction_locked); - unlock_journal(journal); } /* @@ -445,7 +489,7 @@ * continuing as gracefully as possible. # * * The caller should already hold the journal lock and - * journal_datalist_lock spinlock: most callers will need those anyway + * j_list_lock spinlock: most callers will need those anyway * in order to probe the buffer's journaling state safely. */ static void jbd_unexpected_dirty_buffer(struct journal_head *jh) @@ -482,7 +526,8 @@ */ static int -do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) +do_get_write_access(handle_t *handle, struct journal_head *jh, + int force_copy, int *credits) { struct buffer_head *bh; transaction_t *transaction = handle->h_transaction; @@ -490,7 +535,6 @@ int error; char *frozen_buffer = NULL; int need_copy = 0; - int locked; jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy); @@ -500,16 +544,9 @@ /* @@@ Need to check for errors here at some point. */ - locked = test_set_buffer_locked(bh); - if (locked) { - /* We can't reliably test the buffer state if we found - * it already locked, so just wait for the lock and - * retry. */ - unlock_journal(journal); - wait_on_buffer(bh); - lock_journal(journal); - goto repeat; - } + lock_buffer(bh); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); /* We now hold the buffer lock so it is safe to query the buffer * state. Is the buffer dirty? @@ -525,7 +562,6 @@ * the buffer dirtied, ugh.) */ if (buffer_dirty(bh)) { - spin_lock(&journal_datalist_lock); /* First question: is this buffer already part of the * current transaction or the existing committing * transaction? */ @@ -540,18 +576,18 @@ JBUFFER_TRACE(jh, "Unexpected dirty buffer"); jbd_unexpected_dirty_buffer(jh); } - spin_unlock(&journal_datalist_lock); } unlock_buffer(bh); error = -EROFS; - if (is_handle_aborted(handle)) + if (is_handle_aborted(handle)) { + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); goto out_unlocked; + } error = 0; - spin_lock(&journal_datalist_lock); - /* The buffer is already part of this transaction if * b_transaction or b_next_transaction points to it. */ @@ -569,6 +605,8 @@ J_ASSERT_JH(jh, handle->h_buffer_credits > 0); handle->h_buffer_credits--; + if (credits) + (*credits)++; goto done_locked; } @@ -593,12 +631,11 @@ wait_queue_head_t *wqh; JBUFFER_TRACE(jh, "on shadow: sleep"); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); /* commit wakes up all shadow buffers after IO */ wqh = bh_waitq_head(jh2bh(jh)); wait_event(*wqh, (jh->b_jlist != BJ_Shadow)); - lock_journal(journal); goto repeat; } @@ -620,18 +657,18 @@ JBUFFER_TRACE(jh, "generate frozen data"); if (!frozen_buffer) { JBUFFER_TRACE(jh, "allocate memory for buffer"); - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); frozen_buffer = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS); - lock_journal(journal); if (!frozen_buffer) { printk(KERN_EMERG "%s: OOM for frozen_buffer\n", __FUNCTION__); JBUFFER_TRACE(jh, "oom!"); error = -ENOMEM; - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); goto done_locked; } goto repeat; @@ -646,6 +683,8 @@ J_ASSERT(handle->h_buffer_credits > 0); handle->h_buffer_credits--; + if (credits) + (*credits)++; /* Finally, if the buffer is not journaled right now, we need to * make sure it doesn't get written to disk before the caller @@ -660,7 +699,7 @@ } done_locked: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); if (need_copy) { struct page *page; int offset; @@ -670,11 +709,11 @@ "Possible IO failure.\n"); page = jh2bh(jh)->b_page; offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK; - source = kmap(page); + source = kmap_atomic(page, KM_USER0); memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); - kunmap(page); + kunmap_atomic(source, KM_USER0); } - + jbd_unlock_bh_state(bh); /* If we are about to journal a buffer, then any revoke pending on it is no longer valid. */ @@ -699,20 +738,17 @@ * because we're write()ing a buffer which is also part of a shared mapping. */ -int journal_get_write_access (handle_t *handle, struct buffer_head *bh) +int journal_get_write_access(handle_t *handle, + struct buffer_head *bh, int *credits) { - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; struct journal_head *jh = journal_add_journal_head(bh); int rc; /* We do not want to get caught playing with fields which the * log thread also manipulates. Make sure that the buffer * completes any outstanding IO before proceeding. */ - lock_journal(journal); - rc = do_get_write_access(handle, jh, 0); - journal_unlock_journal_head(jh); - unlock_journal(journal); + rc = do_get_write_access(handle, jh, 0, NULL); + journal_put_journal_head(jh); return rc; } @@ -736,7 +772,7 @@ * * Call this if you create a new bh. */ -int journal_get_create_access (handle_t *handle, struct buffer_head *bh) +int journal_get_create_access(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -744,21 +780,24 @@ int err; jbd_debug(5, "journal_head %p\n", jh); - lock_journal(journal); err = -EROFS; if (is_handle_aborted(handle)) goto out; err = 0; JBUFFER_TRACE(jh, "entry"); - /* The buffer may already belong to this transaction due to - * pre-zeroing in the filesystem's new_block code. It may also - * be on the previous, committing transaction's lists, but it - * HAS to be in Forget state in that case: the transaction must - * have deleted the buffer for it to be reused here. */ + /* + * The buffer may already belong to this transaction due to pre-zeroing + * in the filesystem's new_block code. It may also be on the previous, + * committing transaction's lists, but it HAS to be in Forget state in + * that case: the transaction must have deleted the buffer for it to be + * reused here. + */ + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && + jh->b_transaction == NULL || + (jh->b_transaction == journal->j_committing_transaction && jh->b_jlist == BJ_Forget))); J_ASSERT_JH(jh, jh->b_next_transaction == NULL); @@ -767,7 +806,6 @@ J_ASSERT_JH(jh, handle->h_buffer_credits > 0); handle->h_buffer_credits--; - spin_lock(&journal_datalist_lock); if (jh->b_transaction == NULL) { jh->b_transaction = transaction; JBUFFER_TRACE(jh, "file as BJ_Reserved"); @@ -776,7 +814,8 @@ JBUFFER_TRACE(jh, "set next transaction"); jh->b_next_transaction = transaction; } - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); /* * akpm: I added this. ext3_alloc_branch can pick up new indirect @@ -787,19 +826,18 @@ */ JBUFFER_TRACE(jh, "cancelling revoke"); journal_cancel_revoke(handle, jh); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); out: - unlock_journal(journal); return err; } - - /** - * int journal_get_undo_access() - Notify intent to modify metadata with non-rewindable consequences + * int journal_get_undo_access() - Notify intent to modify metadata with + * non-rewindable consequences * @handle: transaction * @bh: buffer to undo - * + * @credits: store the number of taken credits here (if not NULL) + * * Sometimes there is a need to distinguish between metadata which has * been committed to disk and that which has not. The ext3fs code uses * this for freeing and allocating space, we have to make sure that we @@ -818,47 +856,56 @@ * will be committed to a new transaction in due course, at which point * we can discard the old committed data pointer. * - * Returns error number or 0 on success. + * Returns error number or 0 on success. */ -int journal_get_undo_access (handle_t *handle, struct buffer_head *bh) +int journal_get_undo_access(handle_t *handle, struct buffer_head *bh, + int *credits) { - journal_t *journal = handle->h_transaction->t_journal; int err; struct journal_head *jh = journal_add_journal_head(bh); + char *committed_data = NULL; JBUFFER_TRACE(jh, "entry"); - lock_journal(journal); - /* Do this first --- it can drop the journal lock, so we want to + /* + * Do this first --- it can drop the journal lock, so we want to * make sure that obtaining the committed_data is done - * atomically wrt. completion of any outstanding commits. */ - err = do_get_write_access (handle, jh, 1); + * atomically wrt. completion of any outstanding commits. + */ + err = do_get_write_access(handle, jh, 1, credits); if (err) goto out; - + +repeat: if (!jh->b_committed_data) { - /* Copy out the current buffer contents into the - * preserved, committed copy. */ - JBUFFER_TRACE(jh, "generate b_committed data"); - jh->b_committed_data = jbd_kmalloc(jh2bh(jh)->b_size, - GFP_NOFS); - if (!jh->b_committed_data) { - printk(KERN_EMERG - "%s: No memory for committed data!\n", - __FUNCTION__); + committed_data = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS); + if (!committed_data) { + printk(KERN_EMERG "%s: No memory for committed data\n", + __FUNCTION__); err = -ENOMEM; goto out; } - - memcpy (jh->b_committed_data, jh2bh(jh)->b_data, - jh2bh(jh)->b_size); } + jbd_lock_bh_state(bh); + if (!jh->b_committed_data) { + /* Copy out the current buffer contents into the + * preserved, committed copy. */ + JBUFFER_TRACE(jh, "generate b_committed data"); + if (!committed_data) { + jbd_unlock_bh_state(bh); + goto repeat; + } + + jh->b_committed_data = committed_data; + committed_data = NULL; + memcpy(jh->b_committed_data, bh->b_data, bh->b_size); + } + jbd_unlock_bh_state(bh); out: - if (!err) - J_ASSERT_JH(jh, jh->b_committed_data); - journal_unlock_journal_head(jh); - unlock_journal(journal); + journal_put_journal_head(jh); + if (committed_data) + kfree(committed_data); return err; } @@ -875,10 +922,9 @@ * Returns error number or 0 on success. * * journal_dirty_data() can be called via page_launder->ext3_writepage - * by kswapd. So it cannot block. Happily, there's nothing here - * which needs lock_journal if `async' is set. + * by kswapd. */ -int journal_dirty_data (handle_t *handle, struct buffer_head *bh) +int journal_dirty_data(handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; int need_brelse = 0; @@ -917,7 +963,8 @@ * never, ever allow this to happen: there's nothing we can do * about it in this layer. */ - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (jh->b_transaction) { JBUFFER_TRACE(jh, "has transaction"); if (jh->b_transaction != handle->h_transaction) { @@ -971,11 +1018,13 @@ * commit to never terminate. */ if (buffer_dirty(bh)) { - atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); + get_bh(bh); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); need_brelse = 1; sync_dirty_buffer(bh); - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); /* The buffer may become locked again at any time if it is redirtied */ } @@ -1009,13 +1058,14 @@ __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); } no_journal: - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); if (need_brelse) { BUFFER_TRACE(bh, "brelse"); __brelse(bh); } JBUFFER_TRACE(jh, "exit"); - journal_unlock_journal_head(jh); + journal_put_journal_head(jh); return 0; } @@ -1038,7 +1088,7 @@ * buffer: that only gets done when the old transaction finally * completes its commit. */ -int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh) +int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1046,12 +1096,38 @@ jbd_debug(5, "journal_head %p\n", jh); JBUFFER_TRACE(jh, "entry"); - lock_journal(journal); if (is_handle_aborted(handle)) - goto out_unlock; + goto out; - spin_lock(&journal_datalist_lock); - set_bit(BH_JBDDirty, &bh->b_state); + jbd_lock_bh_state(bh); + + /* + * fastpath, to avoid expensive locking. If this buffer is already + * on the running transaction's metadata list there is nothing to do. + * Nobody can take it off again because there is a handle open. + * I _think_ we're OK here with SMP barriers - a mistaken decision will + * result in this test being false, so we go in and take the locks. + */ + if (jh->b_transaction == handle->h_transaction && + jh->b_jlist == BJ_Metadata) { + JBUFFER_TRACE(jh, "fastpath"); + console_verbose(); + if (jh->b_transaction != journal->j_running_transaction) { + printk("jh->b_transaction=%p\n", jh->b_transaction); + printk("journal->j_running_transaction=%p\n", + journal->j_running_transaction); + printk("handle->h_transaction=%p\n", + handle->h_transaction); + printk("journal->j_committing_transaction=%p\n", + journal->j_committing_transaction); + } + J_ASSERT_JH(jh, jh->b_transaction == + journal->j_running_transaction); + goto out_unlock_bh; + } + + spin_lock(&journal->j_list_lock); + set_buffer_jbddirty(bh); J_ASSERT_JH(jh, jh->b_transaction != NULL); @@ -1070,8 +1146,7 @@ /* And this case is illegal: we can't reuse another * transaction's data buffer, ever. */ /* FIXME: writepage() should be journalled */ - J_ASSERT_JH(jh, jh->b_jlist != BJ_SyncData); - goto done_locked; + goto out_unlock_list; } /* That test should have eliminated the following case: */ @@ -1080,49 +1155,51 @@ JBUFFER_TRACE(jh, "file as BJ_Metadata"); __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); -done_locked: - spin_unlock(&journal_datalist_lock); +out_unlock_list: + spin_unlock(&journal->j_list_lock); +out_unlock_bh: + jbd_unlock_bh_state(bh); +out: JBUFFER_TRACE(jh, "exit"); -out_unlock: - unlock_journal(journal); return 0; } -#if 0 /* * journal_release_buffer: undo a get_write_access without any buffer * updates, if the update decided in the end that it didn't need access. * * journal_get_write_access() can block, so it is quite possible for a * journaling component to decide after the write access is returned - * that global state has changed and the update is no longer required. */ - -void journal_release_buffer (handle_t *handle, struct buffer_head *bh) + * that global state has changed and the update is no longer required. + * + * The caller passes in the number of credits which should be put back for + * this buffer (zero or one). + */ +void +journal_release_buffer(handle_t *handle, struct buffer_head *bh, int credits) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; struct journal_head *jh = bh2jh(bh); - lock_journal(journal); JBUFFER_TRACE(jh, "entry"); /* If the buffer is reserved but not modified by this * transaction, then it is safe to release it. In all other * cases, just leave the buffer as it is. */ - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (jh->b_jlist == BJ_Reserved && jh->b_transaction == transaction && - !buffer_jdirty(jh2bh(jh))) { + !buffer_jbddirty(jh2bh(jh))) { JBUFFER_TRACE(jh, "unused: refiling it"); - handle->h_buffer_credits++; __journal_refile_buffer(jh); } - spin_unlock(&journal_datalist_lock); - + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + handle->h_buffer_credits += credits; JBUFFER_TRACE(jh, "exit"); - unlock_journal(journal); } -#endif /** * void journal_forget() - bforget() for potentially-journaled buffers. @@ -1141,7 +1218,7 @@ * Allow this call even if the handle has aborted --- it may be part of * the caller's cleanup after an abort. */ -void journal_forget (handle_t *handle, struct buffer_head *bh) +void journal_forget(handle_t *handle, struct buffer_head *bh) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; @@ -1149,8 +1226,8 @@ BUFFER_TRACE(bh, "entry"); - lock_journal(journal); - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); if (!buffer_jbd(bh)) goto not_jbd; @@ -1163,7 +1240,7 @@ * of this transaction, then we can just drop it from * the transaction immediately. */ clear_buffer_dirty(bh); - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); J_ASSERT_JH(jh, !jh->b_committed_data); @@ -1186,11 +1263,11 @@ if (jh->b_cp_transaction) { __journal_file_buffer(jh, transaction, BJ_Forget); } else { - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); if (!buffer_jbd(bh)) { - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); __bforget(bh); return; } @@ -1212,72 +1289,12 @@ } not_jbd: - spin_unlock(&journal_datalist_lock); - unlock_journal(journal); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); __brelse(bh); return; } -#if 0 /* Unused */ -/* - * journal_sync_buffer: flush a potentially-journaled buffer to disk. - * - * Used for O_SYNC filesystem operations. If the buffer is journaled, - * we need to complete the O_SYNC by waiting for the transaction to - * complete. It is an error to call journal_sync_buffer before - * journal_stop! - */ - -void journal_sync_buffer(struct buffer_head *bh) -{ - transaction_t *transaction; - journal_t *journal; - long sequence; - struct journal_head *jh; - - /* If the buffer isn't journaled, this is easy: just sync it to - * disk. */ - BUFFER_TRACE(bh, "entry"); - - spin_lock(&journal_datalist_lock); - if (!buffer_jbd(bh)) { - spin_unlock(&journal_datalist_lock); - return; - } - jh = bh2jh(bh); - if (jh->b_transaction == NULL) { - /* If the buffer has already been journaled, then this - * is a noop. */ - if (jh->b_cp_transaction == NULL) { - spin_unlock(&journal_datalist_lock); - return; - } - atomic_inc(&bh->b_count); - spin_unlock(&journal_datalist_lock); - sync_dirty_buffer(bh); - __brelse(bh); - goto out; - } - - /* Otherwise, just wait until the transaction is synced to disk. */ - transaction = jh->b_transaction; - journal = transaction->t_journal; - sequence = transaction->t_tid; - spin_unlock(&journal_datalist_lock); - - jbd_debug(2, "requesting commit for jh %p\n", jh); - log_start_commit (journal, transaction); - - while (tid_gt(sequence, journal->j_commit_sequence)) { - wake_up(&journal->j_wait_done_commit); - sleep_on(&journal->j_wait_done_commit); - } - JBUFFER_TRACE(jh, "exit"); -out: - return; -} -#endif - /** * void journal_callback_set() - Register a callback function for this handle. * @handle: handle to attach the callback to. @@ -1299,14 +1316,15 @@ * and has the caller-specific data afterwards. */ void journal_callback_set(handle_t *handle, - void (*func)(struct journal_callback *jcb, int error), - struct journal_callback *jcb) + void (*func)(struct journal_callback *jcb, int error), + struct journal_callback *jcb) { + spin_lock(&handle->h_transaction->t_jcb_lock); list_add_tail(&jcb->jcb_list, &handle->h_jcb); + spin_unlock(&handle->h_transaction->t_jcb_lock); jcb->jcb_func = func; } - /** * int journal_stop() - complete a transaction * @handle: tranaction to complete. @@ -1332,8 +1350,8 @@ if (!handle) return 0; - J_ASSERT (transaction->t_updates > 0); - J_ASSERT (journal_current_handle() == handle); + J_ASSERT(transaction->t_updates > 0); + J_ASSERT(journal_current_handle() == handle); if (is_handle_aborted(handle)) err = -EIO; @@ -1366,6 +1384,8 @@ } current->journal_info = NULL; + spin_lock(&journal->j_state_lock); + spin_lock(&transaction->t_handle_lock); transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) { @@ -1375,7 +1395,9 @@ } /* Move callbacks from the handle to the transaction. */ + spin_lock(&transaction->t_jcb_lock); list_splice(&handle->h_jcb, &transaction->t_jcb); + spin_unlock(&transaction->t_jcb_lock); /* * If the handle is marked SYNC, we need to set another commit @@ -1392,18 +1414,24 @@ * anything to disk. */ tid_t tid = transaction->t_tid; + spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "transaction too old, requesting commit for " "handle %p\n", handle); /* This is non-blocking */ - log_start_commit(journal, transaction); - + __log_start_commit(journal, transaction->t_tid); + spin_unlock(&journal->j_state_lock); + /* * Special case: JFS_SYNC synchronous updates require us * to wait for the commit to complete. */ if (handle->h_sync && !(current->flags & PF_MEMALLOC)) err = log_wait_commit(journal, tid); + } else { + spin_unlock(&transaction->t_handle_lock); + spin_unlock(&journal->j_state_lock); } + jbd_free_handle(handle); return err; } @@ -1420,16 +1448,13 @@ handle_t *handle; int ret; - lock_kernel(); handle = journal_start(journal, 1); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out; + } else { + handle->h_sync = 1; + ret = journal_stop(handle); } - handle->h_sync = 1; - ret = journal_stop(handle); -out: - unlock_kernel(); return ret; } @@ -1443,7 +1468,10 @@ /* * Append a buffer to a transaction list, given the transaction's list head * pointer. - * journal_datalist_lock is held. + * + * j_list_lock is held. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. */ static inline void @@ -1465,8 +1493,9 @@ * Remove a buffer from a transaction list, given the transaction's list * head pointer. * - * Called with journal_datalist_lock held, and the journal may not - * be locked. + * Called with j_list_lock held, and the journal may not be locked. + * + * jbd_lock_bh_state(jh2bh(jh)) is held. */ static inline void @@ -1490,23 +1519,20 @@ * is holding onto a copy of one of thee pointers, it could go bad. * Generally the caller needs to re-read the pointer from the transaction_t. * - * If bh->b_jlist is BJ_SyncData then we may have been called - * via journal_try_to_free_buffer() or journal_clean_data_list(). In that - * case, journal_datalist_lock will be held, and the journal may not be locked. + * Called under j_list_lock. The journal may not be locked. */ void __journal_unfile_buffer(struct journal_head *jh) { struct journal_head **list = 0; - transaction_t * transaction; + transaction_t *transaction; + struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); transaction = jh->b_transaction; + if (transaction) + assert_spin_locked(&transaction->t_journal->j_list_lock); -#ifdef __SMP__ - J_ASSERT (current->lock_depth >= 0); -#endif J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - if (jh->b_jlist != BJ_None) J_ASSERT_JH(jh, transaction != 0); @@ -1540,38 +1566,29 @@ __blist_del_buffer(list, jh); jh->b_jlist = BJ_None; - if (test_and_clear_bit(BH_JBDDirty, &jh2bh(jh)->b_state)) - mark_buffer_dirty(jh2bh(jh)); /* Expose it to the VM */ + if (test_clear_buffer_jbddirty(bh)) + mark_buffer_dirty(bh); /* Expose it to the VM */ } -void journal_unfile_buffer(struct journal_head *jh) +void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) { - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&journal->j_list_lock); __journal_unfile_buffer(jh); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); } /* - * Called from journal_try_to_free_buffers(). The journal is not - * locked. lru_list_lock is not held. - * - * Here we see why journal_datalist_lock is global and not per-journal. - * We cannot get back to this buffer's journal pointer without locking - * out journal_clean_data_list() in some manner. + * Called from journal_try_to_free_buffers(). * - * One could use journal_datalist_lock to get unracy access to a - * per-journal lock. - * - * Called with journal_datalist_lock held. - * - * Returns non-zero iff we were able to free the journal_head. + * Called under jbd_lock_bh_state(bh) */ -static inline int __journal_try_to_free_buffer(struct buffer_head *bh) +static void +__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) { struct journal_head *jh; - assert_spin_locked(&journal_datalist_lock); - jh = bh2jh(bh); if (buffer_locked(bh) || buffer_dirty(bh)) @@ -1580,13 +1597,14 @@ if (jh->b_next_transaction != 0) goto out; + spin_lock(&journal->j_list_lock); if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) { if (jh->b_jlist == BJ_SyncData) { /* A written-back ordered data buffer */ JBUFFER_TRACE(jh, "release data"); __journal_unfile_buffer(jh); jh->b_transaction = 0; - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) { @@ -1594,14 +1612,13 @@ if (jh->b_jlist == BJ_None) { JBUFFER_TRACE(jh, "remove from checkpoint list"); __journal_remove_checkpoint(jh); - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } } - return !buffer_jbd(bh); - + spin_unlock(&journal->j_list_lock); out: - return 0; + return; } @@ -1650,14 +1667,25 @@ head = page_buffers(page); bh = head; - spin_lock(&journal_datalist_lock); do { - if (buffer_jbd(bh) && !__journal_try_to_free_buffer(bh)) { - spin_unlock(&journal_datalist_lock); + struct journal_head *jh; + + /* + * We take our own ref against the journal_head here to avoid + * having to add tons of locking around each instance of + * journal_remove_journal_head() and journal_put_journal_head(). + */ + jh = journal_grab_journal_head(bh); + if (!jh) + continue; + + jbd_lock_bh_state(bh); + __journal_try_to_free_buffer(journal, bh); + journal_put_journal_head(jh); + jbd_unlock_bh_state(bh); + if (buffer_jbd(bh)) goto busy; - } } while ((bh = bh->b_this_page) != head); - spin_unlock(&journal_datalist_lock); ret = try_to_free_buffers(page); busy: return ret; @@ -1670,28 +1698,29 @@ * this transaction commits. If the buffer isn't on a checkpoint list, we * release it. * Returns non-zero if JBD no longer has an interest in the buffer. + * + * Called under j_list_lock. + * + * Called under jbd_lock_bh_state(bh). */ -static int dispose_buffer(struct journal_head *jh, - transaction_t *transaction) +static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) { int may_free = 1; struct buffer_head *bh = jh2bh(jh); - spin_lock(&journal_datalist_lock); __journal_unfile_buffer(jh); jh->b_transaction = 0; if (jh->b_cp_transaction) { JBUFFER_TRACE(jh, "on running+cp transaction"); __journal_file_buffer(jh, transaction, BJ_Forget); - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); may_free = 0; } else { JBUFFER_TRACE(jh, "on running transaction"); - __journal_remove_journal_head(bh); + journal_remove_journal_head(bh); __brelse(bh); } - spin_unlock(&journal_datalist_lock); return may_free; } @@ -1747,14 +1776,27 @@ transaction_t *transaction; struct journal_head *jh; int may_free = 1; + int ret; BUFFER_TRACE(bh, "entry"); - /* It is safe to proceed here without the - * journal_datalist_spinlock because the buffers cannot be - * stolen by try_to_free_buffers as long as we are holding the - * page lock. --sct */ + /* + * It is safe to proceed here without the j_list_lock because the + * buffers cannot be stolen by try_to_free_buffers as long as we are + * holding the page lock. --sct + */ + + if (!buffer_jbd(bh)) + goto zap_buffer_unlocked; + + spin_lock(&journal->j_state_lock); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); + /* + * Now we have the locks, check again to see whether kjournald has + * taken the buffer off the transaction. + */ if (!buffer_jbd(bh)) goto zap_buffer; @@ -1784,8 +1826,12 @@ * committed, the buffer won't be needed any * longer. */ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - return dispose_buffer(jh, + ret = __dispose_buffer(jh, journal->j_running_transaction); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; } else { /* There is no currently-running transaction. So the * orphan record which we wrote for this file must have @@ -1793,12 +1839,16 @@ * the committing transaction, if it exists. */ if (journal->j_committing_transaction) { JBUFFER_TRACE(jh, "give to committing trans"); - return dispose_buffer(jh, + ret = __dispose_buffer(jh, journal->j_committing_transaction); + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); + return ret; } else { /* The orphan record's transaction has * committed. We can cleanse this buffer */ - clear_bit(BH_JBDDirty, &bh->b_state); + clear_buffer_jbddirty(bh); goto zap_buffer; } } @@ -1814,6 +1864,9 @@ journal->j_running_transaction); jh->b_next_transaction = NULL; } + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); return 0; } else { /* Good, the buffer belongs to the running transaction. @@ -1823,12 +1876,16 @@ * i_size already for this truncate so recovery will not * expose the disk blocks we are discarding here.) */ J_ASSERT_JH(jh, transaction == journal->j_running_transaction); - may_free = dispose_buffer(jh, transaction); + may_free = __dispose_buffer(jh, transaction); } -zap_buffer: +zap_buffer: + spin_unlock(&journal->j_list_lock); + jbd_unlock_bh_state(bh); + spin_unlock(&journal->j_state_lock); +zap_buffer_unlocked: clear_buffer_dirty(bh); - J_ASSERT_BH(bh, !buffer_jdirty(bh)); + J_ASSERT_BH(bh, !buffer_jbddirty(bh)); clear_buffer_mapped(bh); clear_buffer_req(bh); clear_buffer_new(bh); @@ -1862,7 +1919,6 @@ /* We will potentially be playing with lists other than just the * data lists (especially for journaled data mode), so be * cautious in our locking. */ - lock_journal(journal); head = bh = page_buffers(page); do { @@ -1881,8 +1937,6 @@ } while (bh != head); - unlock_journal(journal); - if (!offset) { if (!may_free || !try_to_free_buffers(page)) return 0; @@ -1901,8 +1955,9 @@ int was_dirty = 0; struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); - + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + assert_spin_locked(&transaction->t_journal->j_list_lock); + #ifdef __SMP__ J_ASSERT (current->lock_depth >= 0); #endif @@ -1968,9 +2023,11 @@ void journal_file_buffer(struct journal_head *jh, transaction_t *transaction, int jlist) { - spin_lock(&journal_datalist_lock); + jbd_lock_bh_state(jh2bh(jh)); + spin_lock(&transaction->t_journal->j_list_lock); __journal_file_buffer(jh, transaction, jlist); - spin_unlock(&journal_datalist_lock); + spin_unlock(&transaction->t_journal->j_list_lock); + jbd_unlock_bh_state(jh2bh(jh)); } /* @@ -1978,14 +2035,19 @@ * dropping it from its current transaction entirely. If the buffer has * already started to be used by a subsequent transaction, refile the * buffer on that transaction's metadata list. + * + * Called under journal->j_list_lock + * + * Called under jbd_lock_bh_state(jh2bh(jh)) */ - void __journal_refile_buffer(struct journal_head *jh) { int was_dirty; + struct buffer_head *bh = jh2bh(jh); - assert_spin_locked(&journal_datalist_lock); - J_ASSERT_JH(jh, kernel_locked()); + J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); + if (jh->b_transaction) + assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock); /* If the buffer is now unused, just drop it. */ if (jh->b_next_transaction == NULL) { @@ -1994,10 +2056,12 @@ return; } - /* It has been modified by a later transaction: add it to the - * new transaction's metadata list. */ + /* + * It has been modified by a later transaction: add it to the new + * transaction's metadata list. + */ - was_dirty = test_clear_buffer_jbddirty(jh2bh(jh)); + was_dirty = test_clear_buffer_jbddirty(bh); __journal_unfile_buffer(jh); jh->b_transaction = jh->b_next_transaction; jh->b_next_transaction = NULL; @@ -2005,7 +2069,7 @@ J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); if (was_dirty) - set_buffer_jbddirty(jh2bh(jh)); + set_buffer_jbddirty(bh); } /* @@ -2022,16 +2086,17 @@ * * *** The journal_head may be freed by this call! *** */ -void journal_refile_buffer(struct journal_head *jh) +void journal_refile_buffer(journal_t *journal, struct journal_head *jh) { - struct buffer_head *bh; + struct buffer_head *bh = jh2bh(jh); - spin_lock(&journal_datalist_lock); - bh = jh2bh(jh); + jbd_lock_bh_state(bh); + spin_lock(&journal->j_list_lock); __journal_refile_buffer(jh); - __journal_remove_journal_head(bh); + jbd_unlock_bh_state(bh); + journal_remove_journal_head(bh); - spin_unlock(&journal_datalist_lock); + spin_unlock(&journal->j_list_lock); __brelse(bh); } diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Thu Jun 12 15:51:27 2003 +++ b/fs/namei.c Mon Jun 16 22:09:04 2003 @@ -985,6 +985,8 @@ * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. * 9. We can't remove a root or mountpoint. + * 10. We don't allow removal of NFS sillyrenamed files; it's handled by + * nfs_async_unlink(). */ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir) { @@ -1008,6 +1010,8 @@ return -EISDIR; if (IS_DEADDIR(dir)) return -ENOENT; + if (victim->d_flags & DCACHE_NFSFS_RENAMED) + return -EBUSY; return 0; } diff -Nru a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c --- a/fs/ncpfs/sock.c Wed Jun 4 17:57:06 2003 +++ b/fs/ncpfs/sock.c Thu Jun 19 18:10:37 2003 @@ -521,7 +521,7 @@ return result; } if (result > len) { - printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %u)\n", result, len); + printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len); return -EIO; } return result; @@ -614,7 +614,7 @@ goto skipdata2; } if (datalen > req->datalen + 8) { - printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %d)\n", datalen, req->datalen + 8); + printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8); server->rcv.state = 3; goto skipdata; } diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Sun May 25 19:14:31 2003 +++ b/fs/nfs/inode.c Mon Jun 16 22:03:19 2003 @@ -715,7 +715,6 @@ if (fattr->valid & NFS_ATTR_FATTR_V4) nfsi->change_attr = fattr->change_attr; inode->i_size = nfs_size_to_loff_t(fattr->size); - inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; inode->i_gid = fattr->gid; diff -Nru a/fs/nfsd/auth.c b/fs/nfsd/auth.c --- a/fs/nfsd/auth.c Tue Feb 5 09:39:38 2002 +++ b/fs/nfsd/auth.c Tue Jun 17 16:31:29 2003 @@ -17,9 +17,6 @@ struct svc_cred *cred = &rqstp->rq_cred; int i; - if (rqstp->rq_userset) - return; - if (exp->ex_flags & NFSEXP_ALLSQUASH) { cred->cr_uid = exp->ex_anon_uid; cred->cr_gid = exp->ex_anon_gid; @@ -57,5 +54,4 @@ current->cap_permitted); } - rqstp->rq_userset = 1; } diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c --- a/fs/nfsd/export.c Mon May 19 23:34:38 2003 +++ b/fs/nfsd/export.c Tue Jun 17 16:18:16 2003 @@ -153,9 +153,13 @@ goto out; dprintk("Path seems to be <%s>\n", buf); err = 0; - if (len == 0) + if (len == 0) { + struct svc_expkey *ek; set_bit(CACHE_NEGATIVE, &key.h.flags); - else { + ek = svc_expkey_lookup(&key, 2); + if (ek) + expkey_put(&ek->h, &svc_expkey_cache); + } else { struct nameidata nd; struct svc_expkey *ek; struct svc_export *exp; diff -Nru a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c --- a/fs/nfsd/nfs4proc.c Mon May 19 23:34:38 2003 +++ b/fs/nfsd/nfs4proc.c Tue Jun 17 16:30:53 2003 @@ -147,12 +147,6 @@ return 0; } -static inline int -nfsd4_renew(clientid_t *clientid) -{ - return nfs_ok; -} - /* * filehandle-manipulating ops. */ diff -Nru a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c --- a/fs/nfsd/nfs4state.c Mon May 19 23:34:37 2003 +++ b/fs/nfsd/nfs4state.c Tue Jun 17 16:31:07 2003 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ static u32 current_clientid = 1; static u32 current_ownerid = 0; static u32 current_fileid = 0; +static u32 nfs4_init = 0; /* debug counters */ u32 list_add_perfile = 0; @@ -105,11 +107,28 @@ * * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed * setclientid info. + * + * client_lru holds client queue ordered by nfs4_client.cl_time + * for lease renewal. */ static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; +static struct list_head client_lru; + +static inline void +renew_client(struct nfs4_client *clp) +{ + /* + * Move client to the end to the LRU list. + */ + dprintk("renewing client (clientid %08x/%08x)\n", + clp->cl_clientid.cl_boot, + clp->cl_clientid.cl_id); + list_move_tail(&clp->cl_lru, &client_lru); + clp->cl_time = get_seconds(); +} /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ static int @@ -160,6 +179,7 @@ dprintk("NFSD: expire_client\n"); list_del(&clp->cl_idhash); list_del(&clp->cl_strhash); + list_del(&clp->cl_lru); while (!list_empty(&clp->cl_perclient)) { sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient); release_stateowner(sop); @@ -176,6 +196,7 @@ INIT_LIST_HEAD(&clp->cl_idhash); INIT_LIST_HEAD(&clp->cl_strhash); INIT_LIST_HEAD(&clp->cl_perclient); + INIT_LIST_HEAD(&clp->cl_lru); out: return clp; } @@ -264,6 +285,8 @@ list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); idhashval = clientid_hashval(clp->cl_clientid.cl_id); list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); + list_add_tail(&clp->cl_lru, &client_lru); + clp->cl_time = get_seconds(); } void @@ -271,13 +294,13 @@ { unsigned int strhashval; - printk("ANDROS: move_to_confirm nfs4_client %p\n", clp); list_del_init(&clp->cl_strhash); list_del_init(&clp->cl_idhash); list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len); list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); + renew_client(clp); } /* @@ -940,9 +963,7 @@ open->op_stateowner = sop; status = nfs_ok; renew: - /* XXX implement LRU and state recovery thread - * renew will place nfs4_client at end of LRU - */ + renew_client(sop->so_client); out: up(&client_sema); /*XXX need finer grained locking */ return status; @@ -1048,13 +1069,98 @@ kfree(stp); goto out; } +static struct work_struct laundromat_work; +static void laundromat_main(void *); +static DECLARE_WORK(laundromat_work, laundromat_main, NULL); + +int +nfsd4_renew(clientid_t *clid) +{ + struct nfs4_client *clp; + struct list_head *pos, *next; + unsigned int idhashval; + int status; + + down(&client_sema); + printk("process_renew(%08x/%08x): starting\n", + clid->cl_boot, clid->cl_id); + status = nfserr_stale_clientid; + if (STALE_CLIENTID(clid)) + goto out; + status = nfs_ok; + idhashval = clientid_hashval(clid->cl_id); + list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_idhash); + if (!cmp_clid(&clp->cl_clientid, clid)) + continue; + renew_client(clp); + goto out; + } + list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) { + clp = list_entry(pos, struct nfs4_client, cl_idhash); + if (!cmp_clid(&clp->cl_clientid, clid)) + continue; + renew_client(clp); + goto out; + } + /* + * Couldn't find an nfs4_client for this clientid. + * Presumably this is because the client took too long to + * RENEW, so return NFS4ERR_EXPIRED. + */ + printk("nfsd4_renew: clientid not found!\n"); + status = nfserr_expired; +out: + up(&client_sema); + return status; +} + +time_t +nfs4_laundromat(void) +{ + struct nfs4_client *clp; + struct list_head *pos, *next; + time_t cutoff = get_seconds() - NFSD_LEASE_TIME; + time_t t, return_val = NFSD_LEASE_TIME; + + down(&client_sema); + + dprintk("NFSD: laundromat service - starting, examining clients\n"); + list_for_each_safe(pos, next, &client_lru) { + clp = list_entry(pos, struct nfs4_client, cl_lru); + if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { + t = clp->cl_time - cutoff; + if (return_val > t) + return_val = t; + break; + } + dprintk("NFSD: purging unused client (clientid %08x)\n", + clp->cl_clientid.cl_id); + expire_client(clp); + } + if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT) + return_val = NFSD_LAUNDROMAT_MINTIMEOUT; + up(&client_sema); + return return_val; +} + +void +laundromat_main(void *not_used) +{ + time_t t; + + t = nfs4_laundromat(); + dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); + schedule_delayed_work(&laundromat_work, t*HZ); +} void nfs4_state_init(void) { - struct timespec tv; int i; + if (nfs4_init) + return; for (i = 0; i < CLIENT_HASH_SIZE; i++) { INIT_LIST_HEAD(&conf_id_hashtbl[i]); INIT_LIST_HEAD(&conf_str_hashtbl[i]); @@ -1067,9 +1173,13 @@ for (i = 0; i < OWNER_HASH_SIZE; i++) { INIT_LIST_HEAD(&ownerstr_hashtbl[i]); } + INIT_LIST_HEAD(&client_lru); init_MUTEX(&client_sema); - tv = CURRENT_TIME; - boot_time = tv.tv_sec; + boot_time = get_seconds(); + INIT_WORK(&laundromat_work,laundromat_main, NULL); + schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ); + nfs4_init = 1; + } static void @@ -1089,6 +1199,9 @@ } } release_all_files(); + cancel_delayed_work(&laundromat_work); + flush_scheduled_work(); + nfs4_init = 0; dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n", list_add_perfile, list_del_perfile); dprintk("NFSD: add_perclient %d del_perclient %d\n", diff -Nru a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c --- a/fs/nfsd/nfs4xdr.c Mon May 19 23:34:36 2003 +++ b/fs/nfsd/nfs4xdr.c Tue Jun 17 16:30:43 2003 @@ -1039,6 +1039,7 @@ *p++ = htonl((u32)(n)); \ } while (0) #define WRITEMEM(ptr,nbytes) do { \ + *(p + XDR_QUADLEN(nbytes) -1) = 0; \ memcpy(p, ptr, nbytes); \ p += XDR_QUADLEN(nbytes); \ } while (0) @@ -1425,6 +1426,7 @@ u32 *p = cd->buffer; u32 *attrlenp; struct dentry *dentry; + struct svc_export *exp = cd->rd_fhp->fh_export; u32 bmval0, bmval1; int nfserr = 0; @@ -1454,9 +1456,7 @@ if ((bmval0 & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_FILEID)) || bmval1) { /* * "Heavyweight" case: we have no choice except to - * call nfsd4_encode_fattr(). As far as I know, - * only Windows clients will trigger this code - * path. + * call nfsd4_encode_fattr(). */ dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen); if (IS_ERR(dentry)) { @@ -1464,10 +1464,25 @@ goto error; } - nfserr = nfsd4_encode_fattr(NULL, cd->rd_fhp->fh_export, - dentry, p, &buflen, cd->rd_bmval); - dput(dentry); + if (d_mountpoint(dentry)) { + if ((nfserr = nfsd_cross_mnt(cd->rd_rqstp, &dentry, + &exp))) { + /* + * -EAGAIN is the only error returned from + * nfsd_cross_mnt() and it indicates that an + * up-call has been initiated to fill in the export + * options on exp. When the answer comes back, + * this call will be retried. + */ + dput(dentry); + nfserr = nfserr_dropit; + goto error; + } + } + + nfserr = nfsd4_encode_fattr(NULL, exp, + dentry, p, &buflen, cd->rd_bmval); if (!nfserr) { p += buflen; goto out; diff -Nru a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c --- a/fs/nfsd/nfsctl.c Sun May 25 18:48:17 2003 +++ b/fs/nfsd/nfsctl.c Tue Jun 17 16:31:07 2003 @@ -453,7 +453,6 @@ nfsd_cache_init(); /* RPC reply cache */ nfsd_export_init(); /* Exports table */ nfsd_lockd_init(); /* lockd->nfsd callbacks */ - nfs4_state_init(); /* NFSv4 State */ if (proc_mkdir("fs/nfs", 0)) { struct proc_dir_entry *entry; entry = create_proc_entry("fs/nfs/exports", 0, NULL); diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c --- a/fs/nfsd/nfsfh.c Wed Apr 2 22:51:32 2003 +++ b/fs/nfsd/nfsfh.c Tue Jun 17 16:31:29 2003 @@ -161,9 +161,6 @@ goto out; } - /* Set user creds if we haven't done so already. */ - nfsd_setuser(rqstp, exp); - /* * Look up the dentry using the NFS file handle. */ @@ -222,6 +219,10 @@ cache_get(&exp->h); inode = dentry->d_inode; + + + /* Set user creds for this exportpoint */ + nfsd_setuser(rqstp, exp); /* Type check. The correct error return for type mismatches * does not seem to be generally agreed upon. SunOS seems to diff -Nru a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c --- a/fs/nfsd/nfsproc.c Mon Jan 13 04:39:46 2003 +++ b/fs/nfsd/nfsproc.c Tue Jun 17 16:18:16 2003 @@ -591,6 +591,7 @@ { nfserr_dquot, -EDQUOT }, #endif { nfserr_stale, -ESTALE }, + { nfserr_dropit, -EAGAIN }, { nfserr_dropit, -ENOMEM }, { -1, -EIO } }; diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c --- a/fs/nfsd/nfssvc.c Tue Jun 10 23:33:23 2003 +++ b/fs/nfsd/nfssvc.c Tue Jun 17 16:31:07 2003 @@ -91,6 +91,7 @@ /* Readahead param cache - will no-op if it already exists */ error = nfsd_racache_init(2*nrservs); + nfs4_state_init(); if (error<0) goto out; if (!nfsd_serv) { diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c --- a/fs/nfsd/vfs.c Sun May 4 22:49:54 2003 +++ b/fs/nfsd/vfs.c Tue Jun 17 16:24:29 2003 @@ -74,6 +74,46 @@ static struct raparms * raparml; static struct raparms * raparm_cache; +/* + * Called from nfsd_lookup and encode_dirent. Check if we have crossed + * a mount point. + * Returns -EAGAIN leaving *dpp and *expp unchanged, + * or nfs_ok having possibly changed *dpp and *expp + */ +int +nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp) +{ + struct svc_export *exp = *expp, *exp2 = NULL; + struct dentry *dentry = *dpp; + struct vfsmount *mnt = mntget(exp->ex_mnt); + struct dentry *mounts = dget(dentry); + int err = nfs_ok; + + while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); + + exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); + if (IS_ERR(exp2)) { + err = PTR_ERR(exp2); + dput(mounts); + mntput(mnt); + goto out; + } + if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMNT) || EX_NOHIDE(exp2))) { + /* successfully crossed mount point */ + exp_put(exp); + *expp = exp2; + dput(dentry); + *dpp = mounts; + } else { + if (exp2) exp_put(exp2); + dput(mounts); + } + mntput(mnt); +out: + return err; +} + /* * Look up one component of a pathname. * N.B. After this call _both_ fhp and resfh need an fh_put @@ -154,34 +194,10 @@ * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { - struct svc_export *exp2 = NULL; - struct vfsmount *mnt = mntget(exp->ex_mnt); - struct dentry *mounts = dget(dentry); - while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)) - ; - - exp2 = exp_get_by_name(exp->ex_client, mnt, - mounts, &rqstp->rq_chandle); - if (IS_ERR(exp2)) { - err = PTR_ERR(exp2); - dput(mounts); - dput(dentry); - mntput(mnt); - goto out; - } - if (exp2 && - ((exp->ex_flags & NFSEXP_CROSSMNT) - || EX_NOHIDE(exp2))) { - /* successfully crossed mount point */ - exp_put(exp); - exp = exp2; + if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { dput(dentry); - dentry = mounts; - } else { - if (exp2) exp_put(exp2); - dput(mounts); + goto out_nfserr; } - mntput(mnt); } } /* diff -Nru a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c --- a/fs/proc/task_mmu.c Mon May 19 12:40:47 2003 +++ b/fs/proc/task_mmu.c Thu Jun 19 16:57:39 2003 @@ -91,13 +91,13 @@ } seq_printf(m, "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %lu %n", - 2*sizeof(void*), map->vm_start, - 2*sizeof(void*), map->vm_end, + (int) (2*sizeof(void*)), map->vm_start, + (int) (2*sizeof(void*)), map->vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', - 2*sizeof(void*), map->vm_pgoff << PAGE_SHIFT, + (int) (2*sizeof(void*)), map->vm_pgoff << PAGE_SHIFT, MAJOR(dev), MINOR(dev), ino, &len); if (map->vm_file) { diff -Nru a/include/acpi/acconfig.h b/include/acpi/acconfig.h --- a/include/acpi/acconfig.h Fri May 23 16:01:52 2003 +++ b/include/acpi/acconfig.h Thu Jun 19 17:41:29 2003 @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20030522 +#define ACPI_CA_VERSION 0x20030619 /* Maximum objects in the various object caches */ diff -Nru a/include/acpi/acglobal.h b/include/acpi/acglobal.h --- a/include/acpi/acglobal.h Mon May 12 10:44:47 2003 +++ b/include/acpi/acglobal.h Thu Jun 19 17:41:29 2003 @@ -105,6 +105,7 @@ */ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width; +ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; diff -Nru a/include/acpi/achware.h b/include/acpi/achware.h --- a/include/acpi/achware.h Thu Apr 24 11:22:45 2003 +++ b/include/acpi/achware.h Thu Jun 19 17:41:29 2003 @@ -108,7 +108,7 @@ acpi_status acpi_hw_clear_acpi_status ( - void); + u32 flags); /* GPE support */ diff -Nru a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h --- a/include/acpi/acpiosxf.h Sat May 24 00:32:37 2003 +++ b/include/acpi/acpiosxf.h Thu Jun 19 17:41:29 2003 @@ -287,15 +287,15 @@ * Miscellaneous */ -BOOLEAN +u8 acpi_os_readable ( void *pointer, - u32 length); + acpi_size length); -BOOLEAN +u8 acpi_os_writable ( void *pointer, - u32 length); + acpi_size length); u32 acpi_os_get_timer ( diff -Nru a/include/acpi/actypes.h b/include/acpi/actypes.h --- a/include/acpi/actypes.h Sun May 25 14:08:22 2003 +++ b/include/acpi/actypes.h Thu Jun 19 17:41:29 2003 @@ -50,11 +50,14 @@ /* * Data type ranges - */ -#define ACPI_UINT8_MAX (~((UINT8) 0)) -#define ACPI_UINT16_MAX (~((UINT16) 0)) -#define ACPI_UINT32_MAX (~((UINT32) 0)) -#define ACPI_UINT64_MAX (~((UINT64) 0)) + * Note: These macros are designed to be compiler independent as well as + * working around problems that some 32-bit compilers have with 64-bit + * constants. + */ +#define ACPI_UINT8_MAX (UINT8) (~((UINT8) 0)) /* 0xFF */ +#define ACPI_UINT16_MAX (UINT16)(~((UINT16) 0)) /* 0xFFFF */ +#define ACPI_UINT32_MAX (UINT32)(~((UINT32) 0)) /* 0xFFFFFFFF */ +#define ACPI_UINT64_MAX (UINT64)(~((UINT64) 0)) /* 0xFFFFFFFFFFFFFFFF */ #define ACPI_ASCII_MAX 0x7F @@ -299,8 +302,6 @@ typedef u32 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT32_MAX #define ACPI_INTEGER_BIT_SIZE 32 -#define ACPI_MAX_BCD_VALUE 99999999 -#define ACPI_MAX_BCD_DIGITS 8 #define ACPI_MAX_DECIMAL_DIGITS 10 #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */ @@ -313,12 +314,6 @@ typedef u64 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 -#if ACPI_MACHINE_WIDTH == 64 -#define ACPI_MAX_BCD_VALUE 9999999999999999UL -#else -#define ACPI_MAX_BCD_VALUE 9999999999999999ULL -#endif -#define ACPI_MAX_BCD_DIGITS 16 #define ACPI_MAX_DECIMAL_DIGITS 19 #if ACPI_MACHINE_WIDTH == 64 diff -Nru a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h --- a/include/asm-alpha/smp.h Thu Jan 2 00:08:46 2003 +++ b/include/asm-alpha/smp.h Tue Jun 17 09:21:45 2003 @@ -57,6 +57,15 @@ return hweight64(cpu_online_map); } +extern inline int +any_online_cpu(unsigned int mask) +{ + if (mask & cpu_online_map) + return __ffs(mask & cpu_online_map); + + return -1; +} + extern int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, unsigned long cpu); #else /* CONFIG_SMP */ diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h --- a/include/asm-alpha/unistd.h Thu Jun 5 17:01:44 2003 +++ b/include/asm-alpha/unistd.h Thu Jun 19 10:20:02 2003 @@ -593,13 +593,7 @@ return sys_read(fd, buf, nr); } -extern int __kernel_execve(char *, char **, char **, struct pt_regs *); -static inline long execve(char * file, char ** argvp, char ** envp) -{ - struct pt_regs regs; - memset(®s, 0, sizeof(regs)); - return __kernel_execve(file, argvp, envp, ®s); -} +extern long execve(char *, char **, char **); extern long sys_setsid(void); static inline long setsid(void) diff -Nru a/include/asm-alpha/xor.h b/include/asm-alpha/xor.h --- a/include/asm-alpha/xor.h Sat Nov 9 04:16:32 2002 +++ b/include/asm-alpha/xor.h Mon Jun 16 11:18:35 2003 @@ -822,19 +822,19 @@ "); static struct xor_block_template xor_block_alpha = { - name: "alpha", - do_2: xor_alpha_2, - do_3: xor_alpha_3, - do_4: xor_alpha_4, - do_5: xor_alpha_5, + .name = "alpha", + .do_2 = xor_alpha_2, + .do_3 = xor_alpha_3, + .do_4 = xor_alpha_4, + .do_5 = xor_alpha_5, }; static struct xor_block_template xor_block_alpha_prefetch = { - name: "alpha prefetch", - do_2: xor_alpha_prefetch_2, - do_3: xor_alpha_prefetch_3, - do_4: xor_alpha_prefetch_4, - do_5: xor_alpha_prefetch_5, + .name = "alpha prefetch", + .do_2 = xor_alpha_prefetch_2, + .do_3 = xor_alpha_prefetch_3, + .do_4 = xor_alpha_prefetch_4, + .do_5 = xor_alpha_prefetch_5, }; /* For grins, also test the generic routines. */ diff -Nru a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/hardware/amba.h Wed Jun 18 15:23:24 2003 @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/hardware/amba.h + * + * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef ASMARM_AMBA_H +#define ASMARM_AMBA_H + +struct amba_device { + struct device dev; + struct resource res; + unsigned int irq; + unsigned int periphid; +}; + +struct amba_id { + unsigned int id; + unsigned int mask; + void *data; +}; + +struct amba_driver { + struct device_driver drv; + int (*probe)(struct amba_device *, void *); + int (*remove)(struct amba_device *); + void (*shutdown)(struct amba_device *); + int (*suspend)(struct amba_device *, u32, u32); + int (*resume)(struct amba_device *, u32); + struct amba_id *id_table; +}; + +#define amba_get_drvdata(d) dev_get_drvdata(&d->dev) +#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p) + +int amba_driver_register(struct amba_driver *); +void amba_driver_unregister(struct amba_driver *); +int amba_device_register(struct amba_device *, struct resource *); +void amba_device_unregister(struct amba_device *); + +#endif diff -Nru a/include/asm-arm/hardware/icst525.h b/include/asm-arm/hardware/icst525.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm/hardware/icst525.h Wed Jun 18 14:59:44 2003 @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/hardware/icst525.h + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST525 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + */ +#ifndef ASMARM_HARDWARE_ICST525_H +#define ASMARM_HARDWARE_ICST525_H + +struct icst525_params { + unsigned long ref; + unsigned long vco_max; /* inclusive */ + unsigned short vd_min; /* inclusive */ + unsigned short vd_max; /* inclusive */ + unsigned char rd_min; /* inclusive */ + unsigned char rd_max; /* inclusive */ +}; + +struct icst525_vco { + unsigned short v; + unsigned char r; + unsigned char s; +}; + +unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco); +struct icst525_vco icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq); +struct icst525_vco icst525_ps_to_vco(const struct icst525_params *p, unsigned long period); + +#endif diff -Nru a/include/asm-arm/memory.h b/include/asm-arm/memory.h --- a/include/asm-arm/memory.h Sun Dec 29 02:03:23 2002 +++ b/include/asm-arm/memory.h Wed Jun 18 16:12:59 2003 @@ -27,6 +27,9 @@ /* * These are *only* valid on the kernel direct mapped RAM memory. + * Note: Drivers should NOT use these. They are the wrong + * translation for translating DMA addresses. Use the driver + * DMA support - see dma-mapping.h. */ static inline unsigned long virt_to_phys(void *x) { @@ -38,6 +41,9 @@ return (void *)(__phys_to_virt((unsigned long)(x))); } +/* + * Drivers should NOT use these either. + */ #define __pa(x) __virt_to_phys((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) @@ -72,7 +78,7 @@ #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) #define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) -#define virt_addr_valid(kaddr) ((kaddr) >= PAGE_OFFSET && (kaddr) < (unsigned long)high_memory) +#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) #define PHYS_TO_NID(addr) (0) diff -Nru a/include/asm-arm/proc-armv/uaccess.h b/include/asm-arm/proc-armv/uaccess.h --- a/include/asm-arm/proc-armv/uaccess.h Fri Jan 10 15:37:48 2003 +++ b/include/asm-arm/proc-armv/uaccess.h Fri Jun 13 05:07:49 2003 @@ -87,10 +87,18 @@ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ : "cc") +#ifndef __ARMEB__ +#define __reg_oper0 "%R2" +#define __reg_oper1 "%Q2" +#else +#define __reg_oper0 "%Q2" +#define __reg_oper1 "%R2" +#endif + #define __put_user_asm_dword(x,__pu_addr,err) \ __asm__ __volatile__( \ - "1: strt %Q2, [%1], #4\n" \ - "2: strt %R2, [%1], #0\n" \ + "1: strt " __reg_oper1 ", [%1], #4\n" \ + "2: strt " __reg_oper0 ", [%1], #0\n" \ "3:\n" \ " .section .fixup,\"ax\"\n" \ " .align 2\n" \ diff -Nru a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h --- a/include/asm-i386/acpi.h Mon Jul 22 12:55:44 2002 +++ b/include/asm-i386/acpi.h Fri Jun 13 12:58:20 2003 @@ -106,6 +106,10 @@ :"0"(n_hi), "1"(n_lo)) +#ifdef CONFIG_ACPI_HT_ONLY +extern int acpi_lapic; +#define acpi_ioapic 0 +#else #ifndef CONFIG_ACPI_BOOT #define acpi_lapic 0 #define acpi_ioapic 0 @@ -119,6 +123,7 @@ extern int acpi_ioapic; #else #define acpi_ioapic 0 +#endif #endif /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ diff -Nru a/include/asm-i386/apic.h b/include/asm-i386/apic.h --- a/include/asm-i386/apic.h Sat Jun 14 17:17:28 2003 +++ b/include/asm-i386/apic.h Sun Jun 15 11:00:08 2003 @@ -81,6 +81,8 @@ extern void setup_apic_nmi_watchdog (void); extern void disable_lapic_nmi_watchdog(void); extern void enable_lapic_nmi_watchdog(void); +extern void disable_timer_nmi_watchdog(void); +extern void enable_timer_nmi_watchdog(void); extern inline void nmi_watchdog_tick (struct pt_regs * regs); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); diff -Nru a/include/asm-ia64/a.out.h b/include/asm-ia64/a.out.h --- a/include/asm-ia64/a.out.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/a.out.h Wed Jun 4 05:30:36 2003 @@ -30,9 +30,6 @@ #define N_TXTOFF(x) 0 #ifdef __KERNEL__ -# include -# define STACK_TOP (0x6000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) -# define IA64_RBS_BOT (STACK_TOP - 0x80000000L + PAGE_SIZE) /* bottom of reg. backing store */ +#include #endif - #endif /* _ASM_IA64_A_OUT_H */ diff -Nru a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h --- a/include/asm-ia64/asmmacro.h Wed Jan 29 22:16:51 2003 +++ b/include/asm-ia64/asmmacro.h Thu Jun 12 01:09:19 2003 @@ -43,21 +43,25 @@ .section "__ex_table", "a" // declare section & section attributes .previous -#if __GNUC__ >= 3 # define EX(y,x...) \ .xdata4 "__ex_table", 99f-., y-.; \ [99:] x # define EXCLR(y,x...) \ .xdata4 "__ex_table", 99f-., y-.+4; \ [99:] x -#else -# define EX(y,x...) \ - .xdata4 "__ex_table", 99f-., y-.; \ - 99: x -# define EXCLR(y,x...) \ - .xdata4 "__ex_table", 99f-., y-.+4; \ - 99: x -#endif + +/* + * Mark instructions that need a load of a virtual address patched to be + * a load of a physical address. We use this either in critical performance + * path (ivt.S - TLB miss processing) or in places where it might not be + * safe to use a "tpa" instruction (mca_asm.S - error recovery). + */ + .section ".data.patch.vtop", "a" // declare section & section attributes + .previous + +#define LOAD_PHYSICAL(pr, reg, obj) \ +[1:](pr)movl reg = obj; \ + .xdata4 ".data.patch.vtop", 1b-. /* * For now, we always put in the McKinley E9 workaround. On CPUs that don't need it, @@ -65,11 +69,11 @@ */ #define DO_MCKINLEY_E9_WORKAROUND #ifdef DO_MCKINLEY_E9_WORKAROUND - .section "__mckinley_e9_bundles", "a" + .section ".data.patch.mckinley_e9", "a" .previous /* workaround for Itanium 2 Errata 9: */ # define MCKINLEY_E9_WORKAROUND \ - .xdata4 "__mckinley_e9_bundles", 1f-.; \ + .xdata4 ".data.patch.mckinley_e9", 1f-.;\ 1:{ .mib; \ nop.m 0; \ nop.i 0; \ diff -Nru a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h --- a/include/asm-ia64/compat.h Fri Apr 18 07:18:38 2003 +++ b/include/asm-ia64/compat.h Tue Jun 17 23:50:17 2003 @@ -128,4 +128,11 @@ return (void *) (unsigned long) uptr; } +static __inline__ void * +compat_alloc_user_space (long len) +{ + struct pt_regs *regs = ia64_task_regs(current); + return (void *) ((regs->r12 & -16) - len); +} + #endif /* _ASM_IA64_COMPAT_H */ diff -Nru a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h --- a/include/asm-ia64/elf.h Mon Mar 17 21:31:50 2003 +++ b/include/asm-ia64/elf.h Thu Jun 12 19:31:21 2003 @@ -42,6 +42,93 @@ */ #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x800000000) +#define PT_IA_64_UNWIND 0x70000001 + +/* IA-64 relocations: */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym+add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym+add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym+add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym+add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym+add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym+add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym+add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym+add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym+add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym+add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym+add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym+add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym+add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym+add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym+add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym+add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym+add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym+add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym+add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym+add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym+add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym+add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym+add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), 4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), 4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), 8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), 8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym+add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym+add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym+add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym+add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym+add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym+add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym+add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym+add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym+add), ptb, call */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym+add), imm22 */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym+add), imm64 */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* dynamic reloc, data copy */ +#define R_IA64_SUB 0x85 /* -symbol + addend, add imm22 */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym+add), add imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym+add), add imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym+add), add imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym+add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), add imm22 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym+add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym+add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(s+a)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym+add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym+add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym+add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym+add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym+add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym+add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym+add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* IA-64 specific section flags: */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ /* * We use (abuse?) this macro to insert the (empty) vm_area that is @@ -62,7 +149,7 @@ * b0-b7 * ip cfm psr * ar.rsc ar.bsp ar.bspstore ar.rnat - * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec + * ar.ccv ar.unat ar.fpsr ar.pfs ar.lc ar.ec ar.csd ar.ssd */ #define ELF_NGREG 128 /* we really need just 72 but let's leave some headroom... */ #define ELF_NFPREG 128 /* f0 and f1 could be omitted, but so what... */ @@ -91,28 +178,72 @@ #define ELF_PLATFORM 0 /* - * This should go into linux/elf.h... + * Architecture-neutral AT_ values are in the range 0-17. Leave some room for more of + * them, start the architecture-specific ones at 32. */ #define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 #ifdef __KERNEL__ struct elf64_hdr; extern void ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter); #define SET_PERSONALITY(ex, ibcs2) ia64_set_personality(&(ex), ibcs2) +struct task_struct; + extern int dump_task_regs(struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); #define ELF_CORE_COPY_TASK_REGS(tsk, elf_gregs) dump_task_regs(tsk, elf_gregs) #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) -#ifdef CONFIG_FSYS -#define ARCH_DLINFO \ -do { \ - extern char syscall_via_epc[], __start_gate_section[]; \ - NEW_AUX_ENT(AT_SYSINFO, GATE_ADDR + (syscall_via_epc - __start_gate_section)); \ +#define GATE_EHDR ((const struct elfhdr *) GATE_ADDR) + +#define ARCH_DLINFO \ +do { \ + extern char __kernel_syscall_via_epc[]; \ + NEW_AUX_ENT(AT_SYSINFO, __kernel_syscall_via_epc); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, (unsigned long) GATE_EHDR); \ +} while (0) + +/* + * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out extra segments + * containing the gate DSO contents. Dumping its contents makes post-mortem fully + * interpretable later without matching up the same kernel and hardware config to see what + * IP values meant. Dumping its extra ELF program headers includes all the other + * information a debugger needs to easily find how the gate DSO was being used. + */ +#define ELF_CORE_EXTRA_PHDRS (GATE_EHDR->e_phnum) +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +do { \ + const struct elf_phdr *const gate_phdrs = \ + (const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff); \ + int i; \ + Elf64_Off ofs = 0; \ + for (i = 0; i < GATE_EHDR->e_phnum; ++i) { \ + struct elf_phdr phdr = gate_phdrs[i]; \ + if (phdr.p_type == PT_LOAD) { \ + ofs = phdr.p_offset = offset; \ + offset += phdr.p_filesz; \ + } else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} while (0) + +#define ELF_CORE_WRITE_EXTRA_DATA \ +do { \ + const struct elf_phdr *const gate_phdrs = \ + (const struct elf_phdr *) (GATE_ADDR \ + + GATE_EHDR->e_phoff); \ + int i; \ + for (i = 0; i < GATE_EHDR->e_phnum; ++i) { \ + if (gate_phdrs[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) gate_phdrs[i].p_vaddr, \ + gate_phdrs[i].p_filesz); \ + } \ } while (0) -#endif #endif /* __KERNEL__ */ diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h --- a/include/asm-ia64/ia32.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/ia32.h Thu Jun 12 00:29:38 2003 @@ -3,478 +3,19 @@ #include -#ifdef CONFIG_IA32_SUPPORT - -#include -#include - -/* - * 32 bit structures for IA32 support. - */ - -#define IA32_PAGE_SHIFT 12 /* 4KB pages */ -#define IA32_PAGE_SIZE (1UL << IA32_PAGE_SHIFT) -#define IA32_PAGE_MASK (~(IA32_PAGE_SIZE - 1)) -#define IA32_PAGE_ALIGN(addr) (((addr) + IA32_PAGE_SIZE - 1) & IA32_PAGE_MASK) -#define IA32_CLOCKS_PER_SEC 100 /* Cast in stone for IA32 Linux */ - -/* sigcontext.h */ -/* - * As documented in the iBCS2 standard.. - * - * The first part of "struct _fpstate" is just the - * normal i387 hardware setup, the extra "status" - * word is used to save the coprocessor status word - * before entering the handler. - */ -struct _fpreg_ia32 { - unsigned short significand[4]; - unsigned short exponent; -}; - -struct _fpxreg_ia32 { - unsigned short significand[4]; - unsigned short exponent; - unsigned short padding[3]; -}; - -struct _xmmreg_ia32 { - unsigned int element[4]; -}; - - -struct _fpstate_ia32 { - unsigned int cw, - sw, - tag, - ipoff, - cssel, - dataoff, - datasel; - struct _fpreg_ia32 _st[8]; - unsigned short status; - unsigned short magic; /* 0xffff = regular FPU data only */ - - /* FXSR FPU environment */ - unsigned int _fxsr_env[6]; /* FXSR FPU env is ignored */ - unsigned int mxcsr; - unsigned int reserved; - struct _fpxreg_ia32 _fxsr_st[8]; /* FXSR FPU reg data is ignored */ - struct _xmmreg_ia32 _xmm[8]; - unsigned int padding[56]; -}; - -struct sigcontext_ia32 { - unsigned short gs, __gsh; - unsigned short fs, __fsh; - unsigned short es, __esh; - unsigned short ds, __dsh; - unsigned int edi; - unsigned int esi; - unsigned int ebp; - unsigned int esp; - unsigned int ebx; - unsigned int edx; - unsigned int ecx; - unsigned int eax; - unsigned int trapno; - unsigned int err; - unsigned int eip; - unsigned short cs, __csh; - unsigned int eflags; - unsigned int esp_at_signal; - unsigned short ss, __ssh; - unsigned int fpstate; /* really (struct _fpstate_ia32 *) */ - unsigned int oldmask; - unsigned int cr2; -}; - -/* user.h */ -/* - * IA32 (Pentium III/4) FXSR, SSE support - * - * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for - * interacting with the FXSR-format floating point environment. Floating - * point data can be accessed in the regular format in the usual manner, - * and both the standard and SIMD floating point data can be accessed via - * the new ptrace requests. In either case, changes to the FPU environment - * will be reflected in the task's state as expected. - */ -struct ia32_user_i387_struct { - int cwd; - int swd; - int twd; - int fip; - int fcs; - int foo; - int fos; - int st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ -}; - -struct ia32_user_fxsr_struct { - unsigned short cwd; - unsigned short swd; - unsigned short twd; - unsigned short fop; - int fip; - int fcs; - int foo; - int fos; - int mxcsr; - int reserved; - int st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ - int xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ - int padding[56]; -}; - -/* signal.h */ -#define IA32_SET_SA_HANDLER(ka,handler,restorer) \ - ((ka)->sa.sa_handler = (__sighandler_t) \ - (((unsigned long)(restorer) << 32) \ - | ((handler) & 0xffffffff))) -#define IA32_SA_HANDLER(ka) ((unsigned long) (ka)->sa.sa_handler & 0xffffffff) -#define IA32_SA_RESTORER(ka) ((unsigned long) (ka)->sa.sa_handler >> 32) - -struct sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal with 32 bits */ - unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ - compat_sigset_t sa_mask; /* A 32 bit mask */ -}; - -struct old_sigaction32 { - unsigned int sa_handler; /* Really a pointer, but need to deal - with 32 bits */ - compat_old_sigset_t sa_mask; /* A 32 bit mask */ - unsigned int sa_flags; - unsigned int sa_restorer; /* Another 32 bit pointer */ -}; - -typedef struct sigaltstack_ia32 { - unsigned int ss_sp; - int ss_flags; - unsigned int ss_size; -} stack_ia32_t; - -struct ucontext_ia32 { - unsigned int uc_flags; - unsigned int uc_link; - stack_ia32_t uc_stack; - struct sigcontext_ia32 uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ -}; - -struct stat64 { - unsigned short st_dev; - unsigned char __pad0[10]; - unsigned int __st_ino; - unsigned int st_mode; - unsigned int st_nlink; - unsigned int st_uid; - unsigned int st_gid; - unsigned short st_rdev; - unsigned char __pad3[10]; - unsigned int st_size_lo; - unsigned int st_size_hi; - unsigned int st_blksize; - unsigned int st_blocks; /* Number 512-byte blocks allocated. */ - unsigned int __pad4; /* future possible st_blocks high bits */ - unsigned int st_atime; - unsigned int st_atime_nsec; - unsigned int st_mtime; - unsigned int st_mtime_nsec; - unsigned int st_ctime; - unsigned int st_ctime_nsec; - unsigned int st_ino_lo; - unsigned int st_ino_hi; -}; - -typedef union sigval32 { - int sival_int; - unsigned int sival_ptr; -} sigval_t32; - -typedef struct siginfo32 { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[((128/sizeof(int)) - 3)]; - - /* kill() */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof(unsigned int) - sizeof(int)]; - sigval_t32 _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - unsigned int _pid; /* sender's pid */ - unsigned int _uid; /* sender's uid */ - sigval_t32 _sigval; - } _rt; - - /* SIGCHLD */ - struct { - unsigned int _pid; /* which child */ - unsigned int _uid; /* sender's uid */ - int _status; /* exit code */ - compat_clock_t _utime; - compat_clock_t _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - unsigned int _addr; /* faulting insn/memory ref. */ - } _sigfault; - - /* SIGPOLL */ - struct { - int _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - } _sifields; -} siginfo_t32; - -struct linux32_dirent { - u32 d_ino; - u32 d_off; - u16 d_reclen; - char d_name[256]; -}; - -struct old_linux32_dirent { - u32 d_ino; - u32 d_offset; - u16 d_namlen; - char d_name[1]; -}; - -/* - * IA-32 ELF specific definitions for IA-64. - */ - -#define _ASM_IA64_ELF_H /* Don't include elf.h */ - -#include -#include - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ((x)->e_machine == EM_386) - -/* - * These are used to set parameters in the core dumps. - */ -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2LSB -#define ELF_ARCH EM_386 +#include +#include -#define IA32_PAGE_OFFSET 0xc0000000 -#define IA32_STACK_TOP IA32_PAGE_OFFSET - -/* - * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can - * access them. - */ -#define IA32_GDT_OFFSET (IA32_PAGE_OFFSET) -#define IA32_TSS_OFFSET (IA32_PAGE_OFFSET + PAGE_SIZE) -#define IA32_LDT_OFFSET (IA32_PAGE_OFFSET + 2*PAGE_SIZE) - -#define USE_ELF_CORE_DUMP -#define ELF_EXEC_PAGESIZE IA32_PAGE_SIZE - -/* - * This is the location that an ET_DYN program is loaded if exec'ed. - * Typical use of this is to invoke "./ld.so someprog" to test out a - * new version of the loader. We need to make sure that it is out of - * the way of the program that it will "exec", and that there is - * sufficient room for the brk. - */ -#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) - -void ia64_elf32_init(struct pt_regs *regs); -#define ELF_PLAT_INIT(_r, load_addr) ia64_elf32_init(_r) - -#define elf_addr_t u32 - -/* ELF register definitions. This is needed for core dump support. */ - -#define ELF_NGREG 128 /* XXX fix me */ -#define ELF_NFPREG 128 /* XXX fix me */ - -typedef unsigned long elf_greg_t; -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -typedef struct { - unsigned long w0; - unsigned long w1; -} elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; - -/* This macro yields a bitmask that programs can use to figure out - what instruction set this CPU supports. */ -#define ELF_HWCAP 0 - -/* This macro yields a string that ld.so will use to load - implementation specific libraries for optimization. Not terribly - relevant until we have real hardware to play with... */ -#define ELF_PLATFORM 0 - -#ifdef __KERNEL__ -# define SET_PERSONALITY(EX,IBCS2) \ - (current->personality = (IBCS2) ? PER_SVR4 : PER_LINUX) -#endif - -#define IA32_EFLAG 0x200 - -/* - * IA-32 ELF specific definitions for IA-64. - */ - -#define __USER_CS 0x23 -#define __USER_DS 0x2B - -#define FIRST_TSS_ENTRY 6 -#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) -#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) -#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) - -#define IA32_SEGSEL_RPL (0x3 << 0) -#define IA32_SEGSEL_TI (0x1 << 2) -#define IA32_SEGSEL_INDEX_SHIFT 3 - -#define IA32_SEG_BASE 16 -#define IA32_SEG_TYPE 40 -#define IA32_SEG_SYS 44 -#define IA32_SEG_DPL 45 -#define IA32_SEG_P 47 -#define IA32_SEG_HIGH_LIMIT 48 -#define IA32_SEG_AVL 52 -#define IA32_SEG_DB 54 -#define IA32_SEG_G 55 -#define IA32_SEG_HIGH_BASE 56 - -#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran) \ - (((limit) & 0xffff) \ - | (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE) \ - | ((unsigned long) (segtype) << IA32_SEG_TYPE) \ - | ((unsigned long) (nonsysseg) << IA32_SEG_SYS) \ - | ((unsigned long) (dpl) << IA32_SEG_DPL) \ - | ((unsigned long) (segpresent) << IA32_SEG_P) \ - | ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT) \ - | ((unsigned long) (avl) << IA32_SEG_AVL) \ - | ((unsigned long) (segdb) << IA32_SEG_DB) \ - | ((unsigned long) (gran) << IA32_SEG_G) \ - | ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE)) - -#define SEG_LIM 32 -#define SEG_TYPE 52 -#define SEG_SYS 56 -#define SEG_DPL 57 -#define SEG_P 59 -#define SEG_AVL 60 -#define SEG_DB 62 -#define SEG_G 63 - -/* Unscramble an IA-32 segment descriptor into the IA-64 format. */ -#define IA32_SEG_UNSCRAMBLE(sd) \ - ( (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \ - | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM) \ - | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE) \ - | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS) \ - | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL) \ - | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P) \ - | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL) \ - | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB) \ - | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G)) - -#define IA32_IOBASE 0x2000000000000000 /* Virtual address for I/O space */ - -#define IA32_CR0 0x80000001 /* Enable PG and PE bits */ -#define IA32_CR4 0x600 /* MMXEX and FXSR on */ - -/* - * IA32 floating point control registers starting values - */ - -#define IA32_FSR_DEFAULT 0x55550000 /* set all tag bits */ -#define IA32_FCR_DEFAULT 0x17800000037fUL /* extended precision, all masks */ - -#define IA32_PTRACE_GETREGS 12 -#define IA32_PTRACE_SETREGS 13 -#define IA32_PTRACE_GETFPREGS 14 -#define IA32_PTRACE_SETFPREGS 15 -#define IA32_PTRACE_GETFPXREGS 18 -#define IA32_PTRACE_SETFPXREGS 19 - -#define ia32_start_thread(regs,new_ip,new_sp) do { \ - set_fs(USER_DS); \ - ia64_psr(regs)->cpl = 3; /* set user mode */ \ - ia64_psr(regs)->ri = 0; /* clear return slot number */ \ - ia64_psr(regs)->is = 1; /* IA-32 instruction set */ \ - regs->cr_iip = new_ip; \ - regs->ar_rsc = 0xc; /* enforced lazy mode, priv. level 3 */ \ - regs->ar_rnat = 0; \ - regs->loadrs = 0; \ - regs->r12 = new_sp; \ -} while (0) - -/* - * Local Descriptor Table (LDT) related declarations. - */ - -#define IA32_LDT_ENTRIES 8192 /* Maximum number of LDT entries supported. */ -#define IA32_LDT_ENTRY_SIZE 8 /* The size of each LDT entry. */ - -struct ia32_modify_ldt_ldt_s { - unsigned int entry_number; - unsigned int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; -}; - -struct linux_binprm; +#ifdef CONFIG_IA32_SUPPORT +extern void ia32_cpu_init (void); extern void ia32_gdt_init (void); -extern void ia32_init_addr_space (struct pt_regs *regs); -extern int ia32_setup_arg_pages (struct linux_binprm *bprm); extern int ia32_exception (struct pt_regs *regs, unsigned long isr); extern int ia32_intercept (struct pt_regs *regs, unsigned long isr); -extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t); -extern void ia32_load_segment_descriptors (struct task_struct *task); - -#define ia32f2ia64f(dst,src) \ - do { \ - register double f6 asm ("f6"); \ - asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ - } while(0) - -#define ia64f2ia32f(dst,src) \ - do { \ - register double f6 asm ("f6"); \ - asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \ - } while(0) #endif /* !CONFIG_IA32_SUPPORT */ -/* Declare this uncondiontally, so we don't get warnings for unreachable code. */ +/* Declare this unconditionally, so we don't get warnings for unreachable code. */ extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs); diff -Nru a/include/asm-ia64/io.h b/include/asm-ia64/io.h --- a/include/asm-ia64/io.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/io.h Tue Jun 10 13:57:17 2003 @@ -413,4 +413,17 @@ # endif /* __KERNEL__ */ +/* + * It makes no sense at all to have this BIO_VMERGE_BOUNDARY macro here. Should be + * replaced by dma_merge_mask() or something of that sort. Note: the only way + * BIO_VMERGE_BOUNDARY is used is to mask off bits. Effectively, our definition gets + * expanded into: + * + * addr & ((ia64_max_iommu_merge_mask + 1) - 1) == (addr & ia64_max_iommu_vmerge_mask) + * + * which is precisely what we want. + */ +extern unsigned long ia64_max_iommu_merge_mask; +#define BIO_VMERGE_BOUNDARY (ia64_max_iommu_merge_mask + 1) + #endif /* _ASM_IA64_IO_H */ diff -Nru a/include/asm-ia64/ioctl32.h b/include/asm-ia64/ioctl32.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/ioctl32.h Thu May 15 05:18:24 2003 @@ -0,0 +1 @@ +#include diff -Nru a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h --- a/include/asm-ia64/kregs.h Thu Aug 1 00:44:11 2002 +++ b/include/asm-ia64/kregs.h Fri Jun 6 07:20:51 2003 @@ -72,7 +72,7 @@ #define IA64_PSR_BITS_TO_CLEAR (IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_DB | IA64_PSR_LP | \ IA64_PSR_TB | IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | \ IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA) -#define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH) +#define IA64_PSR_BITS_TO_SET (IA64_PSR_DFH | IA64_PSR_SP) #define IA64_PSR_BE (__IA64_UL(1) << IA64_PSR_BE_BIT) #define IA64_PSR_UP (__IA64_UL(1) << IA64_PSR_UP_BIT) diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h --- a/include/asm-ia64/machvec.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/machvec.h Fri May 16 04:18:18 2003 @@ -74,8 +74,6 @@ # include # elif defined (CONFIG_IA64_HP_ZX1) # include -# elif defined (CONFIG_IA64_SGI_SN1) -# include # elif defined (CONFIG_IA64_SGI_SN2) # include # elif defined (CONFIG_IA64_GENERIC) diff -Nru a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h --- a/include/asm-ia64/mca.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/mca.h Mon Jun 9 07:11:38 2003 @@ -92,6 +92,8 @@ u64 imsto_sal_check_ra; /* Return address in SAL_CHECK while going * back to SAL from OS after MCA handling. */ + u64 pal_min_state; /* from PAL in r17 */ + u64 proc_state_param; /* from PAL in r18. See SDV 2:268 11.3.2.1 */ } ia64_mca_sal_to_os_state_t; enum { diff -Nru a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h --- a/include/asm-ia64/mca_asm.h Tue Nov 5 06:12:30 2002 +++ b/include/asm-ia64/mca_asm.h Fri May 30 17:54:44 2003 @@ -35,7 +35,7 @@ * 1. Lop off bits 61 thru 63 in the virtual address */ #define DATA_VA_TO_PA(addr) \ - dep addr = 0, addr, 61, 3 + tpa addr = addr /* * This macro converts a data physical address to a virtual address * Right now for simulation purposes the virtual addresses are diff -Nru a/include/asm-ia64/nodedata.h b/include/asm-ia64/nodedata.h --- a/include/asm-ia64/nodedata.h Tue Oct 22 15:29:01 2002 +++ b/include/asm-ia64/nodedata.h Fri May 16 04:18:18 2003 @@ -22,6 +22,7 @@ struct pglist_data; struct ia64_node_data { + short active_cpu_count; short node; struct pglist_data *pg_data_ptrs[NR_NODES]; struct page *bank_mem_map_base[NR_BANKS]; diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h --- a/include/asm-ia64/page.h Sat May 10 03:13:39 2003 +++ b/include/asm-ia64/page.h Fri Jun 6 22:53:38 2003 @@ -33,6 +33,8 @@ #define PERCPU_PAGE_SHIFT 16 /* log2() of max. size of per-CPU area */ #define PERCPU_PAGE_SIZE (__IA64_UL_CONST(1) << PERCPU_PAGE_SHIFT) +#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ + #ifdef CONFIG_HUGETLB_PAGE # if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB) @@ -60,6 +62,7 @@ # define HPAGE_SIZE (__IA64_UL_CONST(1) << HPAGE_SHIFT) # define HPAGE_MASK (~(HPAGE_SIZE - 1)) # define HAVE_ARCH_HUGETLB_UNMAPPED_AREA +# define ARCH_HAS_VALID_HUGEPAGE_RANGE #endif /* CONFIG_HUGETLB_PAGE */ #ifdef __ASSEMBLY__ @@ -131,9 +134,7 @@ # 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 +extern int check_valid_hugepage_range(unsigned long addr, unsigned long len); #endif static __inline__ int diff -Nru a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/patch.h Sat Jun 14 00:38:59 2003 @@ -0,0 +1,25 @@ +#ifndef _ASM_IA64_PATCH_H +#define _ASM_IA64_PATCH_H + +/* + * Copyright (C) 2003 Hewlett-Packard Co + * David Mosberger-Tang + * + * There are a number of reasons for patching instructions. Rather than duplicating code + * all over the place, we put the common stuff here. Reasons for patching: in-kernel + * module-loader, virtual-to-physical patch-list, McKinley Errata 9 workaround, and gate + * shared library. Undoubtedly, some of these reasons will disappear and others will + * be added over time. + */ +#include +#include + +extern void ia64_patch (u64 insn_addr, u64 mask, u64 val); /* patch any insn slot */ +extern void ia64_patch_imm64 (u64 insn_addr, u64 val); /* patch "movl" w/abs. value*/ +extern void ia64_patch_imm60 (u64 insn_addr, u64 val); /* patch "brl" w/ip-rel value */ + +extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end); +extern void ia64_patch_vtop (unsigned long start, unsigned long end); +extern void ia64_patch_gate (void); + +#endif /* _ASM_IA64_PATCH_H */ diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h --- a/include/asm-ia64/pci.h Mon Jun 9 09:26:10 2003 +++ b/include/asm-ia64/pci.h Mon Jun 16 17:03:25 2003 @@ -26,11 +26,19 @@ struct pci_dev; /* - * The PCI address space does equal the physical memory address space. - * The networking and block device layers use this boolean for bounce - * buffer decisions. + * PCI_DMA_BUS_IS_PHYS should be set to 1 if there is _necessarily_ a direct correspondence + * between device bus addresses and CPU physical addresses. Platforms with a hardware I/O + * MMU _must_ turn this off to suppress the bounce buffer handling code in the block and + * network device layers. Platforms with separate bus address spaces _must_ turn this off + * and provide a device DMA mapping implementation that takes care of the necessary + * address translation. + * + * For now, the ia64 platforms which may have separate/multiple bus address spaces all + * have I/O MMUs which support the merging of physically discontiguous buffers, so we can + * use that as the sole factor to determine the setting of PCI_DMA_BUS_IS_PHYS. */ -#define PCI_DMA_BUS_IS_PHYS (1) +extern unsigned long ia64_max_iommu_merge_mask; +#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL) static inline void pcibios_set_master (struct pci_dev *dev) diff -Nru a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h --- a/include/asm-ia64/perfmon.h Tue Apr 15 08:59:04 2003 +++ b/include/asm-ia64/perfmon.h Fri Jun 6 07:20:51 2003 @@ -14,20 +14,21 @@ #define PFM_READ_PMDS 0x03 #define PFM_STOP 0x04 #define PFM_START 0x05 -#define PFM_ENABLE 0x06 -#define PFM_DISABLE 0x07 +#define PFM_ENABLE 0x06 /* obsolete */ +#define PFM_DISABLE 0x07 /* obsolete */ #define PFM_CREATE_CONTEXT 0x08 -#define PFM_DESTROY_CONTEXT 0x09 +#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ #define PFM_RESTART 0x0a -#define PFM_PROTECT_CONTEXT 0x0b +#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ #define PFM_GET_FEATURES 0x0c #define PFM_DEBUG 0x0d -#define PFM_UNPROTECT_CONTEXT 0x0e +#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ #define PFM_GET_PMC_RESET_VAL 0x0f - +#define PFM_LOAD_CONTEXT 0x10 +#define PFM_UNLOAD_CONTEXT 0x11 /* - * CPU model specific commands (may not be supported on all models) + * PMU model specific commands (may not be supported on all PMU models) */ #define PFM_WRITE_IBRS 0x20 #define PFM_WRITE_DBRS 0x21 @@ -35,19 +36,21 @@ /* * context flags */ -#define PFM_FL_INHERIT_NONE 0x00 /* never inherit a context across fork (default) */ -#define PFM_FL_INHERIT_ONCE 0x01 /* clone pfm_context only once across fork() */ -#define PFM_FL_INHERIT_ALL 0x02 /* always clone pfm_context across fork() */ -#define PFM_FL_NOTIFY_BLOCK 0x04 /* block task on user level notifications */ -#define PFM_FL_SYSTEM_WIDE 0x08 /* create a system wide context */ -#define PFM_FL_EXCL_IDLE 0x20 /* exclude idle task from system wide session */ -#define PFM_FL_UNSECURE 0x40 /* allow unsecure monitoring for non self-monitoring task */ +#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ +#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ +#define PFM_FL_UNSECURE 0x04 /* allow unsecure monitoring for non self-monitoring task */ +#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ + +/* + * event set flags + */ +#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ /* * PMC flags */ #define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ -#define PFM_REGFL_RANDOM 0x2 /* randomize sampling periods */ +#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ /* * PMD/PMC/IBR/DBR return flags (ignored on input) @@ -55,150 +58,196 @@ * Those flags are used on output and must be checked in case EAGAIN is returned * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. */ -#define PFM_REG_RETFL_NOTAVAIL (1U<<31) /* set if register is implemented but not available */ -#define PFM_REG_RETFL_EINVAL (1U<<30) /* set if register entry is invalid */ +#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ +#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ #define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) #define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) +typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ + /* * Request structure used to define a context */ typedef struct { - unsigned long ctx_smpl_entries; /* how many entries in sampling buffer */ - unsigned long ctx_smpl_regs[4]; /* which pmds to record on overflow */ - - pid_t ctx_notify_pid; /* which process to notify on overflow */ - int ctx_flags; /* noblock/block, inherit flags */ - void *ctx_smpl_vaddr; /* returns address of BTB buffer */ - - unsigned long ctx_cpu_mask; /* on which CPU to enable perfmon (systemwide) */ - - unsigned long reserved[8]; /* for future use */ + pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ + unsigned long ctx_flags; /* noblock/block */ + unsigned int ctx_nextra_sets; /* number of extra event sets (you always get 1) */ + int ctx_fd; /* return arg: unique identification for context */ + void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ + unsigned long ctx_reserved[11]; /* for future use */ } pfarg_context_t; /* * Request structure used to write/read a PMC or PMD */ typedef struct { - unsigned int reg_num; /* which register */ - unsigned int reg_flags; /* PMC: notify/don't notify. PMD/PMC: return flags */ - unsigned long reg_value; /* configuration (PMC) or initial value (PMD) */ - - unsigned long reg_long_reset; /* reset after sampling buffer overflow (large) */ - unsigned long reg_short_reset;/* reset after counter overflow (small) */ - - unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ - unsigned long reg_random_seed; /* seed value when randomization is used */ - unsigned long reg_random_mask; /* bitmask used to limit random value */ - unsigned long reg_last_reset_value;/* last value used to reset the PMD (PFM_READ_PMDS) */ + unsigned int reg_num; /* which register */ + unsigned int reg_set; /* event set for this register */ + + unsigned long reg_value; /* initial pmc/pmd value */ + unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ - unsigned long reserved[13]; /* for future use */ + unsigned long reg_long_reset; /* reset after buffer overflow notification */ + unsigned long reg_short_reset; /* reset after counter overflow */ + + unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ + unsigned long reg_random_seed; /* seed value when randomization is used */ + unsigned long reg_random_mask; /* bitmask used to limit random value */ + unsigned long reg_last_reset_val;/* return: PMD last reset value */ + + unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ + unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ + + unsigned long reserved[3]; /* for future use */ } pfarg_reg_t; typedef struct { - unsigned int dbreg_num; /* which register */ - unsigned int dbreg_flags; /* dbregs return flags */ - unsigned long dbreg_value; /* configuration (PMC) or initial value (PMD) */ - unsigned long reserved[6]; + unsigned int dbreg_num; /* which debug register */ + unsigned int dbreg_set; /* event set for this register */ + unsigned long dbreg_value; /* value for debug register */ + unsigned long dbreg_flags; /* return: dbreg error */ + unsigned long dbreg_reserved[1]; /* for future use */ } pfarg_dbreg_t; -typedef struct { +typedef struct { unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ - unsigned int ft_smpl_version;/* sampling format: major [16-31], minor [0-15] */ - unsigned long reserved[4]; /* for future use */ + unsigned int ft_reserved; /* reserved for future use */ + unsigned long reserved[4]; /* for future use */ } pfarg_features_t; -/* - * This header is at the beginning of the sampling buffer returned to the user. - * It is exported as Read-Only at this point. It is directly followed by the - * first record. - */ typedef struct { - unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ - unsigned int reserved; - unsigned long hdr_entry_size; /* size of one entry in bytes */ - unsigned long hdr_count; /* how many valid entries */ - unsigned long hdr_pmds[4]; /* which pmds are recorded */ -} perfmon_smpl_hdr_t; + pid_t load_pid; /* process to load the context into */ + unsigned int load_set; /* first event set to load */ + unsigned long load_reserved[2]; /* for future use */ +} pfarg_load_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ + unsigned int msg_active_set; /* active set at the time of overflow */ + unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ +} pfm_ovfl_msg_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_end_msg_t; + +typedef struct { + int msg_type; /* type of the message */ + int msg_ctx_fd; /* unique identifier for the context */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_gen_msg_t; + +#define PFM_MSG_OVFL 1 /* an overflow happened */ +#define PFM_MSG_END 2 /* task to which context was attached ended */ + +typedef union { + pfm_ovfl_msg_t pfm_ovfl_msg; + pfm_end_msg_t pfm_end_msg; + pfm_gen_msg_t pfm_gen_msg; +} pfm_msg_t; /* * Define the version numbers for both perfmon as a whole and the sampling buffer format. */ -#define PFM_VERSION_MAJ 1U -#define PFM_VERSION_MIN 4U -#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) - -#define PFM_SMPL_VERSION_MAJ 1U -#define PFM_SMPL_VERSION_MIN 0U -#define PFM_SMPL_VERSION (((PFM_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_SMPL_VERSION_MIN & 0xffff)) +#define PFM_VERSION_MAJ 2U +#define PFM_VERSION_MIN 0U +#define PFM_SMPL_HDR_VERSION_MAJ 2U +#define PFM_SMPL_HDR_VERSION_MIN 0U +#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) +#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) +#define PFM_VERSION_MINOR(x) ((x) & 0xffff) -#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) -#define PFM_VERSION_MINOR(x) ((x) & 0xffff) - /* - * Entry header in the sampling buffer. The header is directly followed - * with the PMDs saved in increasing index order: PMD4, PMD5, .... How - * many PMDs are present is determined by the user program during - * context creation. - * - * XXX: in this version of the entry, only up to 64 registers can be - * recorded. This should be enough for quite some time. Always check - * sampling format before parsing entries! - * - * In the case where multiple counters overflow at the same time, the - * last_reset_value member indicates the initial value of the PMD with - * the smallest index. For instance, if PMD2 and PMD5 have overflowed, - * the last_reset_value member contains the initial value of PMD2. - */ -typedef struct { - int pid; /* identification of process */ - int cpu; /* which cpu was used */ - unsigned long last_reset_value; /* initial value of counter that overflowed */ - unsigned long stamp; /* timestamp */ - unsigned long ip; /* where did the overflow interrupt happened */ - unsigned long regs; /* bitmask of which registers overflowed */ - unsigned long reserved; /* unused */ -} perfmon_smpl_entry_t; - -extern long perfmonctl(pid_t pid, int cmd, void *arg, int narg); + * miscellaneous architected definitions + */ +#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ +#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ +#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ #ifdef __KERNEL__ -typedef struct { - void (*handler)(int irq, void *arg, struct pt_regs *regs); -} pfm_intr_handler_desc_t; +extern long perfmonctl(int fd, int cmd, void *arg, int narg); extern void pfm_save_regs (struct task_struct *); extern void pfm_load_regs (struct task_struct *); -extern int pfm_inherit (struct task_struct *, struct pt_regs *); -extern void pfm_context_exit (struct task_struct *); -extern void pfm_flush_regs (struct task_struct *); -extern void pfm_cleanup_notifiers (struct task_struct *); -extern void pfm_cleanup_owners (struct task_struct *); +extern void pfm_exit_thread(struct task_struct *); extern int pfm_use_debug_registers(struct task_struct *); extern int pfm_release_debug_registers(struct task_struct *); -extern int pfm_cleanup_smpl_buf(struct task_struct *); extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin); -extern void pfm_ovfl_block_reset(void); +extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); extern void pfm_init_percpu(void); +extern void pfm_handle_work(void); + +/* + * Reset PMD register flags + */ +#define PFM_PMD_NO_RESET 0 +#define PFM_PMD_LONG_RESET 1 +#define PFM_PMD_SHORT_RESET 2 + +typedef struct { + unsigned int notify_user:1; /* notify user program of overflow */ + unsigned int reset_pmds :2; /* PFM_PMD_NO_RESET, PFM_PMD_LONG_RESET, PFM_PMD_SHORT_RESET */ + unsigned int block:1; /* block monitored task on kernel exit */ + unsigned int stop_monitoring:1; /* will mask monitoring via PMCx.plm */ + unsigned int reserved:26; /* for future use */ +} pfm_ovfl_ctrl_t; -/* - * hooks to allow VTune/Prospect to cooperate with perfmon. - * (reserved for system wide monitoring modules only) +typedef struct { + unsigned long ovfl_pmds[4]; /* bitmask of overflowed pmds */ + unsigned long ovfl_notify[4]; /* bitmask of overflow pmds which asked for notification */ + unsigned long pmd_value; /* current 64-bit value of 1st pmd which overflowed */ + unsigned long pmd_last_reset; /* last reset value of 1st pmd which overflowed */ + unsigned long pmd_eventid; /* eventid associated with 1st pmd which overflowed */ + unsigned int active_set; /* event set active at the time of the overflow */ + unsigned int reserved1; + unsigned long smpl_pmds[4]; + unsigned long smpl_pmds_values[PMU_MAX_PMDS]; + pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */ +} pfm_ovfl_arg_t; + + +typedef struct _pfm_buffer_fmt_t { + char *fmt_name; + pfm_uuid_t fmt_uuid; + size_t fmt_arg_size; + unsigned long fmt_flags; + + int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg); + int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size); + int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg); + int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs); + int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs); + + struct _pfm_buffer_fmt_t *fmt_next; + struct _pfm_buffer_fmt_t *fmt_prev; +} pfm_buffer_fmt_t; + +extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt); +extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid); + +/* + * perfmon interface exported to modules */ -extern int pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h); -extern int pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h); +extern long pfm_mod_fast_read_pmds(struct task_struct *, unsigned long mask[4], unsigned long *addr, struct pt_regs *regs); +extern long pfm_mod_read_pmds(struct task_struct *, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs); +extern long pfm_mod_write_pmcs(struct task_struct *, pfarg_reg_t *req, unsigned int nreq, struct pt_regs *regs); /* * describe the content of the local_cpu_date->pfm_syst_info field */ -#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exist */ +#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */ #define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ #define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ - #endif /* __KERNEL__ */ diff -Nru a/include/asm-ia64/perfmon_default_smpl.h b/include/asm-ia64/perfmon_default_smpl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/perfmon_default_smpl.h Fri Jun 6 07:20:51 2003 @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for Linux/ia64 perfmon subsystem. + */ +#ifndef __PERFMON_DEFAULT_SMPL_H__ +#define __PERFMON_DEFAULT_SMPL_H__ 1 + +#define PFM_DEFAULT_SMPL_UUID { \ + 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} + +/* + * format specific parameters (passed at context creation) + */ +typedef struct { + unsigned long buf_size; /* size of the buffer in bytes */ + unsigned long reserved[3]; /* for future use */ +} pfm_default_smpl_arg_t; + +/* + * combined context+format specific structure. Can be passed + * to PFM_CONTEXT_CREATE + */ +typedef struct { + pfarg_context_t ctx_arg; + pfm_default_smpl_arg_t buf_arg; +} pfm_default_smpl_ctx_arg_t; + +/* + * This header is at the beginning of the sampling buffer returned to the user. + * It is directly followed by the first record. + */ +typedef struct { + unsigned long hdr_count; /* how many valid entries */ + void *hdr_cur_pos; /* current position in the buffer */ + void *hdr_last_pos; /* first byte beyond buffer */ + + unsigned long hdr_overflows; /* how many times the buffer overflowed */ + unsigned long hdr_buf_size; /* how many bytes in the buffer */ + unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ + unsigned int hdr_reserved1; /* for future use */ + unsigned long hdr_reserved[10]; /* for future use */ +} pfm_default_smpl_hdr_t; + +/* + * Entry header in the sampling buffer. The header is directly followed + * with the PMDs saved in increasing index order: PMD4, PMD5, .... How + * many PMDs are present depends on how the session was programmed. + * + * XXX: in this version of the entry, only up to 64 registers can be + * recorded. This should be enough for quite some time. Always check + * sampling format before parsing entries! + * + * In the case where multiple counters overflow at the same time, the + * last_reset_value member indicates the initial value of the + * overflowed PMD with the smallest index. For instance, if PMD2 and + * PMD5 have overflowed, the last_reset_value member contains the + * initial value of PMD2. + */ +typedef struct { + int pid; /* current process at PMU interrupt point */ + int cpu; /* cpu on which the overfow occured */ + unsigned long last_reset_val; /* initial value of 1st overflowed PMD */ + unsigned long ip; /* where did the overflow interrupt happened */ + unsigned long ovfl_pmds; /* which PMDS registers overflowed (64 max) */ + unsigned long tstamp; /* ar.itc on the CPU that took the overflow */ + unsigned int set; /* event set active when overflow ocurred */ + unsigned int reserved1; /* for future use */ +} pfm_default_smpl_entry_t; + +#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */ +#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS)) +#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE) + +#define PFM_DEFAULT_SMPL_VERSION_MAJ 2U +#define PFM_DEFAULT_SMPL_VERSION_MIN 0U +#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff)) + +#endif /* __PERFMON_DEFAULT_SMPL_H__ */ diff -Nru a/include/asm-ia64/pgalloc.h b/include/asm-ia64/pgalloc.h --- a/include/asm-ia64/pgalloc.h Sat Apr 19 23:22:43 2003 +++ b/include/asm-ia64/pgalloc.h Tue Jun 17 23:50:17 2003 @@ -158,29 +158,4 @@ extern void check_pgt_cache (void); -/* - * IA-64 doesn't have any external MMU info: the page tables contain all the necessary - * information. However, we use this macro to take care of any (delayed) i-cache flushing - * that may be necessary. - */ -static inline void -update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte) -{ - unsigned long addr; - struct page *page; - - if (!pte_exec(pte)) - return; /* not an executable page... */ - - page = pte_page(pte); - /* don't use VADDR: it may not be mapped on this CPU (or may have just been flushed): */ - addr = (unsigned long) page_address(page); - - if (test_bit(PG_arch_1, &page->flags)) - return; /* i-cache is already coherent with d-cache */ - - flush_icache_range(addr, addr + PAGE_SIZE); - set_bit(PG_arch_1, &page->flags); /* mark page as clean */ -} - #endif /* _ASM_IA64_PGALLOC_H */ diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h --- a/include/asm-ia64/pgtable.h Sun Jun 1 14:12:56 2003 +++ b/include/asm-ia64/pgtable.h Tue Jun 17 23:50:17 2003 @@ -8,7 +8,7 @@ * This hopefully works with any (fixed) IA-64 page-size, as defined * in (currently 8192). * - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang */ @@ -75,6 +75,8 @@ #define _PAGE_SIZE_16M 24 #define _PAGE_SIZE_64M 26 #define _PAGE_SIZE_256M 28 +#define _PAGE_SIZE_1G 30 +#define _PAGE_SIZE_4G 32 #define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB #define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB @@ -202,16 +204,21 @@ #define set_pte(ptep, pteval) (*(ptep) = (pteval)) #define RGN_SIZE (1UL << 61) -#define RGN_MAP_LIMIT ((1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE) /* per region addr limit */ #define RGN_KERNEL 7 -#define VMALLOC_START (0xa000000000000000 + 3*PERCPU_PAGE_SIZE) +#define VMALLOC_START 0xa000000200000000 #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#ifdef CONFIG_VIRTUAL_MEM_MAP +# define VMALLOC_END_INIT (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +# define VMALLOC_END vmalloc_end + extern unsigned long vmalloc_end; +#else +# define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +#endif /* fs/proc/kcore.c */ -#define kc_vaddr_to_offset(v) ((v) - 0xA000000000000000) -#define kc_offset_to_vaddr(o) ((o) + 0xA000000000000000) +#define kc_vaddr_to_offset(v) ((v) - 0xa000000000000000) +#define kc_offset_to_vaddr(o) ((o) + 0xa000000000000000) /* * Conversion functions: convert page frame number (pfn) and a protection value to a page @@ -255,6 +262,7 @@ /* * The following have defined behavior only work if pte_present() is true. */ +#define pte_user(pte) ((pte_val(pte) & _PAGE_PL_MASK) == _PAGE_PL_3) #define pte_read(pte) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) < 6) #define pte_write(pte) ((unsigned) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) - 2) <= 4) #define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0) @@ -274,10 +282,9 @@ #define pte_mkdirty(pte) (__pte(pte_val(pte) | _PAGE_D)) /* - * Macro to make mark a page protection value as "uncacheable". Note - * that "protection" is really a misnomer here as the protection value - * contains the memory attribute bits, dirty bits, and various other - * bits as well. + * Macro to a page protection value as "uncacheable". Note that "protection" is really a + * misnomer here as the protection value contains the memory attribute bits, dirty bits, + * and various other bits as well. */ #define pgprot_noncached(prot) __pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_UC) @@ -446,13 +453,27 @@ * for zero-mapped memory areas etc.. */ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) +extern struct page *zero_page_memmap_ptr; +#define ZERO_PAGE(vaddr) (zero_page_memmap_ptr) /* We provide our own get_unmapped_area to cope with VA holes for userland */ #define HAVE_ARCH_UNMAPPED_AREA typedef pte_t *pte_addr_t; +/* + * IA-64 doesn't have any external MMU info: the page tables contain all the necessary + * information. However, we use this routine to take care of any (delayed) i-cache + * flushing that may be necessary. + */ +extern void update_mmu_cache (struct vm_area_struct *vma, unsigned long vaddr, pte_t pte); + +# ifdef CONFIG_VIRTUAL_MEM_MAP + /* arch mem_map init routine is needed due to holes in a virtual mem_map */ +# define __HAVE_ARCH_MEMMAP_INIT + extern void memmap_init (struct page *start, unsigned long size, int nid, unsigned long zone, + unsigned long start_pfn); +# endif /* CONFIG_VIRTUAL_MEM_MAP */ # endif /* !__ASSEMBLY__ */ /* @@ -471,11 +492,14 @@ */ #define KERNEL_TR_PAGE_SHIFT _PAGE_SIZE_64M #define KERNEL_TR_PAGE_SIZE (1 << KERNEL_TR_PAGE_SHIFT) -#define KERNEL_TR_PAGE_NUM ((KERNEL_START - PAGE_OFFSET) / KERNEL_TR_PAGE_SIZE) /* * No page table caches to initialise */ #define pgtable_cache_init() do { } while (0) + +/* These tell get_user_pages() that the first gate page is accessible from user-level. */ +#define FIXADDR_USER_START GATE_ADDR +#define FIXADDR_USER_END (GATE_ADDR + 2*PAGE_SIZE) #endif /* _ASM_IA64_PGTABLE_H */ diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h --- a/include/asm-ia64/processor.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/processor.h Fri Jun 6 07:40:33 2003 @@ -17,7 +17,7 @@ #include #include -#include +#include #define IA64_NUM_DBG_REGS 8 /* @@ -87,9 +87,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -236,6 +236,7 @@ __u64 ksp; /* kernel stack pointer */ __u64 map_base; /* base address for get_unmapped_area() */ __u64 task_size; /* limit for task size */ + __u64 rbs_bot; /* the base address for the RBS */ int last_fph_cpu; /* CPU that may hold the contents of f32-f127 */ #ifdef CONFIG_IA32_SUPPORT @@ -244,8 +245,6 @@ __u64 fcr; /* IA32 floating pt control reg */ __u64 fir; /* IA32 fp except. instr. reg */ __u64 fdr; /* IA32 fp except. data reg */ - __u64 csd; /* IA32 code selector descriptor */ - __u64 ssd; /* IA32 stack selector descriptor */ __u64 old_k1; /* old value of ar.k1 */ __u64 old_iob; /* old IOBase value */ # define INIT_THREAD_IA32 .eflag = 0, \ @@ -253,28 +252,20 @@ .fcr = 0x17800000037fULL, \ .fir = 0, \ .fdr = 0, \ - .csd = 0, \ - .ssd = 0, \ .old_k1 = 0, \ .old_iob = 0, #else # define INIT_THREAD_IA32 #endif /* CONFIG_IA32_SUPPORT */ #ifdef CONFIG_PERFMON - __u64 pmc[IA64_NUM_PMC_REGS]; - __u64 pmd[IA64_NUM_PMD_REGS]; - unsigned long pfm_ovfl_block_reset;/* non-zero if we need to block or reset regs on ovfl */ - void *pfm_context; /* pointer to detailed PMU context */ - atomic_t pfm_notifiers_check; /* when >0, will cleanup ctx_notify_task in tasklist */ - atomic_t pfm_owners_check; /* when >0, will cleanup ctx_owner in tasklist */ - void *pfm_smpl_buf_list; /* list of sampling buffers to vfree */ -# define INIT_THREAD_PM .pmc = {0, }, \ - .pmd = {0, }, \ - .pfm_ovfl_block_reset = 0, \ - .pfm_context = NULL, \ - .pfm_notifiers_check = { 0 }, \ - .pfm_owners_check = { 0 }, \ - .pfm_smpl_buf_list = NULL, + __u64 pmcs[IA64_NUM_PMC_REGS]; + __u64 pmds[IA64_NUM_PMD_REGS]; + void *pfm_context; /* pointer to detailed PMU context */ + unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */ +# define INIT_THREAD_PM .pmcs = {0UL, }, \ + .pmds = {0UL, }, \ + .pfm_context = NULL, \ + .pfm_needs_checking = 0UL, #else # define INIT_THREAD_PM #endif @@ -288,8 +279,9 @@ .on_ustack = 0, \ .ksp = 0, \ .map_base = DEFAULT_MAP_BASE, \ + .rbs_bot = DEFAULT_USER_STACK_SIZE, \ .task_size = DEFAULT_TASK_SIZE, \ - .last_fph_cpu = 0, \ + .last_fph_cpu = -1, \ INIT_THREAD_IA32 \ INIT_THREAD_PM \ .dbr = {0, }, \ @@ -304,36 +296,18 @@ regs->cr_iip = new_ip; \ regs->ar_rsc = 0xf; /* eager mode, privilege level 3 */ \ regs->ar_rnat = 0; \ - regs->ar_bspstore = IA64_RBS_BOT; \ + regs->ar_bspstore = current->thread.rbs_bot; \ regs->ar_fpsr = FPSR_DEFAULT; \ regs->loadrs = 0; \ regs->r8 = current->mm->dumpable; /* set "don't zap registers" flag */ \ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \ - if (unlikely(!current->mm->dumpable)) { \ + if (unlikely(!current->mm->dumpable)) { \ /* \ * Zap scratch regs to avoid leaking bits between processes with different \ * uid/privileges. \ */ \ - regs->ar_pfs = 0; \ - regs->pr = 0; \ - /* \ - * XXX fix me: everything below can go away once we stop preserving scratch \ - * regs on a system call. \ - */ \ - regs->b6 = 0; \ - regs->r1 = 0; regs->r2 = 0; regs->r3 = 0; \ - regs->r13 = 0; regs->r14 = 0; regs->r15 = 0; \ - regs->r9 = 0; regs->r11 = 0; \ - regs->r16 = 0; regs->r17 = 0; regs->r18 = 0; regs->r19 = 0; \ - regs->r20 = 0; regs->r21 = 0; regs->r22 = 0; regs->r23 = 0; \ - regs->r24 = 0; regs->r25 = 0; regs->r26 = 0; regs->r27 = 0; \ - regs->r28 = 0; regs->r29 = 0; regs->r30 = 0; regs->r31 = 0; \ - regs->ar_ccv = 0; \ - regs->b0 = 0; regs->b7 = 0; \ - regs->f6.u.bits[0] = 0; regs->f6.u.bits[1] = 0; \ - regs->f7.u.bits[0] = 0; regs->f7.u.bits[1] = 0; \ - regs->f8.u.bits[0] = 0; regs->f8.u.bits[1] = 0; \ - regs->f9.u.bits[0] = 0; regs->f9.u.bits[1] = 0; \ + regs->ar_pfs = 0; regs->b0 = 0; regs->pr = 0; \ + regs->r1 = 0; regs->r9 = 0; regs->r11 = 0; regs->r13 = 0; regs->r15 = 0; \ } \ } while (0) @@ -346,11 +320,7 @@ * parent of DEAD_TASK has collected the exist status of the task via * wait(). */ -#ifdef CONFIG_PERFMON - extern void release_thread (struct task_struct *task); -#else -# define release_thread(dead_task) -#endif +#define release_thread(dead_task) /* Prepare to copy thread state - unlazy all lazy status */ #define prepare_to_copy(tsk) do { } while (0) @@ -369,7 +339,7 @@ * do_basic_setup() and the timing is such that free_initmem() has * been called already. */ -extern int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); +extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags); /* Get wait channel for task P. */ extern unsigned long get_wchan (struct task_struct *p); @@ -417,17 +387,28 @@ } } -static inline struct task_struct * -ia64_get_fpu_owner (void) -{ - return (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER); -} +/* + * The following three macros can't be inline functions because we don't have struct + * task_struct at this point. + */ -static inline void -ia64_set_fpu_owner (struct task_struct *t) -{ - ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) t); -} +/* Return TRUE if task T owns the fph partition of the CPU we're running on. */ +#define ia64_is_local_fpu_owner(t) \ +({ \ + struct task_struct *__ia64_islfo_task = (t); \ + (__ia64_islfo_task->thread.last_fph_cpu == smp_processor_id() \ + && __ia64_islfo_task == (struct task_struct *) ia64_get_kr(IA64_KR_FPU_OWNER)); \ +}) + +/* Mark task T as owning the fph partition of the CPU we're running on. */ +#define ia64_set_local_fpu_owner(t) do { \ + struct task_struct *__ia64_slfo_task = (t); \ + __ia64_slfo_task->thread.last_fph_cpu = smp_processor_id(); \ + ia64_set_kr(IA64_KR_FPU_OWNER, (unsigned long) __ia64_slfo_task); \ +} while (0) + +/* Mark the fph partition of task T as being invalid on all CPUs. */ +#define ia64_drop_fpu(t) ((t)->thread.last_fph_cpu = -1) extern void __ia64_init_fpu (void); extern void __ia64_save_fpu (struct ia64_fpreg *fph); @@ -636,8 +617,13 @@ asm volatile ("mov cr.lrr0=%0;; srlz.d" :: "r"(val) : "memory"); } -#define cpu_relax() barrier() +static inline void +ia64_hint_pause (void) +{ + asm volatile ("hint @pause" ::: "memory"); +} +#define cpu_relax() ia64_hint_pause() static inline void ia64_set_lrr1 (unsigned long val) @@ -916,6 +902,18 @@ __u64 result; asm ("tpa %0=%1" : "=r"(result) : "r"(addr)); return result; +} + +/* + * Take a mapped kernel address and return the equivalent address + * in the region 7 identity mapped virtual area. + */ +static inline void * +ia64_imva (void *addr) +{ + void *result; + asm ("tpa %0=%1" : "=r"(result) : "r"(addr)); + return __va(result); } #define ARCH_HAS_PREFETCH diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h --- a/include/asm-ia64/ptrace.h Thu Jun 5 23:36:40 2003 +++ b/include/asm-ia64/ptrace.h Mon Jun 16 17:15:40 2003 @@ -5,6 +5,10 @@ * Copyright (C) 1998-2003 Hewlett-Packard Co * David Mosberger-Tang * Stephane Eranian + * Copyright (C) 2003 Intel Co + * Suresh Siddha + * Fenghua Yu + * Arun Sharma * * 12/07/98 S. Eranian added pt_regs & switch_stack * 12/21/98 D. Mosberger updated to match latest code @@ -93,6 +97,16 @@ */ struct pt_regs { /* The following registers are saved by SAVE_MIN: */ + unsigned long b6; /* scratch */ + unsigned long b7; /* scratch */ + + unsigned long ar_csd; /* used by cmp8xchg16 (scratch) */ + unsigned long ar_ssd; /* reserved for future use (scratch) */ + + unsigned long r8; /* scratch (return value register 0) */ + unsigned long r9; /* scratch (return value register 1) */ + unsigned long r10; /* scratch (return value register 2) */ + unsigned long r11; /* scratch (return value register 3) */ unsigned long cr_ipsr; /* interrupted task's psr */ unsigned long cr_iip; /* interrupted task's instruction pointer */ @@ -106,24 +120,23 @@ unsigned long ar_bspstore; /* RSE bspstore */ unsigned long pr; /* 64 predicate registers (1 bit each) */ - unsigned long b6; /* scratch */ + unsigned long b0; /* return pointer (bp) */ unsigned long loadrs; /* size of dirty partition << 16 */ unsigned long r1; /* the gp pointer */ - unsigned long r2; /* scratch */ - unsigned long r3; /* scratch */ unsigned long r12; /* interrupted task's memory stack pointer */ unsigned long r13; /* thread pointer */ - unsigned long r14; /* scratch */ + + unsigned long ar_fpsr; /* floating point status (preserved) */ unsigned long r15; /* scratch */ - unsigned long r8; /* scratch (return value register 0) */ - unsigned long r9; /* scratch (return value register 1) */ - unsigned long r10; /* scratch (return value register 2) */ - unsigned long r11; /* scratch (return value register 3) */ + /* The remaining registers are NOT saved for system calls. */ - /* The following registers are saved by SAVE_REST: */ + unsigned long r14; /* scratch */ + unsigned long r2; /* scratch */ + unsigned long r3; /* scratch */ + /* The following registers are saved by SAVE_REST: */ unsigned long r16; /* scratch */ unsigned long r17; /* scratch */ unsigned long r18; /* scratch */ @@ -142,18 +155,16 @@ unsigned long r31; /* scratch */ unsigned long ar_ccv; /* compare/exchange value (scratch) */ - unsigned long ar_fpsr; /* floating point status (preserved) */ - unsigned long b0; /* return pointer (bp) */ - unsigned long b7; /* scratch */ /* - * Floating point registers that the kernel considers - * scratch: + * Floating point registers that the kernel considers scratch: */ struct ia64_fpreg f6; /* scratch */ struct ia64_fpreg f7; /* scratch */ struct ia64_fpreg f8; /* scratch */ struct ia64_fpreg f9; /* scratch */ + struct ia64_fpreg f10; /* scratch */ + struct ia64_fpreg f11; /* scratch */ }; /* @@ -170,8 +181,6 @@ struct ia64_fpreg f4; /* preserved */ struct ia64_fpreg f5; /* preserved */ - struct ia64_fpreg f10; /* scratch, but untouched by kernel */ - struct ia64_fpreg f11; /* scratch, but untouched by kernel */ struct ia64_fpreg f12; /* scratch, but untouched by kernel */ struct ia64_fpreg f13; /* scratch, but untouched by kernel */ struct ia64_fpreg f14; /* scratch, but untouched by kernel */ @@ -226,6 +235,20 @@ !user_mode(_regs) && user_stack(_task, _regs); \ }) + /* + * System call handlers that, upon successful completion, need to return a negative value + * should call force_successful_syscall_return() right before returning. On architectures + * where the syscall convention provides for a separate error flag (e.g., alpha, ia64, + * ppc{,64}, sparc{,64}, possibly others), this macro can be used to ensure that the error + * flag will not get set. On architectures which do not support a separate error flag, + * the macro is a no-op and the spurious error condition needs to be filtered out by some + * other means (e.g., in user-level, by passing an extra argument to the syscall handler, + * or something along those lines). + * + * On ia64, we can clear the user's pt_regs->r8 to force a successful syscall. + */ +# define force_successful_syscall_return() (ia64_task_regs(current)->r8 = 0) + struct task_struct; /* forward decl */ struct unw_frame_info; /* forward decl */ @@ -249,11 +272,6 @@ extern void ia64_increment_ip (struct pt_regs *pt); extern void ia64_decrement_ip (struct pt_regs *pt); - -#define force_successful_syscall_return() \ - do { \ - ia64_task_regs(current)->r8 = 0; \ - } while (0) #endif /* !__KERNEL__ */ diff -Nru a/include/asm-ia64/ptrace_offsets.h b/include/asm-ia64/ptrace_offsets.h --- a/include/asm-ia64/ptrace_offsets.h Mon Feb 4 23:43:07 2002 +++ b/include/asm-ia64/ptrace_offsets.h Wed May 28 02:03:26 2003 @@ -2,8 +2,8 @@ #define _ASM_IA64_PTRACE_OFFSETS_H /* - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang + * Copyright (C) 1999, 2003 Hewlett-Packard Co + * David Mosberger-Tang */ /* * The "uarea" that can be accessed via PEEKUSER and POKEUSER is a @@ -11,9 +11,59 @@ * * struct uarea { * struct ia64_fpreg fph[96]; // f32-f127 - * struct switch_stack sw; - * struct pt_regs pt; - * unsigned long rsvd1[712]; + * unsigned long nat_bits; + * unsigned long empty1; + * struct ia64_fpreg f2; // f2-f5 + * : + * struct ia64_fpreg f5; + * struct ia64_fpreg f10; // f10-f31 + * : + * struct ia64_fpreg f31; + * unsigned long r4; // r4-r7 + * : + * unsigned long r7; + * unsigned long b1; // b1-b5 + * : + * unsigned long b5; + * unsigned long ar_ec; + * unsigned long ar_lc; + * unsigned long empty2[5]; + * unsigned long cr_ipsr; + * unsigned long cr_iip; + * unsigned long cfm; + * unsigned long ar_unat; + * unsigned long ar_pfs; + * unsigned long ar_rsc; + * unsigned long ar_rnat; + * unsigned long ar_bspstore; + * unsigned long pr; + * unsigned long b6; + * unsigned long ar_bsp; + * unsigned long r1; + * unsigned long r2; + * unsigned long r3; + * unsigned long r12; + * unsigned long r13; + * unsigned long r14; + * unsigned long r15; + * unsigned long r8; + * unsigned long r9; + * unsigned long r10; + * unsigned long r11; + * unsigned long r16; + * : + * unsigned long r31; + * unsigned long ar_ccv; + * unsigned long ar_fpsr; + * unsigned long b0; + * unsigned long b7; + * unsigned long f6; + * unsigned long f7; + * unsigned long f8; + * unsigned long f9; + * unsigned long ar_csd; + * unsigned long ar_ssd; + * unsigned long rsvd1[710]; * unsigned long dbr[8]; * unsigned long rsvd2[504]; * unsigned long ibr[8]; @@ -119,7 +169,7 @@ #define PT_F125 0x05d0 #define PT_F126 0x05e0 #define PT_F127 0x05f0 -/* switch stack: */ + #define PT_NAT_BITS 0x0600 #define PT_F2 0x0610 @@ -162,7 +212,6 @@ #define PT_AR_EC 0x0800 #define PT_AR_LC 0x0808 -/* pt_regs */ #define PT_CR_IPSR 0x0830 #define PT_CR_IIP 0x0838 #define PT_CFM 0x0840 @@ -209,6 +258,8 @@ #define PT_F7 0x0990 #define PT_F8 0x09a0 #define PT_F9 0x09b0 +#define PT_AR_CSD 0x09c0 +#define PT_AR_SSD 0x09c8 #define PT_DBR 0x2000 /* data breakpoint registers */ #define PT_IBR 0x3000 /* instruction breakpoint registers */ diff -Nru a/include/asm-ia64/resource.h b/include/asm-ia64/resource.h --- a/include/asm-ia64/resource.h Tue Feb 5 09:39:54 2002 +++ b/include/asm-ia64/resource.h Wed Jun 4 05:30:36 2003 @@ -8,6 +8,8 @@ * Copyright (C) 1998, 1999 David Mosberger-Tang */ +#include + #define RLIMIT_CPU 0 /* CPU time in ms */ #define RLIMIT_FSIZE 1 /* Maximum filesize */ #define RLIMIT_DATA 2 /* max data size */ @@ -35,7 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ - { _STK_LIM, RLIM_INFINITY }, \ + { _STK_LIM, DEFAULT_USER_STACK_SIZE }, \ { 0, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h Tue Apr 22 19:47:07 2003 +++ b/include/asm-ia64/sal.h Tue May 13 03:47:02 2003 @@ -23,6 +23,18 @@ * (plus examples of platform error info structures from smariset @ Intel) */ +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT 0 +#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT 1 +#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT 2 +#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT 3 + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1< #include @@ -162,11 +174,6 @@ u8 oem_reserved[8]; } ia64_sal_desc_memory_t; -#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1 << 0) -#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT (1 << 1) -#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT (1 << 2) -#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT (1 << 3) - typedef struct ia64_sal_desc_platform_feature { u8 type; u8 feature_mask; @@ -789,5 +796,7 @@ } extern unsigned long sal_platform_features; + +#endif /* __ASSEMBLY__ */ #endif /* _ASM_IA64_PAL_H */ diff -Nru a/include/asm-ia64/sigcontext.h b/include/asm-ia64/sigcontext.h --- a/include/asm-ia64/sigcontext.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sigcontext.h Wed May 21 19:48:56 2003 @@ -56,7 +56,7 @@ unsigned long sc_rbs_base; /* NULL or new base of sighandler's rbs */ unsigned long sc_loadrs; /* see description above */ - unsigned long sc_ar25; /* rsvd for scratch use */ + unsigned long sc_ar25; /* cmp8xchg16 uses this */ unsigned long sc_ar26; /* rsvd for scratch use */ unsigned long sc_rsvd[12]; /* reserved for future use */ /* diff -Nru a/include/asm-ia64/siginfo.h b/include/asm-ia64/siginfo.h --- a/include/asm-ia64/siginfo.h Thu Mar 6 21:11:46 2003 +++ b/include/asm-ia64/siginfo.h Fri Jun 6 07:20:51 2003 @@ -69,13 +69,6 @@ long _band; /* POLL_IN, POLL_OUT, POLL_MSG (XPG requires a "long") */ int _fd; } _sigpoll; - - /* SIGPROF */ - struct { - pid_t _pid; /* which child */ - uid_t _uid; /* sender's uid */ - unsigned long _pfm_ovfl_counters[4]; /* which PMU counter overflowed */ - } _sigprof; } _sifields; } siginfo_t; @@ -95,14 +88,6 @@ #define __ISR_VALID (1 << __ISR_VALID_BIT) /* - * si_code values - * Positive values for kernel-generated signals. - */ -#ifdef __KERNEL__ -#define __SI_PROF (6 << 16) -#endif - -/* * SIGILL si_codes */ #define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ @@ -137,11 +122,6 @@ #undef NSIGTRAP #define NSIGTRAP 4 -/* - * SIGPROF si_codes - */ -#define PROF_OVFL (__SI_PROF|1) /* some counters overflowed */ - #ifdef __KERNEL__ #include @@ -151,8 +131,8 @@ if (from->si_code < 0) memcpy(to, from, sizeof(siginfo_t)); else - /* _sigprof is currently the largest know union member */ - memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigprof)); + /* _sigchld is currently the largest know union member */ + memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld)); } extern int copy_siginfo_from_user(siginfo_t *to, siginfo_t *from); diff -Nru a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h --- a/include/asm-ia64/sn/addrs.h Mon May 12 18:59:24 2003 +++ b/include/asm-ia64/sn/addrs.h Mon Jun 16 17:15:40 2003 @@ -1,26 +1,17 @@ - /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992-1999,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1999,2001-2003 Silicon Graphics, Inc. All rights reserved. */ - #ifndef _ASM_IA64_SN_ADDRS_H #define _ASM_IA64_SN_ADDRS_H #include -#if defined (CONFIG_IA64_SGI_SN1) -#include -#elif defined (CONFIG_IA64_SGI_SN2) #include -#else -#error <<>> -#endif /* !SN1 && !SN2 */ #ifndef __ASSEMBLY__ #include @@ -30,11 +21,7 @@ #define PS_UINT_CAST (__psunsigned_t) #define UINT64_CAST (uint64_t) -#ifdef CONFIG_IA64_SGI_SN2 #define HUBREG_CAST (volatile mmr_t *) -#else -#define HUBREG_CAST (volatile hubreg_t *) -#endif #elif __ASSEMBLY__ @@ -52,11 +39,7 @@ * node's address space. */ -#ifdef CONFIG_IA64_SGI_SN2 /* SN2 has an extra AS field between node offset and node id (nasid) */ #define NODE_OFFSET(_n) (UINT64_CAST (_n) << NASID_SHFT) -#else -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#endif #define NODE_CAC_BASE(_n) (CAC_BASE + NODE_OFFSET(_n)) #define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) @@ -83,7 +66,7 @@ */ #define SWIN_SIZE_BITS 24 -#define SWIN_SIZE (UINT64_CAST 1 << 24) +#define SWIN_SIZE (1UL<<24) #define SWIN_SIZEMASK (SWIN_SIZE - 1) #define SWIN_WIDGET_MASK 0xF @@ -119,44 +102,13 @@ * references to the local hub's registers. */ -#if defined CONFIG_IA64_SGI_SN1 -#define LREG_BASE (HSPEC_BASE + 0x10000000) -#define LREG_SIZE 0x8000000 /* 128 MB */ -#define LREG_LIMIT (LREG_BASE + LREG_SIZE) -#define LBOOT_BASE (LREG_LIMIT) -#define LBOOT_SIZE 0x8000000 /* 128 MB */ -#define LBOOT_LIMIT (LBOOT_BASE + LBOOT_SIZE) -#define LBOOT_STRIDE 0x2000000 /* two PROMs, on 32M boundaries */ -#endif - #define HUB_REGISTER_WIDGET 1 -#ifdef CONFIG_IA64_SGI_SN2 #define IALIAS_BASE LOCAL_SWIN_BASE(HUB_REGISTER_WIDGET) -#else -#define IALIAS_BASE NODE_SWIN_BASE(0, HUB_REGISTER_WIDGET) -#endif #define IALIAS_SIZE 0x800000 /* 8 Megabytes */ #define IS_IALIAS(_a) (((_a) >= IALIAS_BASE) && \ ((_a) < (IALIAS_BASE + IALIAS_SIZE))) /* - * Macro for referring to Hub's RBOOT space - */ - -#if defined CONFIG_IA64_SGI_SN1 - -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define NODE_LREG_LIMIT(_n) (NODE_LREG_BASE(_n) + LREG_SIZE) -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) -#define RREG_LIMIT(_n) (NODE_LREG_LIMIT(_n)) -#define RBOOT_SIZE 0x8000000 /* 128 Megabytes */ -#define NODE_RBOOT_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x38000000) -#define NODE_RBOOT_LIMIT(_n) (NODE_RBOOT_BASE(_n) + RBOOT_SIZE) - -#endif - - -/* * The following macros produce the correct base virtual address for * the hub registers. The LOCAL_HUB_* macros produce the appropriate * address for the local registers. The REMOTE_HUB_* macro produce @@ -166,11 +118,10 @@ */ -#ifdef CONFIG_IA64_SGI_SN2 /* - * SN2 has II mmr's located inside small window space like SN0 & SN1, - * but has all other non-II mmr's located at the top of big window - * space, unlike SN0 & SN1. + * SN2 has II mmr's located inside small window space. + * As all other non-II mmr's located at the top of big window + * space. */ #define LOCAL_HUB_BASE(_x) (LOCAL_MMR_ADDR(_x) | (((~(_x)) & BWIN_TOP)>>8)) #define REMOTE_HUB_BASE(_x) \ @@ -182,18 +133,6 @@ #define REMOTE_HUB(_n, _x) \ (HUBREG_CAST (REMOTE_HUB_BASE(_x) | ((((long)(_n))<offset -#else -#define KLCONFIG_OFFSET(nasid) \ - ia64_sn_get_klconfig_addr(nasid) -#endif /* CONFIG_IA64_SGI_SN2 */ +#define KLCONFIG_OFFSET(nasid) ia64_sn_get_klconfig_addr(nasid) #define KLCONFIG_ADDR(nasid) \ TO_NODE_CAC((nasid), KLCONFIG_OFFSET(nasid)) diff -Nru a/include/asm-ia64/sn/alenlist.h b/include/asm-ia64/sn/alenlist.h --- a/include/asm-ia64/sn/alenlist.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/alenlist.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ALENLIST_H #define _ASM_IA64_SN_ALENLIST_H diff -Nru a/include/asm-ia64/sn/arc/hinv.h b/include/asm-ia64/sn/arc/hinv.h --- a/include/asm-ia64/sn/arc/hinv.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/arc/hinv.h Fri May 16 04:18:17 2003 @@ -1,12 +1,10 @@ /* - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ - /* $Id$ * diff -Nru a/include/asm-ia64/sn/arc/types.h b/include/asm-ia64/sn/arc/types.h --- a/include/asm-ia64/sn/arc/types.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/arc/types.h Fri May 16 04:18:18 2003 @@ -3,8 +3,8 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * + * Copyright (c) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright 1999 Ralf Baechle (ralf@gnu.org) - * Copyright 1999,2001 Silicon Graphics, Inc. */ #ifndef _ASM_SN_ARC_TYPES_H #define _ASM_SN_ARC_TYPES_H diff -Nru a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h --- a/include/asm-ia64/sn/arch.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/arch.h Fri May 16 04:18:17 2003 @@ -6,7 +6,7 @@ * * SGI specific setup. * - * Copyright (C) 1995-1997,1999,2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1995-1997,1999,2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) */ #ifndef _ASM_IA64_SN_ARCH_H @@ -17,23 +17,12 @@ #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif - -#if defined(CONFIG_IA64_SGI_SN1) -typedef u64 bdrkreg_t; -#elif defined(CONFIG_IA64_SGI_SN2) typedef u64 shubreg_t; -#endif - typedef u64 hubreg_t; typedef u64 mmr_t; typedef u64 nic_t; -typedef char cnodeid_t; #define CNODE_TO_CPU_BASE(_cnode) (NODEPDA(_cnode)->node_first_cpu) diff -Nru a/include/asm-ia64/sn/ate_utils.h b/include/asm-ia64/sn/ate_utils.h --- a/include/asm-ia64/sn/ate_utils.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/ate_utils.h Fri May 16 04:18:18 2003 @@ -7,7 +7,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* diff -Nru a/include/asm-ia64/sn/bte.h b/include/asm-ia64/sn/bte.h --- a/include/asm-ia64/sn/bte.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/bte.h Fri May 16 04:18:18 2003 @@ -1,7 +1,7 @@ /* * * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -36,11 +36,28 @@ #ifndef _ASM_IA64_SN_BTE_H #define _ASM_IA64_SN_BTE_H -#ident "$Revision: 1.1 $" - +#include #include #include #include +#include + + +/* #define BTE_DEBUG */ +/* #define BTE_DEBUG_VERBOSE */ + +#ifdef BTE_DEBUG +# define BTE_PRINTK(x) printk x /* Terse */ +# ifdef BTE_DEBUG_VERBOSE +# define BTE_PRINTKV(x) printk x /* Verbose */ +# else +# define BTE_PRINTKV(x) +# endif /* BTE_DEBUG_VERBOSE */ +#else +# define BTE_PRINTK(x) +# define BTE_PRINTKV(x) +#endif /* BTE_DEBUG */ + /* BTE status register only supports 16 bits for length field */ #define BTE_LEN_BITS (16) @@ -48,40 +65,60 @@ #define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES) -/* - * Constants used in determining the best and worst case transfer - * times. To help explain the two, the following graph of transfer - * status vs time may help. - * - * active +------------------:-+ : - * status | : | : - * idle +__________________:_+======= - * 0 Time MaxT MinT - * - * Therefore, MaxT is the maximum thoeretical rate for transfering - * the request block (assuming ideal circumstances) - * - * MinT is the minimum theoretical rate for transferring the - * requested block (assuming maximum link distance and contention) - * - * The following defines are the inverse of the above. They are - * used for calculating the MaxT time and MinT time given the - * number of lines in the transfer. - */ -#define BTE_MAXT_LINES_PER_SECOND 800 -#define BTE_MINT_LINES_PER_SECOND 600 - - /* Define hardware */ #define BTES_PER_NODE 2 + /* Define hardware modes */ #define BTE_NOTIFY (IBCT_NOTIFY) #define BTE_NORMAL BTE_NOTIFY #define BTE_ZERO_FILL (BTE_NOTIFY | IBCT_ZFIL_MODE) - /* Use a reserved bit to let the caller specify a wait for any BTE */ #define BTE_WACQUIRE (0x4000) +/* macro to force the IBCT0 value valid */ +#define BTE_VALID_MODE(x) ((x) & (IBCT_NOTIFY | IBCT_ZFIL_MODE)) + + +/* + * Handle locking of the bte interfaces. + * + * All transfers spinlock the interface before setting up the SHUB + * registers. Sync transfers hold the lock until all processing is + * complete. Async transfers release the lock as soon as the transfer + * is initiated. + * + * To determine if an interface is available, we must check both the + * busy bit and the spinlock for that interface. + */ +#define BTE_LOCK_IF_AVAIL(_x) (\ + (*pda->cpu_bte_if[_x]->most_rcnt_na & (IBLS_BUSY | IBLS_ERROR)) && \ + (!(spin_trylock(&(pda->cpu_bte_if[_x]->spinlock)))) \ + ) + +/* + * Some macros to simplify reading. + * Start with macros to locate the BTE control registers. + */ +#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) +#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) +#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) +#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) +#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) + + +/* Possible results from bte_copy and bte_unaligned_copy */ +typedef enum { + BTE_SUCCESS, /* 0 is success */ + BTEFAIL_NOTAVAIL, /* BTE not available */ + BTEFAIL_POISON, /* poison page */ + BTEFAIL_PROT, /* Protection violation */ + BTEFAIL_ACCESS, /* access error */ + BTEFAIL_TOUT, /* Time out */ + BTEFAIL_XTERR, /* Diretory error */ + BTEFAIL_DIR, /* Diretory error */ + BTEFAIL_ERROR, /* Generic error */ +} bte_result_t; + /* * Structure defining a bte. An instance of this @@ -90,28 +127,41 @@ * This structure contains everything necessary * to work with a BTE. */ -typedef struct bteinfo_s { +struct bteinfo_s { u64 volatile notify ____cacheline_aligned; char *bte_base_addr ____cacheline_aligned; spinlock_t spinlock; - u64 ideal_xfr_tmo; /* Time out */ - u64 ideal_xfr_tmo_cnt; - /* u64 most_recent_src; - * u64 most_recent_dest; - * u64 most_recent_len; - * u64 most_recent_mode; */ + cnodeid_t bte_cnode; /* cnode */ + int bte_error_count; /* Number of errors encountered */ + int bte_num; /* 0 --> BTE0, 1 --> BTE1 */ + int cleanup_active; /* Interface is locked for cleanup */ + volatile bte_result_t bh_error; /* error while processing */ u64 volatile *most_rcnt_na; - void *bte_test_buf; -} bteinfo_t; + void *scratch_buf; /* Node local scratch buffer */ +}; -/* Possible results from bte_copy and bte_unaligned_copy */ -typedef enum { - BTE_SUCCESS, /* 0 is success */ - BTEFAIL_NOTAVAIL, /* BTE not available */ - BTEFAIL_ERROR, /* Generic error */ - BTEFAIL_DIR /* Diretory error */ -} bte_result_t; -void bte_reset_nasid(nasid_t); +/* + * Function prototypes (functions defined in bte.c, used elsewhere) + */ +extern bte_result_t bte_copy(u64, u64, u64, u64, void *); +extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); +extern void bte_error_handler(unsigned long); + + +/* + * The following is the prefered way of calling bte_unaligned_copy + * If the copy is fully cache line aligned, then bte_copy is + * used instead. Since bte_copy is inlined, this saves a call + * stack. NOTE: bte_copy is called synchronously and does block + * until the transfer is complete. In order to get the asynch + * version of bte_copy, you must perform this check yourself. + */ +#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ + (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ + (dest & L1_CACHE_MASK)) ? \ + bte_unaligned_copy(src, dest, len, mode) : \ + bte_copy(src, dest, len, mode, NULL)) + -#endif /* _ASM_IA64_SN_BTE_H */ +#endif /* _ASM_IA64_SN_BTE_H */ diff -Nru a/include/asm-ia64/sn/bte_copy.h b/include/asm-ia64/sn/bte_copy.h --- a/include/asm-ia64/sn/bte_copy.h Tue Dec 3 10:07:32 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,385 +0,0 @@ -/* - * - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#ifndef _ASM_IA64_SN_BTE_COPY_H -#define _ASM_IA64_SN_BTE_COPY_H - -#ident "$Revision: 1.1 $" - -#include -#include -#include -#include -#include -#include - -#define L1_CACHE_MASK (L1_CACHE_BYTES - 1) - -/* - * BTE_LOCKING support - When CONFIG_IA64_SGI_BTE_LOCKING is - * not defined, the bte_copy code supports one bte per cpu in - * synchronous mode. Even if bte_copy is called with a - * notify address, the bte will spin and wait for the transfer - * to complete. By defining the following, spin_locks and - * busy checks are placed around the initiation of a BTE - * transfer and multiple bte's per cpu are supported. - */ -#if 0 -#define CONFIG_IA64_SGI_BTE_LOCKING 1 -#endif - -/* - * Handle locking of the bte interfaces. - * - * All transfers spinlock the interface before setting up the SHUB - * registers. Sync transfers hold the lock until all processing is - * complete. Async transfers release the lock as soon as the transfer - * is initiated. - * - * To determine if an interface is available, we must check both the - * busy bit and the spinlock for that interface. - */ -#define BTE_LOCK_IF_AVAIL(_x) (\ - (*pda.cpu_bte_if[_x]->most_rcnt_na & IBLS_BUSY) && \ - (!(spin_trylock(&(pda.cpu_bte_if[_x]->spinlock)))) \ - ) - -/* - * Some macros to simplify reading. - * - * Start with macros to locate the BTE control registers. - */ - -#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr)) -#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC)) -#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST)) -#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL)) -#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY)) - -/* Some macros to force the IBCT0 value valid. */ - -#define BTE_VALID_MODES BTE_NOTIFY -#define BTE_VLD_MODE(x) (x & BTE_VALID_MODES) - -// #define BTE_DEBUG -// #define BTE_DEBUG_VERBOSE -// #define BTE_TIME - -#ifdef BTE_DEBUG -# define BTE_PRINTK(x) printk x /* Terse */ -# ifdef BTE_DEBUG_VERBOSE -# define BTE_PRINTKV(x) printk x /* Verbose */ -# else -# define BTE_PRINTKV(x) -# endif /* BTE_DEBUG_VERBOSE */ -#else -# define BTE_PRINTK(x) -# define BTE_PRINTKV(x) -#endif /* BTE_DEBUG */ - -#define BTE_IDEAL_TMO(x) (jiffies + \ - (HZ / BTE_MAXT_LINES_PER_SECOND * x)) - -#ifdef BTE_TIME -volatile extern u64 bte_setup_time; -volatile extern u64 bte_transfer_time; -volatile extern u64 bte_tear_down_time; -volatile extern u64 bte_execute_time; - -#define BTE_TIME_DECLARE() \ - u64 btcp_strt_tm = 0; \ - u64 btcp_cplt_tm = 0; \ - u64 xfr_strt_tm = 0; \ - u64 xfr_cplt_tm = 0; \ - -#define BTE_TIME_START() \ - btcp_strt_tm = xfr_strt_tm = xfr_cplt_tm = ia64_get_itc(); - -#define BTE_TIME_XFR_START() \ - xfr_strt_tm = ia64_get_itc(); - -#define BTE_TIME_XFR_STOP() \ - xfr_cplt_tm = ia64_get_itc(); - -#define BTE_TIME_STOP() \ - btcp_cplt_tm = ia64_get_itc(); \ - bte_setup_time = xfr_strt_tm - btcp_strt_tm; \ - bte_transfer_time = xfr_cplt_tm - xfr_strt_tm; \ - bte_tear_down_time = btcp_cplt_tm - xfr_cplt_tm; \ - bte_execute_time = btcp_cplt_tm - btcp_strt_tm; \ - -#else /* BTE_TIME */ -#define BTE_TIME_DECLARE() -#define BTE_TIME_START() -#define BTE_TIME_XFR_START() -#define BTE_TIME_XFR_STOP() -#define BTE_TIME_STOP() -#endif /* BTE_TIME */ - -/* - * bte_copy(src, dest, len, mode, notification) - * - * use the block transfer engine to move kernel - * memory from src to dest using the assigned mode. - * - * Paramaters: - * src - physical address of the transfer source. - * dest - physical address of the transfer destination. - * len - number of bytes to transfer from source to dest. - * mode - hardware defined. See reference information - * for IBCT0/1 in the SHUB Programmers Reference - * notification - kernel virtual address of the notification cache - * line. If NULL, the default is used and - * the bte_copy is synchronous. - * - * NOTE: This function requires src, dest, and len to - * be cache line aligned. - */ -extern __inline__ bte_result_t -bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification) -{ -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - int bte_to_use; -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - u64 transfer_size; - u64 lines_remaining; - bteinfo_t *bte; - BTE_TIME_DECLARE(); - - BTE_TIME_START(); - - BTE_PRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", - src, dest, len, mode, notification)); - - if (len == 0) { - BTE_TIME_STOP(); - return (BTE_SUCCESS); - } - - ASSERT(!((len & L1_CACHE_MASK) || - (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK))); - - ASSERT(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)); - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - { - bte_to_use = 0; - - /* Attempt to lock one of the BTE interfaces */ - while ((bte_to_use < BTES_PER_NODE) && - BTE_LOCK_IF_AVAIL(bte_to_use)) { - - bte_to_use++; - } - - if ((bte_to_use >= BTES_PER_NODE) && - !(mode & BTE_WACQUIRE)) { - BTE_TIME_STOP(); - return (BTEFAIL_NOTAVAIL); - } - - /* Wait until a bte is available. */ - } - while (bte_to_use >= BTES_PER_NODE); - - bte = pda.cpu_bte_if[bte_to_use]; - BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use)); -#else - /* Assuming one BTE per CPU. */ - bte = pda->cpu_bte_if[0]; -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - - /* - * The following are removed for optimization but is - * available in the event that the SHUB exhibits - * notification problems similar to the hub, bedrock et al. - * - * bte->mostRecentSrc = src; - * bte->mostRecentDest = dest; - * bte->mostRecentLen = len; - * bte->mostRecentMode = mode; - */ - if (notification == NULL) { - /* User does not want to be notified. */ - bte->most_rcnt_na = &bte->notify; - } else { - bte->most_rcnt_na = notification; - } - - /* Calculate the number of cache lines to transfer. */ - transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK); - - BTE_PRINTKV(("Calculated transfer size of %d cache lines\n", - transfer_size)); - - /* Initialize the notification to a known value. */ - *bte->most_rcnt_na = -1L; - - - BTE_PRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - /* Set the status reg busy bit and transfer length */ - BTE_PRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n", - BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size)); - HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size)); - - /* Set the source and destination registers */ - BTE_PRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SRC_ADDR, - (TO_PHYS(src)))); - HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src))); - BTE_PRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, - (TO_PHYS(dest)))); - HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest))); - - /* Set the notification register */ - BTE_PRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR, - (TO_PHYS(__pa(bte->most_rcnt_na))))); - HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(__pa(bte->most_rcnt_na)))); - - /* Initiate the transfer */ - BTE_PRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode)); - BTE_TIME_XFR_START(); - HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode)); - - BTE_PRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - if (notification == NULL) { - /* - * Calculate our timeout - * - * What are we doing here? We are trying to determine - * the fastest time the BTE could have transfered our - * block of data. By takine the clock frequency (ticks/sec) - * divided by the BTE MaxT Transfer Rate (lines/sec) - * times the transfer size (lines), we get a tick - * offset from current time that the transfer should - * complete. - * - * Why do this? We are watching for a notification - * failure from the BTE. This behaviour has been - * seen in the SN0 and SN1 hardware on rare circumstances - * and is expected in SN2. By checking at the - * ideal transfer timeout, we minimize our time - * delay from hardware completing our request and - * our detecting the failure. - */ - bte->ideal_xfr_tmo = BTE_IDEAL_TMO(transfer_size); - - while (bte->notify == -1UL) { - /* - * Notification Workaround: When the max - * theoretical time has elapsed, read the hub - * status register into the notification area. - * This fakes the shub performing the copy. - */ - BTE_PRINTKV((" Timing. IBLS = 0x%lx, " - "notify= 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - if (time_after(jiffies, bte->ideal_xfr_tmo)) { - lines_remaining = HUB_L(BTEREG_LNSTAT_ADDR) & - BTE_LEN_MASK; - bte->ideal_xfr_tmo_cnt++; - bte->ideal_xfr_tmo = - BTE_IDEAL_TMO(lines_remaining); - - BTE_PRINTKV((" Timeout. cpu %d " - "IBLS = 0x%lx, " - "notify= 0x%lx, " - "Lines remaining = %d. " - "New timeout = %d.\n", - smp_processor_id(), - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify, - lines_remaining, - bte->ideal_xfr_tmo)); - } - } - BTE_PRINTKV((" Delay Done. IBLS = 0x%lx, notify= 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - BTE_TIME_XFR_STOP(); - if (bte->notify & IBLS_ERROR) { - /* >>> Need to do real error checking. */ - transfer_size = 0; - -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - BTE_PRINTKV(("Erroring status is 0x%lx and " - "notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - bte->notify)); - - BTE_TIME_STOP(); - bte->notify = 0L; - return (BTEFAIL_ERROR); - } - - } -#ifdef CONFIG_IA64_SGI_BTE_LOCKING - spin_unlock(&(bte->spinlock)); -#endif /* CONFIG_IA64_SGI_BTE_LOCKING */ - BTE_TIME_STOP(); - BTE_PRINTKV(("Returning status is 0x%lx and notify is 0x%lx\n", - HUB_L(BTEREG_LNSTAT_ADDR), - *bte->most_rcnt_na)); - - return (BTE_SUCCESS); -} - -/* - * Define the bte_unaligned_copy as an extern. - */ -extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64); - -/* - * The following is the prefered way of calling bte_unaligned_copy - * If the copy is fully cache line aligned, then bte_copy is - * used instead. Since bte_copy is inlined, this saves a call - * stack. NOTE: bte_copy is called synchronously and does block - * until the transfer is complete. In order to get the asynch - * version of bte_copy, you must perform this check yourself. - */ -#define BTE_UNALIGNED_COPY(src, dest, len, mode) \ - (((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) || \ - (dest & L1_CACHE_MASK)) ? \ - bte_unaligned_copy(src, dest, len, mode) : \ - bte_copy(src, dest, len, mode, NULL)) - -#endif /* _ASM_IA64_SN_BTE_COPY_H */ diff -Nru a/include/asm-ia64/sn/cdl.h b/include/asm-ia64/sn/cdl.h --- a/include/asm-ia64/sn/cdl.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/cdl.h Fri May 16 04:18:18 2003 @@ -4,13 +4,20 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_CDL_H #define _ASM_IA64_SN_CDL_H #include +struct cdl { + int part_num; /* Part part number */ + int mfg_num; /* Part MFG number */ + int (*attach)(vertex_hdl_t); /* Attach routine */ +}; + + /* * cdl: connection/driver list * @@ -21,175 +28,14 @@ typedef struct cdl *cdl_p; /* - * cdl_itr_f is the type for the functions - * that are handled by cdl_iterate. - */ - -typedef void -cdl_iter_f (devfs_handle_t vhdl); - -/* - * cdl_drv_f is the type for the functions - * that are called by cdl_add_driver and - * cdl_del_driver. - */ - -typedef void -cdl_drv_f (devfs_handle_t vhdl, int key1, int key2, int error); - -/* - * If CDL_PRI_HI is specified in the flags - * parameter for cdl_add_driver, then that driver's - * attach routine will be called for future connect - * points before any (non-CDL_PRI_HI) drivers. - * - * The IOC3 driver uses this facility to make sure - * that the ioc3_attach() function is called before - * the attach routines of any subdevices. - * - * Drivers for bridge-based crosstalk cards that - * are almost but not quite generic can use it to - * arrange that their attach() functions get called - * before the generic bridge drivers, so they can - * leave behind "hint" structures that will - * properly configure the generic driver. - */ -#define CDL_PRI_HI 0x0001 - -/* - * cdl_new: construct a new connection/driver list - * - * Called once for each "kind" of bus. Returns an - * opaque cookie representing the particular list - * that will be operated on by the other calls. - */ -extern cdl_p cdl_new(char *, char *, char *); - -/* - * cdl_del: destroy a connection/driver list. - * - * Releases all dynamically allocated resources - * associated with the specified list. Forgets what - * drivers might be involved in this kind of bus, - * forgets what connection points have been noticed - * on this kind of bus. - */ -extern void cdl_del(cdl_p reg); - -/* - * cdl_add_driver: register a device driver - * - * Calls the driver's attach routine with all - * connection points on the list that have the same - * key information as the driver; call-back the - * specified function to notify the driver of the - * attach status for each device. Place the driver - * on the list so that any connection points - * discovered in the future that match the driver - * can be handed off to the driver's attach - * routine. - * - * CDL_PRI_HI may be specified (see above). - */ - -extern int cdl_add_driver(cdl_p reg, - int key1, - int key2, - char *prefix, - int flags, - cdl_drv_f *func); - -/* - * cdl_del_driver: remove a device driver - * - * Calls the driver's detach routine with all - * connection points on the list that match the - * driver; call-back the specified function to - * notify the driver of the detach status for each - * device. Then forget about the driver. Future - * calls to cdl_add_connpt with connections that - * would match this driver no longer trigger calls - * to the driver's attach routine. - * - * NOTE: Yes, I said CONNECTION POINTS, not - * verticies that the driver has been attached to - * with hwgraph_driver_add(); this gives the driver - * a chance to clean up anything it did to the - * connection point in its attach routine. Also, - * this is done whether or not the attach routine - * was successful. - */ -extern void cdl_del_driver(cdl_p reg, - char *prefix, - cdl_drv_f *func); - -/* * cdl_add_connpt: add a connection point * * Calls the attach routines of all the drivers on * the list that match this connection point, in - * the order that they were added to the list, - * except that CDL_PRI_HI drivers are called first. - * - * Then the vertex is added to the list, so it can - * be presented to any matching drivers that may be - * subsequently added to the list. + * the order that they were added to the list. */ -extern int cdl_add_connpt(cdl_p reg, - int key1, +extern int cdl_add_connpt(int key1, int key2, - devfs_handle_t conn, + vertex_hdl_t conn, int drv_flags); - -/* - * cdl_del_connpt: delete a connection point - * - * Calls the detach routines of all matching - * drivers for this connection point, in the same - * order that the attach routines were called; then - * forgets about this vertex, so drivers added in - * the future will not be told about it. - * - * NOTE: Same caveat here about the detach calls as - * in the cdl_del_driver() comment above. - */ -extern int cdl_del_connpt(cdl_p reg, - int key1, - int key2, - devfs_handle_t conn, - int drv_flags); - -/* - * cdl_iterate: find all verticies in the registry - * corresponding to the named driver and call them - * with the specified function (giving the vertex - * as the parameter). - */ - -extern void cdl_iterate(cdl_p reg, - char *prefix, - cdl_iter_f *func); - -/* - * An INFO_LBL_ASYNC_ATTACH label is attached to a vertex, pointing to - * an instance of async_attach_s to indicate that asynchronous - * attachment may be applied to that device ... if the corresponding - * driver allows it. - */ - -struct async_attach_s { - struct semaphore async_sema; - int async_count; -}; -typedef struct async_attach_s *async_attach_t; - -async_attach_t async_attach_new(void); -void async_attach_free(async_attach_t); -async_attach_t async_attach_get_info(devfs_handle_t); -void async_attach_add_info(devfs_handle_t, async_attach_t); -void async_attach_del_info(devfs_handle_t); -void async_attach_signal_start(async_attach_t); -void async_attach_signal_done(async_attach_t); -void async_attach_waitall(async_attach_t); - #endif /* _ASM_IA64_SN_CDL_H */ diff -Nru a/include/asm-ia64/sn/clksupport.h b/include/asm-ia64/sn/clksupport.h --- a/include/asm-ia64/sn/clksupport.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/clksupport.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ /* @@ -31,28 +31,10 @@ typedef long clkreg_t; extern unsigned long sn_rtc_cycles_per_second; - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#include - -extern nasid_t master_nasid; - -#define RTC_MASK (0x007fffffffffffff) -/* clocks are not synchronized yet on SN1 - used node 0 (problem if no NASID 0) */ -#define RTC_COUNTER_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COUNTER)) -#define RTC_COMPARE_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_A)) -#define RTC_COMPARE_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_B)) -#define RTC_INT_PENDING_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_A)) -#define RTC_INT_PENDING_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_B)) -#define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_A)) -#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_B)) -#else /* !CONFIG_IA64_SGI_SN1 */ #include #include #include #include -#define RTC_MASK (SH_RTC_MASK) #define RTC_COUNTER_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_COMPARE_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) @@ -60,8 +42,6 @@ #define RTC_INT_PENDING_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) #define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC)) -#endif /* CONFIG_IA64_SGI_SN1 */ - #define GET_RTC_COUNTER() (*RTC_COUNTER_ADDR) #define rtc_time() GET_RTC_COUNTER() diff -Nru a/include/asm-ia64/sn/dmamap.h b/include/asm-ia64/sn/dmamap.h --- a/include/asm-ia64/sn/dmamap.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/dmamap.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DMAMAP_H #define _ASM_IA64_SN_DMAMAP_H @@ -54,9 +54,6 @@ extern int dma_map(dmamap_t *, caddr_t, int); extern int dma_map2(dmamap_t *, caddr_t, caddr_t, int); extern paddr_t dma_mapaddr(dmamap_t *, caddr_t); -#ifdef LATER -extern int dma_mapbp(dmamap_t *, buf_t *, int); -#endif extern int dma_map_alenlist(dmamap_t *, struct alenlist_s *, size_t); extern uint ev_kvtoiopnum(caddr_t); diff -Nru a/include/asm-ia64/sn/driver.h b/include/asm-ia64/sn/driver.h --- a/include/asm-ia64/sn/driver.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/driver.h Fri May 16 04:18:18 2003 @@ -4,12 +4,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_DRIVER_H #define _ASM_IA64_SN_DRIVER_H -#include +#include #include /* @@ -75,7 +75,7 @@ /* TBD: allocated badwidth requirements */ /* interrupt description */ - devfs_handle_t intr_target; /* Hardware locator string */ + vertex_hdl_t intr_target; /* Hardware locator string */ int intr_policy; /* TBD */ ilvl_t intr_swlevel; /* software level for blocking intr */ char *intr_name; /* name of interrupt, if any */ diff -Nru a/include/asm-ia64/sn/eeprom.h b/include/asm-ia64/sn/eeprom.h --- a/include/asm-ia64/sn/eeprom.h Tue Feb 18 10:25:13 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,384 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Public interface for reading Atmel EEPROMs via L1 system controllers - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_EEPROM_H -#define _ASM_IA64_SN_EEPROM_H - -#include -#include -#include -#include -#include -#include - -/* - * The following structures are an implementation of the EEPROM info - * areas described in the SN1 EEPROM spec and the IPMI FRU Information - * Storage definition - */ - -/* Maximum lengths for EEPROM fields - */ -#define EEPROM_PARTNUM_LEN 20 -#define EEPROM_SERNUM_LEN 10 -#define EEPROM_MANUF_NAME_LEN 10 -#define EEPROM_PROD_NAME_LEN 14 - - - -/* The EEPROM "common header", which contains offsets to the other - * info areas in the EEPROM - */ -typedef struct eeprom_common_hdr_t -{ - uchar_t format; /* common header format byte */ - uchar_t internal_use; /* offsets to various info areas */ - uchar_t chassis; /* (in doubleword units) */ - uchar_t board; - uchar_t product; - uchar_t multi_record; - uchar_t pad; - uchar_t checksum; -} eeprom_common_hdr_t; - - -/* The chassis (brick) info area - */ -typedef struct eeprom_chassis_ia_t -{ - uchar_t format; /* format byte */ - uchar_t length; /* info area length in doublewords */ - uchar_t type; /* chassis type (always 0x17 "rack mount") */ - uchar_t part_num_tl; /* type/length of part number field */ - - char part_num[EEPROM_PARTNUM_LEN]; - /* ASCII part number */ - - uchar_t serial_num_tl; /* type/length of serial number field */ - - char serial_num[EEPROM_SERNUM_LEN]; - /* ASCII serial number */ - - uchar_t checksum; - -} eeprom_chassis_ia_t; - - -/* The board info area - */ -typedef struct eeprom_board_ia_t -{ - uchar_t format; /* format byte */ - uchar_t length; /* info area length in doublewords */ - uchar_t language; /* language code, always 0x00 "English" */ - int mfg_date; /* date & time of manufacture, in minutes - since 0:00 1/1/96 */ - uchar_t manuf_tl; /* type/length of manufacturer name field */ - - char manuf[EEPROM_MANUF_NAME_LEN]; - /* ASCII manufacturer name */ - - uchar_t product_tl; /* type/length of product name field */ - - char product[EEPROM_PROD_NAME_LEN]; - /* ASCII product name */ - - uchar_t serial_num_tl; /* type/length of board serial number */ - - char serial_num[EEPROM_SERNUM_LEN]; - /* ASCII serial number */ - - uchar_t part_num_tl; /* type/length of board part number */ - - char part_num[EEPROM_PARTNUM_LEN]; - /* ASCII part number */ - - /* - * "custom" fields -- see SN1 EEPROM Spec - */ - uchar_t board_rev_tl; /* type/length of board rev (always 0xC2) */ - - char board_rev[2]; /* ASCII board revision */ - - uchar_t eeprom_size_tl; /* type/length of eeprom size field */ - uchar_t eeprom_size; /* size code for eeprom */ - uchar_t temp_waiver_tl; /* type/length of temp waiver field (0xC2) */ - char temp_waiver[2]; /* temp waiver */ - - - /* - * these fields only appear in main boards' EEPROMs - */ - uchar_t ekey_G_tl; /* type/length of encryption key "G" */ - uint32_t ekey_G; /* encryption key "G" */ - uchar_t ekey_P_tl; /* type/length of encryption key "P" */ - uint32_t ekey_P; /* encryption key "P" */ - uchar_t ekey_Y_tl; /* type/length of encryption key "Y" */ - uint32_t ekey_Y; /* encryption key "Y" */ - - - /* - * these fields are used for I bricks only - */ - uchar_t mac_addr_tl; /* type/length of MAC address */ - char mac_addr[12]; /* MAC address */ - uchar_t ieee1394_cfg_tl; /* type/length of IEEE 1394 info */ - uchar_t ieee1394_cfg[32]; /* IEEE 1394 config info */ - - - /* - * all boards have a checksum - */ - uchar_t checksum; - -} eeprom_board_ia_t; - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ); - - -/* EEPROM Serial Presence Detect record (used for DIMMs in IP35) - */ -typedef struct eeprom_spd_t -{ - /* 0*/ uchar_t spd_used; /* # of bytes written to serial memory by manufacturer */ - /* 1*/ uchar_t spd_size; /* Total # of bytes of SPD memory device */ - /* 2*/ uchar_t mem_type; /* Fundamental memory type (FPM, EDO, SDRAM..) */ - /* 3*/ uchar_t num_rows; /* # of row addresses on this assembly */ - /* 4*/ uchar_t num_cols; /* # Column Addresses on this assembly */ - /* 5*/ uchar_t mod_rows; /* # Module Rows on this assembly */ - /* 6*/ uchar_t data_width[2]; /* Data Width of this assembly (16b little-endian) */ - /* 8*/ uchar_t volt_if; /* Voltage interface standard of this assembly */ - /* 9*/ uchar_t cyc_time; /* SDRAM Cycle time, CL=X (highest CAS latency) */ - /* A*/ uchar_t acc_time; /* SDRAM Access from Clock (highest CAS latency) */ - /* B*/ uchar_t dimm_cfg; /* DIMM Configuration type (non-parity, ECC) */ - /* C*/ uchar_t refresh_rt; /* Refresh Rate/Type */ - /* D*/ uchar_t prim_width; /* Primary SDRAM Width */ - /* E*/ uchar_t ec_width; /* Error Checking SDRAM width */ - /* F*/ uchar_t min_delay; /* Min Clock Delay Back to Back Random Col Address */ - /*10*/ uchar_t burst_len; /* Burst Lengths Supported */ - /*11*/ uchar_t num_banks; /* # of Banks on Each SDRAM Device */ - /*12*/ uchar_t cas_latencies; /* CAS# Latencies Supported */ - /*13*/ uchar_t cs_latencies; /* CS# Latencies Supported */ - /*14*/ uchar_t we_latencies; /* Write Latencies Supported */ - /*15*/ uchar_t mod_attrib; /* SDRAM Module Attributes */ - /*16*/ uchar_t dev_attrib; /* SDRAM Device Attributes: General */ - /*17*/ uchar_t cyc_time2; /* Min SDRAM Cycle time at CL X-1 (2nd highest CAS latency) */ - /*18*/ uchar_t acc_time2; /* SDRAM Access from Clock at CL X-1 (2nd highest CAS latency) */ - /*19*/ uchar_t cyc_time3; /* Min SDRAM Cycle time at CL X-2 (3rd highest CAS latency) */ - /*1A*/ uchar_t acc_time3; /* Max SDRAM Access from Clock at CL X-2 (3nd highest CAS latency) */ - /*1B*/ uchar_t min_row_prechg; /* Min Row Precharge Time (Trp) */ - /*1C*/ uchar_t min_ra_to_ra; /* Min Row Active to Row Active (Trrd) */ - /*1D*/ uchar_t min_ras_to_cas; /* Min RAS to CAS Delay (Trcd) */ - /*1E*/ uchar_t min_ras_pulse; /* Minimum RAS Pulse Width (Tras) */ - /*1F*/ uchar_t row_density; /* Density of each row on module */ - /*20*/ uchar_t ca_setup; /* Command and Address signal input setup time */ - /*21*/ uchar_t ca_hold; /* Command and Address signal input hold time */ - /*22*/ uchar_t d_setup; /* Data signal input setup time */ - /*23*/ uchar_t d_hold; /* Data signal input hold time */ - - /*24*/ uchar_t pad0[26]; /* unused */ - - /*3E*/ uchar_t data_rev; /* SPD Data Revision Code */ - /*3F*/ uchar_t checksum; /* Checksum for bytes 0-62 */ - /*40*/ uchar_t jedec_id[8]; /* Manufacturer's JEDEC ID code */ - - /*48*/ uchar_t mfg_loc; /* Manufacturing Location */ - /*49*/ uchar_t part_num[18]; /* Manufacturer's Part Number */ - - /*5B*/ uchar_t rev_code[2]; /* Revision Code */ - - /*5D*/ uchar_t mfg_date[2]; /* Manufacturing Date */ - - /*5F*/ uchar_t ser_num[4]; /* Assembly Serial Number */ - - /*63*/ uchar_t manuf_data[27]; /* Manufacturer Specific Data */ - - /*7E*/ uchar_t intel_freq; /* Intel specification frequency */ - /*7F*/ uchar_t intel_100MHz; /* Intel spec details for 100MHz support */ - -} eeprom_spd_t; - - -#define EEPROM_SPD_RECORD_MAXLEN 256 - -typedef union eeprom_spd_u -{ - eeprom_spd_t fields; - char bytes[EEPROM_SPD_RECORD_MAXLEN]; - -} eeprom_spd_u; - - -/* EEPROM board record - */ -typedef struct eeprom_brd_record_t -{ - eeprom_chassis_ia_t *chassis_ia; - eeprom_board_ia_t *board_ia; - eeprom_spd_u *spd; - -} eeprom_brd_record_t; - - -/* End-of-fields marker - */ -#define EEPROM_EOF 0xc1 - - -/* masks for dissecting the type/length bytes - */ -#define FIELD_FORMAT_MASK 0xc0 -#define FIELD_LENGTH_MASK 0x3f - - -/* field format codes (used in type/length bytes) - */ -#define FIELD_FORMAT_BINARY 0x00 /* binary format */ -#define FIELD_FORMAT_BCD 0x40 /* BCD */ -#define FIELD_FORMAT_PACKED 0x80 /* packed 6-bit ASCII */ -#define FIELD_FORMAT_ASCII 0xC0 /* 8-bit ASCII */ - - - - -/* codes specifying brick and board type - */ -#define C_BRICK 0x100 - -#define C_PIMM (C_BRICK | 0x10) -#define C_PIMM_0 (C_PIMM) /* | 0x0 */ -#define C_PIMM_1 (C_PIMM | 0x1) - -#define C_DIMM (C_BRICK | 0x20) -#define C_DIMM_0 (C_DIMM) /* | 0x0 */ -#define C_DIMM_1 (C_DIMM | 0x1) -#define C_DIMM_2 (C_DIMM | 0x2) -#define C_DIMM_3 (C_DIMM | 0x3) -#define C_DIMM_4 (C_DIMM | 0x4) -#define C_DIMM_5 (C_DIMM | 0x5) -#define C_DIMM_6 (C_DIMM | 0x6) -#define C_DIMM_7 (C_DIMM | 0x7) - -#define R_BRICK 0x200 -#define R_POWER (R_BRICK | 0x10) - -#define VECTOR 0x300 /* used in vector ops when the destination - * could be a cbrick or an rbrick */ - -#define IO_BRICK 0x400 -#define IO_POWER (IO_BRICK | 0x10) - -#define BRICK_MASK 0xf00 -#define SUBORD_MASK 0xf0 /* AND with component specification; if the - the result is non-zero, then the component - is a subordinate board of some kind */ -#define COMPT_MASK 0xf /* if there's more than one instance of a - particular type of subordinate board, this - masks out which one we're talking about */ - - - -/* functions & macros for obtaining "NIC-like" strings from EEPROMs - */ - -#ifdef CONFIG_IA64_SGI_SN1 - -int eeprom_str( char *nic_str, nasid_t nasid, int component ); -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ); - -#define CBRICK_EEPROM_STR(s,n) eeprom_str((s),(n),C_BRICK) -#define IOBRICK_EEPROM_STR(s,n) eeprom_str((s),(n),IO_BRICK) -#define RBRICK_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),R_BRICK,p) -#define VECTOR_EEPROM_STR(s,n,p) vector_eeprom_str((s),(n),VECTOR,p) - -#endif /* CONFIG_IA64_SGI_SN1 */ - - -/* functions for obtaining formatted records from EEPROMs - */ - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ); -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ); -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ); - - - -/* retrieve the ethernet MAC address for an I-brick - */ - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ); - - -/* error codes - */ - -#define EEP_OK 0 -#define EEP_L1 1 -#define EEP_FAIL 2 -#define EEP_BAD_CHECKSUM 3 -#define EEP_NICIFY 4 -#define EEP_PARAM 6 -#define EEP_NOMEM 7 - - - -/* given a hardware graph vertex and an indication of the brick type, - * brick and board to be read, this functions reads the eeprom and - * attaches a "NIC"-format string of manufacturing information to the - * vertex. If the vertex already has the string, just returns the - * string. If component is not VECTOR or R_BRICK, the path parameter - * is ignored. - */ - -#ifdef LATER -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ); -#endif - - - -/* We may need to differentiate between an XBridge and other types of - * bridges during discovery to tell whether the bridge in question - * is part of an IO brick. The following function reads the WIDGET_ID - * register of the bridge under examination and returns a positive value - * if the part and mfg numbers stored there indicate that this widget - * is an XBridge (and so must be part of a brick). - */ -#ifdef LATER -int is_iobrick( int nasid, int widget_num ); -#endif - -/* the following macro derives the widget number from the register - * address passed to it and uses is_iobrick to determine whether - * the widget in question is part of an SN1 IO brick. - */ -#define IS_IOBRICK(rg) is_iobrick( NASID_GET((rg)), SWIN_WIDGETNUM((rg)) ) - - - -/* macros for NIC compatibility */ -/* always invoked on "this" cbrick */ -#define HUB_VERTEX_MFG_INFO(v) \ - eeprom_vertex_info_set( C_BRICK, get_nasid(), (v), 0 ) - -#define BRIDGE_VERTEX_MFG_INFO(v, r) \ - ( IS_IOBRICK((r)) ? eeprom_vertex_info_set \ - ( IO_BRICK, NASID_GET((r)), (v), 0 ) \ - : nic_bridge_vertex_info((v), (r)) ) - -#endif /* _ASM_IA64_SN_EEPROM_H */ diff -Nru a/include/asm-ia64/sn/fetchop.h b/include/asm-ia64/sn/fetchop.h --- a/include/asm-ia64/sn/fetchop.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/fetchop.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_FETCHOP_H @@ -39,28 +39,10 @@ #ifdef __KERNEL__ /* - * Initialize a FETCHOP line. The argument should point to the beginning - * of the line. - * SN1 - region mask is in word 0, data in word 1 - * SN2 - no region mask. Data in word 0 - */ -#ifdef CONFIG_IA64_SGI_SN1 -#define FETCHOP_INIT_LINE(p) *(p) = 0xffffffffffffffffUL -#elif CONFIG_IA64_SGI_SN2 -#define FETCHOP_INIT_LINE(p) -#endif - -/* - * Convert a region 7 (kaddr) address to the address of the fetchop variable + * Convert a region 6 (kaddr) address to the address of the fetchop variable */ #define FETCHOP_KADDR_TO_MSPEC_ADDR(kaddr) TO_MSPEC(kaddr) -/* - * Convert a page struct (page) address to the address of the first - * fetchop variable in the page - */ -#define FETCHOP_PAGE_TO_MSPEC_ADDR(page) FETCHOP_KADDR_TO_MSPEC_ADDR(__pa(page_address(page))) - /* * Each Atomic Memory Operation (AMO formerly known as fetchop) @@ -80,19 +62,19 @@ * inconsistency. */ typedef struct { - -#ifdef CONFIG_IA64_SGI_SN1 - u64 permissions; -#endif u64 variable; - -#ifdef CONFIG_IA64_SGI_SN1 - u64 unused[6]; -#else u64 unused[7]; -#endif - } AMO_t; + + +/* + * The following APIs are externalized to the kernel to allocate/free fetchop variables. + * fetchop_kalloc_one - Allocate/initialize 1 fetchop variable on the specified cnode. + * fetchop_kfree_one - Free a previously allocated fetchop variable + */ + +unsigned long fetchop_kalloc_one(int nid); +void fetchop_kfree_one(unsigned long maddr); #endif /* __KERNEL__ */ diff -Nru a/include/asm-ia64/sn/gda.h b/include/asm-ia64/sn/gda.h --- a/include/asm-ia64/sn/gda.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,109 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Derived from IRIX . - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - * - * gda.h -- Contains the data structure for the global data area, - * The GDA contains information communicated between the - * PROM, SYMMON, and the kernel. - */ -#ifndef _ASM_IA64_SN_GDA_H -#define _ASM_IA64_SN_GDA_H - -#include -#include - -#define GDA_MAGIC 0x58464552 - -/* - * GDA Version History - * - * Version # | Change - * -------------+------------------------------------------------------- - * 1 | Initial IP27 version - * 2 | Prom sets g_partid field to the partition number. 0 IS - * | a valid partition #. - */ - -#define GDA_VERSION 2 /* Current GDA version # */ - -#define G_MAGICOFF 0 -#define G_VERSIONOFF 4 -#define G_PROMOPOFF 6 -#define G_MASTEROFF 8 -#define G_VDSOFF 12 -#define G_HKDNORMOFF 16 -#define G_HKDUTLBOFF 24 -#define G_HKDXUTLBOFF 32 -#define G_PARTIDOFF 40 -#define G_TABLEOFF 128 - -#ifndef __ASSEMBLY__ - -typedef struct gda { - u32 g_magic; /* GDA magic number */ - u16 g_version; /* Version of this structure */ - u16 g_masterid; /* The NASID:CPUNUM of the master cpu */ - u32 g_promop; /* Passes requests from the kernel to prom */ - u32 g_vds; /* Store the virtual dipswitches here */ - void **g_hooked_norm;/* ptr to pda loc for norm hndlr */ - void **g_hooked_utlb;/* ptr to pda loc for utlb hndlr */ - void **g_hooked_xtlb;/* ptr to pda loc for xtlb hndlr */ - int g_partid; /* partition id */ - int g_symmax; /* Max symbols in name table. */ - void *g_dbstab; /* Address of idbg symbol table */ - char *g_nametab; /* Address of idbg name table */ - void *g_ktext_repmask; - /* Pointer to a mask of nodes with copies - * of the kernel. */ - char g_padding[56]; /* pad out to 128 bytes */ - nasid_t g_nasidtable[MAX_COMPACT_NODES+1]; /* NASID of each node, - * indexed by cnodeid. - */ -} gda_t; - -#define GDA ((gda_t*) GDA_ADDR(get_nasid())) - -#endif /* __ASSEMBLY__ */ -/* - * Define: PART_GDA_VERSION - * Purpose: Define the minimum version of the GDA required, lower - * revisions assume GDA is NOT set up, and read partition - * information from the board info. - */ -#define PART_GDA_VERSION 2 - -/* - * The following requests can be sent to the PROM during startup. - */ - -#define PROMOP_MAGIC 0x0ead0000 -#define PROMOP_MAGIC_MASK 0x0fff0000 - -#define PROMOP_BIST_SHIFT 11 -#define PROMOP_BIST_MASK (0x3 << 11) - -#define PROMOP_REG PI_ERR_STACK_ADDR_A - -#define PROMOP_INVALID (PROMOP_MAGIC | 0x00) -#define PROMOP_HALT (PROMOP_MAGIC | 0x10) -#define PROMOP_POWERDOWN (PROMOP_MAGIC | 0x20) -#define PROMOP_RESTART (PROMOP_MAGIC | 0x30) -#define PROMOP_REBOOT (PROMOP_MAGIC | 0x40) -#define PROMOP_IMODE (PROMOP_MAGIC | 0x50) - -#define PROMOP_CMD_MASK 0x00f0 -#define PROMOP_OPTIONS_MASK 0xfff0 - -#define PROMOP_SKIP_DIAGS 0x0100 /* don't bother running diags */ -#define PROMOP_SKIP_MEMINIT 0x0200 /* don't bother initing memory */ -#define PROMOP_SKIP_DEVINIT 0x0400 /* don't bother initing devices */ -#define PROMOP_BIST1 0x0800 /* keep track of which BIST ran */ -#define PROMOP_BIST2 0x1000 /* keep track of which BIST ran */ - -#endif /* _ASM_IA64_SN_GDA_H */ diff -Nru a/include/asm-ia64/sn/geo.h b/include/asm-ia64/sn/geo.h --- a/include/asm-ia64/sn/geo.h Mon Feb 24 04:35:17 2003 +++ b/include/asm-ia64/sn/geo.h Fri May 16 04:18:18 2003 @@ -17,15 +17,7 @@ * GEO_MAX_LEN: The maximum length of a geoid, formatted for printing */ -#include - -#ifdef CONFIG_IA64_SGI_SN2 #include -#else - -#error <> - -#endif /* !SN2 && ... */ /* Declarations applicable to all platforms */ diff -Nru a/include/asm-ia64/sn/hack.h b/include/asm-ia64/sn/hack.h --- a/include/asm-ia64/sn/hack.h Tue Dec 3 10:07:32 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,69 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_HACK_H -#define _ASM_IA64_SN_HACK_H - -#include -#include -#include -#include /* for copy_??_user */ - -/****************************************** - * Definitions that do not exist in linux * - ******************************************/ - -typedef int cred_t; /* This is for compilation reasons */ -struct cred { int x; }; - - -/* - * Hardware Graph routines that are currently stubbed! - */ -#include - -#define DELAY(a) - -/************************************************ - * Routines redefined to use linux equivalents. * - ************************************************/ - -/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ - -#define FIXME(s) - -extern devfs_handle_t dummy_vrtx; -#define cpuid_to_vertex(cpuid) dummy_vrtx /* (pdaindr[cpuid].pda->p_vertex) */ - -#define PUTBUF_LOCK(a) { FIXME("PUTBUF_LOCK"); } -#define PUTBUF_UNLOCK(a) { FIXME("PUTBUF_UNLOCK"); } - -typedef int (*splfunc_t)(void); - -/* move to stubs.c yet */ -#define dev_to_vhdl(dev) 0 -#define get_timestamp() 0 -#define us_delay(a) -#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); -#define splhi() 0 -#define spl7 splhi() -#define splx(s) - -extern void * snia_kmem_alloc_node(register size_t, register int, cnodeid_t); -extern void * snia_kmem_zalloc(size_t, int); -extern void * snia_kmem_zalloc_node(register size_t, register int, cnodeid_t ); -extern void * snia_kmem_zone_alloc(register struct zone *, int); -extern struct zone * snia_kmem_zone_init(register int , char *); -extern void snia_kmem_zone_free(register struct zone *, void *); -extern int is_specified(char *); -extern int cap_able(uint64_t); -extern int compare_and_swap_ptr(void **, void *, void *); - -#endif /* _ASM_IA64_SN_HACK_H */ diff -Nru a/include/asm-ia64/sn/hcl.h b/include/asm-ia64/sn/hcl.h --- a/include/asm-ia64/sn/hcl.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/hcl.h Fri May 16 04:18:17 2003 @@ -4,18 +4,15 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_HCL_H #define _ASM_IA64_SN_HCL_H #include -#include -#include -extern devfs_handle_t hcl_handle; /* HCL driver */ -extern devfs_handle_t hwgraph_root; -extern devfs_handle_t linux_busnum; +extern vertex_hdl_t hwgraph_root; +extern vertex_hdl_t linux_busnum; typedef long labelcl_info_place_t; @@ -58,58 +55,56 @@ /* * External declarations of EXPORTED SYMBOLS in hcl.c */ -extern devfs_handle_t hwgraph_register(devfs_handle_t, const char *, +extern vertex_hdl_t hwgraph_register(vertex_hdl_t, const char *, unsigned int, unsigned int, unsigned int, unsigned int, umode_t, uid_t, gid_t, struct file_operations *, void *); -extern int hwgraph_mk_symlink(devfs_handle_t, const char *, unsigned int, - unsigned int, const char *, unsigned int, devfs_handle_t *, void *); +extern int hwgraph_mk_symlink(vertex_hdl_t, const char *, unsigned int, + unsigned int, const char *, unsigned int, vertex_hdl_t *, void *); -extern int hwgraph_vertex_destroy(devfs_handle_t); +extern int hwgraph_vertex_destroy(vertex_hdl_t); -extern int hwgraph_edge_add(devfs_handle_t, devfs_handle_t, char *); -extern int hwgraph_edge_get(devfs_handle_t, char *, devfs_handle_t *); +extern int hwgraph_edge_add(vertex_hdl_t, vertex_hdl_t, char *); +extern int hwgraph_edge_get(vertex_hdl_t, char *, vertex_hdl_t *); -extern arbitrary_info_t hwgraph_fastinfo_get(devfs_handle_t); -extern void hwgraph_fastinfo_set(devfs_handle_t, arbitrary_info_t ); -extern devfs_handle_t hwgraph_mk_dir(devfs_handle_t, const char *, unsigned int, void *); +extern arbitrary_info_t hwgraph_fastinfo_get(vertex_hdl_t); +extern void hwgraph_fastinfo_set(vertex_hdl_t, arbitrary_info_t ); +extern vertex_hdl_t hwgraph_mk_dir(vertex_hdl_t, const char *, unsigned int, void *); -extern int hwgraph_connectpt_set(devfs_handle_t, devfs_handle_t); -extern devfs_handle_t hwgraph_connectpt_get(devfs_handle_t); -extern int hwgraph_edge_get_next(devfs_handle_t, char *, devfs_handle_t *, uint *); -extern graph_error_t hwgraph_edge_remove(devfs_handle_t, char *, devfs_handle_t *); +extern int hwgraph_connectpt_set(vertex_hdl_t, vertex_hdl_t); +extern vertex_hdl_t hwgraph_connectpt_get(vertex_hdl_t); +extern int hwgraph_edge_get_next(vertex_hdl_t, char *, vertex_hdl_t *, uint *); +extern graph_error_t hwgraph_edge_remove(vertex_hdl_t, char *, vertex_hdl_t *); -extern graph_error_t hwgraph_traverse(devfs_handle_t, char *, devfs_handle_t *); +extern graph_error_t hwgraph_traverse(vertex_hdl_t, char *, vertex_hdl_t *); -extern int hwgraph_vertex_get_next(devfs_handle_t *, devfs_handle_t *); -extern int hwgraph_inventory_get_next(devfs_handle_t, invplace_t *, +extern int hwgraph_vertex_get_next(vertex_hdl_t *, vertex_hdl_t *); +extern int hwgraph_inventory_get_next(vertex_hdl_t, invplace_t *, inventory_t **); -extern int hwgraph_inventory_add(devfs_handle_t, int, int, major_t, minor_t, int); -extern int hwgraph_inventory_remove(devfs_handle_t, int, int, major_t, minor_t, int); -extern int hwgraph_controller_num_get(devfs_handle_t); -extern void hwgraph_controller_num_set(devfs_handle_t, int); -extern int hwgraph_path_ad(devfs_handle_t, char *, devfs_handle_t *); -extern devfs_handle_t hwgraph_path_to_vertex(char *); -extern devfs_handle_t hwgraph_path_to_dev(char *); -extern devfs_handle_t hwgraph_block_device_get(devfs_handle_t); -extern devfs_handle_t hwgraph_char_device_get(devfs_handle_t); -extern graph_error_t hwgraph_char_device_add(devfs_handle_t, char *, char *, devfs_handle_t *); -extern int hwgraph_path_add(devfs_handle_t, char *, devfs_handle_t *); -extern int hwgraph_info_add_LBL(devfs_handle_t, char *, arbitrary_info_t); -extern int hwgraph_info_get_LBL(devfs_handle_t, char *, arbitrary_info_t *); -extern int hwgraph_info_replace_LBL(devfs_handle_t, char *, arbitrary_info_t, +extern int hwgraph_inventory_add(vertex_hdl_t, int, int, major_t, minor_t, int); +extern int hwgraph_inventory_remove(vertex_hdl_t, int, int, major_t, minor_t, int); +extern int hwgraph_controller_num_get(vertex_hdl_t); +extern void hwgraph_controller_num_set(vertex_hdl_t, int); +extern int hwgraph_path_ad(vertex_hdl_t, char *, vertex_hdl_t *); +extern vertex_hdl_t hwgraph_path_to_vertex(char *); +extern vertex_hdl_t hwgraph_path_to_dev(char *); +extern vertex_hdl_t hwgraph_block_device_get(vertex_hdl_t); +extern vertex_hdl_t hwgraph_char_device_get(vertex_hdl_t); +extern graph_error_t hwgraph_char_device_add(vertex_hdl_t, char *, char *, vertex_hdl_t *); +extern int hwgraph_path_add(vertex_hdl_t, char *, vertex_hdl_t *); +extern int hwgraph_info_add_LBL(vertex_hdl_t, char *, arbitrary_info_t); +extern int hwgraph_info_get_LBL(vertex_hdl_t, char *, arbitrary_info_t *); +extern int hwgraph_info_replace_LBL(vertex_hdl_t, char *, arbitrary_info_t, arbitrary_info_t *); -extern int hwgraph_info_get_exported_LBL(devfs_handle_t, char *, int *, arbitrary_info_t *); -extern int hwgraph_info_get_next_LBL(devfs_handle_t, char *, arbitrary_info_t *, +extern int hwgraph_info_get_exported_LBL(vertex_hdl_t, char *, int *, arbitrary_info_t *); +extern int hwgraph_info_get_next_LBL(vertex_hdl_t, char *, arbitrary_info_t *, labelcl_info_place_t *); - -extern int hwgraph_path_lookup(devfs_handle_t, char *, devfs_handle_t *, char **); -extern int hwgraph_info_export_LBL(devfs_handle_t, char *, int); -extern int hwgraph_info_unexport_LBL(devfs_handle_t, char *); -extern int hwgraph_info_remove_LBL(devfs_handle_t, char *, arbitrary_info_t *); -extern char * vertex_to_name(devfs_handle_t, char *, uint); -extern graph_error_t hwgraph_vertex_unref(devfs_handle_t); - +extern int hwgraph_path_lookup(vertex_hdl_t, char *, vertex_hdl_t *, char **); +extern int hwgraph_info_export_LBL(vertex_hdl_t, char *, int); +extern int hwgraph_info_unexport_LBL(vertex_hdl_t, char *); +extern int hwgraph_info_remove_LBL(vertex_hdl_t, char *, arbitrary_info_t *); +extern char * vertex_to_name(vertex_hdl_t, char *, uint); +extern graph_error_t hwgraph_vertex_unref(vertex_hdl_t); #endif /* _ASM_IA64_SN_HCL_H */ diff -Nru a/include/asm-ia64/sn/hcl_util.h b/include/asm-ia64/sn/hcl_util.h --- a/include/asm-ia64/sn/hcl_util.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/hcl_util.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_HCL_UTIL_H @@ -12,11 +12,11 @@ #include -extern char * dev_to_name(devfs_handle_t, char *, uint); -extern int device_master_set(devfs_handle_t, devfs_handle_t); -extern devfs_handle_t device_master_get(devfs_handle_t); -extern cnodeid_t master_node_get(devfs_handle_t); -extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t); -extern void mark_nodevertex_as_node(devfs_handle_t, cnodeid_t); +extern char * dev_to_name(vertex_hdl_t, char *, uint); +extern int device_master_set(vertex_hdl_t, vertex_hdl_t); +extern vertex_hdl_t device_master_get(vertex_hdl_t); +extern cnodeid_t master_node_get(vertex_hdl_t); +extern cnodeid_t nodevertex_to_cnodeid(vertex_hdl_t); +extern void mark_nodevertex_as_node(vertex_hdl_t, cnodeid_t); #endif /* _ASM_IA64_SN_HCL_UTIL_H */ diff -Nru a/include/asm-ia64/sn/hires_clock.h b/include/asm-ia64/sn/hires_clock.h --- a/include/asm-ia64/sn/hires_clock.h Sat Mar 9 02:24:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved. - * - * SGI Hi Resolution Clock - * - * SGI SN platforms provide a high resolution clock that is - * synchronized across all nodes. The clock can be memory mapped - * and directly read from user space. - * - * Access to the clock is thru the following: - * (error checking not shown) - * - * (Note: should library routines be provided to encapsulate this??) - * - * int fd: - * volatile long *clk; - * - * fd = open (HIRES_FULLNAME, O_RDONLY); - * clk = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0); - * clk += ioctl(fd, HIRES_IOCQGETOFFSET, 0); - * - * At this point, clk is a pointer to the high resolution clock. - * - * The clock period can be obtained via: - * - * long picosec_per_tick; - * picosec_per_tick = ioctl(fd, HIRES_IOCQGETPICOSEC, 0); - */ - -#ifndef _ASM_IA64_SN_HIRES_CLOCK_H -#define _ASM_IA64_SN_HIRES_CLOCK_H - - -#define HIRES_BASENAME "sgi_hires_clock" -#define HIRES_FULLNAME "/dev/sgi_hires_clock" -#define HIRES_IOC_BASE 's' - - -/* Get page offset of hires timer */ -#define HIRES_IOCQGETOFFSET _IO( HIRES_IOC_BASE, 0 ) - -/* get clock period in picoseconds per tick */ -#define HIRES_IOCQGETPICOSEC _IO( HIRES_IOC_BASE, 1 ) - -/* get number of significant bits in clock counter */ -#define HIRES_IOCQGETCLOCKBITS _IO( HIRES_IOC_BASE, 2 ) - -#endif /* _ASM_IA64_SN_HIRES_CLOCK_H */ diff -Nru a/include/asm-ia64/sn/hwgfs.h b/include/asm-ia64/sn/hwgfs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/sn/hwgfs.h Mon May 19 05:42:08 2003 @@ -0,0 +1,35 @@ +#ifndef _ASM_IA64_SN_HWGFS_H +#define _ASM_IA64_SN_HWGFS_H + +/* $Id$ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. + */ + +typedef struct dentry *hwgfs_handle_t; + +extern hwgfs_handle_t hwgfs_register(hwgfs_handle_t dir, const char *name, + unsigned int flags, + unsigned int major, unsigned int minor, + umode_t mode, void *ops, void *info); +extern int hwgfs_mk_symlink(hwgfs_handle_t dir, const char *name, + unsigned int flags, const char *link, + hwgfs_handle_t *handle, void *info); +extern hwgfs_handle_t hwgfs_mk_dir(hwgfs_handle_t dir, const char *name, + void *info); +extern void hwgfs_unregister(hwgfs_handle_t de); + +extern hwgfs_handle_t hwgfs_find_handle(hwgfs_handle_t dir, const char *name, + unsigned int major,unsigned int minor, + char type, int traverse_symlinks); +extern hwgfs_handle_t hwgfs_get_parent(hwgfs_handle_t de); +extern int hwgfs_generate_path(hwgfs_handle_t de, char *path, int buflen); + +extern void *hwgfs_get_info(hwgfs_handle_t de); +extern int hwgfs_set_info(hwgfs_handle_t de, void *info); + +#endif diff -Nru a/include/asm-ia64/sn/idle.h b/include/asm-ia64/sn/idle.h --- a/include/asm-ia64/sn/idle.h Tue Dec 3 10:07:32 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -#ifndef _ASM_IA64_SN_IDLE_H -#define _ASM_IA64_SN_IDLE_H - -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include - -static __inline__ void -snidle(void) { -#if 0 -#ifdef CONFIG_IA64_SGI_AUTOTEST - { - extern int autotest_enabled; - if (autotest_enabled) { - extern void llsc_main(int); - llsc_main(smp_processor_id()); - } - } -#endif - - if (pda.idle_flag == 0) { - /* - * Turn the activity LED off. - */ - set_led_bits(0, LED_CPU_ACTIVITY); - } - -#ifdef CONFIG_IA64_SGI_SN_SIM - if (IS_RUNNING_ON_SIMULATOR()) - SIMULATOR_SLEEP(); -#endif - - pda.idle_flag = 1; -#endif -} - -static __inline__ void -snidleoff(void) { -#if 0 - /* - * Turn the activity LED on. - */ - set_led_bits(LED_CPU_ACTIVITY, LED_CPU_ACTIVITY); - - pda.idle_flag = 0; -#endif -} - -#endif /* _ASM_IA64_SN_IDLE_H */ diff -Nru a/include/asm-ia64/sn/ifconfig_net.h b/include/asm-ia64/sn/ifconfig_net.h --- a/include/asm-ia64/sn/ifconfig_net.h Sat Mar 9 02:24:40 2002 +++ b/include/asm-ia64/sn/ifconfig_net.h Fri May 16 04:18:17 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IFCONFIG_NET_H diff -Nru a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h --- a/include/asm-ia64/sn/intr.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/intr.h Fri May 16 04:18:17 2003 @@ -4,21 +4,18 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INTR_H #define _ASM_IA64_SN_INTR_H #include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif extern void sn_send_IPI_phys(long, int, int); -#define CPU_VECTOR_TO_IRQ(cpuid,vector) ((cpuid) << 8 | (vector)) +#define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) +#define SN_CPU_FROM_IRQ(irq) (0) +#define SN_IVEC_FROM_IRQ(irq) (irq) #endif /* _ASM_IA64_SN_INTR_H */ diff -Nru a/include/asm-ia64/sn/intr_public.h b/include/asm-ia64/sn/intr_public.h --- a/include/asm-ia64/sn/intr_public.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,19 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_INTR_PUBLIC_H -#define _ASM_IA64_SN_INTR_PUBLIC_H - -#include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) -#endif - -#endif /* _ASM_IA64_SN_INTR_PUBLIC_H */ diff -Nru a/include/asm-ia64/sn/invent.h b/include/asm-ia64/sn/invent.h --- a/include/asm-ia64/sn/invent.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/invent.h Fri May 16 04:18:17 2003 @@ -4,14 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_INVENT_H #define _ASM_IA64_SN_INVENT_H #include -#include - +#include /* * sys/sn/invent.h -- Kernel Hardware Inventory * @@ -31,7 +30,7 @@ #define minor_t int #define app32_ptr_t unsigned long #define graph_vertex_place_t long -#define GRAPH_VERTEX_NONE ((devfs_handle_t)-1) +#define GRAPH_VERTEX_NONE ((vertex_hdl_t)-1) #define GRAPH_EDGE_PLACE_NONE ((graph_edge_place_t)0) #define GRAPH_INFO_PLACE_NONE ((graph_info_place_t)0) #define GRAPH_VERTEX_PLACE_NONE ((graph_vertex_place_t)0) @@ -713,8 +712,8 @@ } irix5_inventory_t; typedef struct invplace_s { - devfs_handle_t invplace_vhdl; /* current vertex */ - devfs_handle_t invplace_vplace; /* place in vertex list */ + vertex_hdl_t invplace_vhdl; /* current vertex */ + vertex_hdl_t invplace_vplace; /* place in vertex list */ inventory_t *invplace_inv; /* place in inv list on vertex */ } invplace_t; /* Magic cookie placeholder in inventory list */ @@ -730,7 +729,7 @@ extern int scaninvent(int (*)(inventory_t *, void *), void *); extern int get_sizeof_inventory(int); -extern void device_inventory_add( devfs_handle_t device, +extern void device_inventory_add( vertex_hdl_t device, int class, int type, major_t ctlr, @@ -738,11 +737,11 @@ int state); -extern inventory_t *device_inventory_get_next( devfs_handle_t device, +extern inventory_t *device_inventory_get_next( vertex_hdl_t device, invplace_t *); -extern void device_controller_num_set( devfs_handle_t, +extern void device_controller_num_set( vertex_hdl_t, int); -extern int device_controller_num_get( devfs_handle_t); +extern int device_controller_num_get( vertex_hdl_t); #endif /* __KERNEL__ */ #endif /* _ASM_IA64_SN_INVENT_H */ diff -Nru a/include/asm-ia64/sn/io.h b/include/asm-ia64/sn/io.h --- a/include/asm-ia64/sn/io.h Thu Mar 27 07:51:07 2003 +++ b/include/asm-ia64/sn/io.h Fri May 16 04:18:17 2003 @@ -56,27 +56,8 @@ (_x) : \ (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) ) -#if defined(CONFIG_IA64_SGI_SN1) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include #include -#endif /* * Used to ensure write ordering (like mb(), but for I/O space) diff -Nru a/include/asm-ia64/sn/ioc3.h b/include/asm-ia64/sn/ioc3.h --- a/include/asm-ia64/sn/ioc3.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/ioc3.h Fri May 16 04:18:17 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License diff -Nru a/include/asm-ia64/sn/ioc4.h b/include/asm-ia64/sn/ioc4.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/sn/ioc4.h Fri May 16 11:50:50 2003 @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + */ + +#ifndef _ASM_IA64_SN_IOC4_H +#define _ASM_IA64_SN_IOC4_H + +#if 0 + +/* + * ioc4.h - IOC4 chip header file + */ + +/* Notes: + * The IOC4 chip is a 32-bit PCI device that provides 4 serial ports, + * an IDE bus interface, a PC keyboard/mouse interface, and a real-time + * external interrupt interface. + * + * It includes an optimized DMA buffer management, and a store-and-forward + * buffer RAM. + * + * All IOC4 registers are 32 bits wide. + */ +typedef __uint32_t ioc4reg_t; + +/* + * PCI Configuration Space Register Address Map, use offset from IOC4 PCI + * configuration base such that this can be used for multiple IOC4s + */ +#define IOC4_PCI_ID 0x0 /* ID */ + +#define IOC4_VENDOR_ID_NUM 0x10A9 +#define IOC4_DEVICE_ID_NUM 0x100A +#define IOC4_ADDRSPACE_MASK 0xfff00000ULL + +#define IOC4_PCI_SCR 0x4 /* Status/Command */ +#define IOC4_PCI_REV 0x8 /* Revision */ +#define IOC4_PCI_LAT 0xC /* Latency Timer */ +#define IOC4_PCI_BAR0 0x10 /* IOC4 base address 0 */ +#define IOC4_PCI_SIDV 0x2c /* Subsys ID and vendor */ +#define IOC4_PCI_CAP 0x34 /* Capability pointer */ +#define IOC4_PCI_LATGNTINT 0x3c /* Max_lat, min_gnt, int_pin, int_line */ + +/* + * PCI Memory Space Map + */ +#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */ +#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0) +#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1) +#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5) +#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6) + +/* Master IDs contained in PCI_ERR_ADDR_MST_ID_MSK */ +#define IOC4_MST_ID_S0_TX 0 +#define IOC4_MST_ID_S0_RX 1 +#define IOC4_MST_ID_S1_TX 2 +#define IOC4_MST_ID_S1_RX 3 +#define IOC4_MST_ID_S2_TX 4 +#define IOC4_MST_ID_S2_RX 5 +#define IOC4_MST_ID_S3_TX 6 +#define IOC4_MST_ID_S3_RX 7 +#define IOC4_MST_ID_ATA 8 + +#define IOC4_PCI_ERR_ADDR_H 0x004 /* High Error Address */ + +#define IOC4_SIO_IR 0x008 /* SIO Interrupt Register */ +#define IOC4_OTHER_IR 0x00C /* Other Interrupt Register */ + +/* These registers are read-only for general kernel code. To modify + * them use the functions in ioc4.c + */ +#define IOC4_SIO_IES_RO 0x010 /* SIO Interrupt Enable Set Reg */ +#define IOC4_OTHER_IES_RO 0x014 /* Other Interrupt Enable Set Reg */ +#define IOC4_SIO_IEC_RO 0x018 /* SIO Interrupt Enable Clear Reg */ +#define IOC4_OTHER_IEC_RO 0x01C /* Other Interrupt Enable Clear Reg */ + +#define IOC4_SIO_CR 0x020 /* SIO Control Reg */ +#define IOC4_INT_OUT 0x028 /* INT_OUT Reg (realtime interrupt) */ +#define IOC4_GPCR_S 0x030 /* GenericPIO Cntrl Set Register */ +#define IOC4_GPCR_C 0x034 /* GenericPIO Cntrl Clear Register */ +#define IOC4_GPDR 0x038 /* GenericPIO Data Register */ +#define IOC4_GPPR_0 0x040 /* GenericPIO Pin Registers */ +#define IOC4_GPPR_OFF 0x4 +#define IOC4_GPPR(x) (IOC4_GPPR_0+(x)*IOC4_GPPR_OFF) + +/* ATAPI Registers */ +#define IOC4_ATA_0 0x100 /* Data w/timing */ +#define IOC4_ATA_1 0x104 /* Error/Features w/timing */ +#define IOC4_ATA_2 0x108 /* Sector Count w/timing */ +#define IOC4_ATA_3 0x10C /* Sector Number w/timing */ +#define IOC4_ATA_4 0x110 /* Cyliner Low w/timing */ +#define IOC4_ATA_5 0x114 /* Cylinder High w/timing */ +#define IOC4_ATA_6 0x118 /* Device/Head w/timing */ +#define IOC4_ATA_7 0x11C /* Status/Command w/timing */ +#define IOC4_ATA_0_AUX 0x120 /* Aux Status/Device Cntrl w/timing */ +#define IOC4_ATA_TIMING 0x140 /* Timing value register 0 */ +#define IOC4_ATA_DMA_PTR_L 0x144 /* Low Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_PTR_H 0x148 /* High Memory Pointer to DMA List */ +#define IOC4_ATA_DMA_ADDR_L 0x14C /* Low Memory DMA Address */ +#define IOC4_ATA_DMA_ADDR_H 0x150 /* High Memory DMA Addresss */ +#define IOC4_ATA_BC_DEV 0x154 /* DMA Byte Count at Device */ +#define IOC4_ATA_BC_MEM 0x158 /* DMA Byte Count at Memory */ +#define IOC4_ATA_DMA_CTRL 0x15C /* DMA Control/Status */ + +/* Keyboard and Mouse Registers */ +#define IOC4_KM_CSR 0x200 /* Kbd and Mouse Cntrl/Status Reg */ +#define IOC4_K_RD 0x204 /* Kbd Read Data Register */ +#define IOC4_M_RD 0x208 /* Mouse Read Data Register */ +#define IOC4_K_WD 0x20C /* Kbd Write Data Register */ +#define IOC4_M_WD 0x210 /* Mouse Write Data Register */ + +/* Serial Port Registers used for DMA mode serial I/O */ +#define IOC4_SBBR01_H 0x300 /* Serial Port Ring Buffers + Base Reg High for Channels 0 1*/ +#define IOC4_SBBR01_L 0x304 /* Serial Port Ring Buffers + Base Reg Low for Channels 0 1 */ +#define IOC4_SBBR23_H 0x308 /* Serial Port Ring Buffers + Base Reg High for Channels 2 3*/ +#define IOC4_SBBR23_L 0x30C /* Serial Port Ring Buffers + Base Reg Low for Channels 2 3 */ + +#define IOC4_SSCR_0 0x310 /* Serial Port 0 Control */ +#define IOC4_STPIR_0 0x314 /* Serial Port 0 TX Produce */ +#define IOC4_STCIR_0 0x318 /* Serial Port 0 TX Consume */ +#define IOC4_SRPIR_0 0x31C /* Serial Port 0 RX Produce */ +#define IOC4_SRCIR_0 0x320 /* Serial Port 0 RX Consume */ +#define IOC4_SRTR_0 0x324 /* Serial Port 0 Receive Timer Reg */ +#define IOC4_SHADOW_0 0x328 /* Serial Port 0 16550 Shadow Reg */ + +#define IOC4_SSCR_1 0x32C /* Serial Port 1 Control */ +#define IOC4_STPIR_1 0x330 /* Serial Port 1 TX Produce */ +#define IOC4_STCIR_1 0x334 /* Serial Port 1 TX Consume */ +#define IOC4_SRPIR_1 0x338 /* Serial Port 1 RX Produce */ +#define IOC4_SRCIR_1 0x33C /* Serial Port 1 RX Consume */ +#define IOC4_SRTR_1 0x340 /* Serial Port 1 Receive Timer Reg */ +#define IOC4_SHADOW_1 0x344 /* Serial Port 1 16550 Shadow Reg */ + +#define IOC4_SSCR_2 0x348 /* Serial Port 2 Control */ +#define IOC4_STPIR_2 0x34C /* Serial Port 2 TX Produce */ +#define IOC4_STCIR_2 0x350 /* Serial Port 2 TX Consume */ +#define IOC4_SRPIR_2 0x354 /* Serial Port 2 RX Produce */ +#define IOC4_SRCIR_2 0x358 /* Serial Port 2 RX Consume */ +#define IOC4_SRTR_2 0x35C /* Serial Port 2 Receive Timer Reg */ +#define IOC4_SHADOW_2 0x360 /* Serial Port 2 16550 Shadow Reg */ + +#define IOC4_SSCR_3 0x364 /* Serial Port 3 Control */ +#define IOC4_STPIR_3 0x368 /* Serial Port 3 TX Produce */ +#define IOC4_STCIR_3 0x36C /* Serial Port 3 TX Consume */ +#define IOC4_SRPIR_3 0x370 /* Serial Port 3 RX Produce */ +#define IOC4_SRCIR_3 0x374 /* Serial Port 3 RX Consume */ +#define IOC4_SRTR_3 0x378 /* Serial Port 3 Receive Timer Reg */ +#define IOC4_SHADOW_3 0x37C /* Serial Port 3 16550 Shadow Reg */ + +#define IOC4_UART0_BASE 0x380 /* UART 0 */ +#define IOC4_UART1_BASE 0x388 /* UART 1 */ +#define IOC4_UART2_BASE 0x390 /* UART 2 */ +#define IOC4_UART3_BASE 0x398 /* UART 3 */ + +/* Private page address aliases for usermode mapping */ +#define IOC4_INT_OUT_P 0x04000 /* INT_OUT Reg */ + +#define IOC4_SSCR_0_P 0x08000 /* Serial Port 0 */ +#define IOC4_STPIR_0_P 0x08004 +#define IOC4_STCIR_0_P 0x08008 /* (read-only) */ +#define IOC4_SRPIR_0_P 0x0800C /* (read-only) */ +#define IOC4_SRCIR_0_P 0x08010 +#define IOC4_SRTR_0_P 0x08014 +#define IOC4_UART_LSMSMCR_0_P 0x08018 /* (read-only) */ + +#define IOC4_SSCR_1_P 0x0C000 /* Serial Port 1 */ +#define IOC4_STPIR_1_P 0x0C004 +#define IOC4_STCIR_1_P 0x0C008 /* (read-only) */ +#define IOC4_SRPIR_1_P 0x0C00C /* (read-only) */ +#define IOC4_SRCIR_1_P 0x0C010 +#define IOC4_SRTR_1_P 0x0C014 +#define IOC4_UART_LSMSMCR_1_P 0x0C018 /* (read-only) */ + +#define IOC4_SSCR_2_P 0x10000 /* Serial Port 2 */ +#define IOC4_STPIR_2_P 0x10004 +#define IOC4_STCIR_2_P 0x10008 /* (read-only) */ +#define IOC4_SRPIR_2_P 0x1000C /* (read-only) */ +#define IOC4_SRCIR_2_P 0x10010 +#define IOC4_SRTR_2_P 0x10014 +#define IOC4_UART_LSMSMCR_2_P 0x10018 /* (read-only) */ + +#define IOC4_SSCR_3_P 0x14000 /* Serial Port 3 */ +#define IOC4_STPIR_3_P 0x14004 +#define IOC4_STCIR_3_P 0x14008 /* (read-only) */ +#define IOC4_SRPIR_3_P 0x1400C /* (read-only) */ +#define IOC4_SRCIR_3_P 0x14010 +#define IOC4_SRTR_3_P 0x14014 +#define IOC4_UART_LSMSMCR_3_P 0x14018 /* (read-only) */ + +#define IOC4_ALIAS_PAGE_SIZE 0x4000 + +/* Interrupt types */ +typedef enum ioc4_intr_type_e { + ioc4_sio_intr_type, + ioc4_other_intr_type, + ioc4_num_intr_types +} ioc4_intr_type_t; +#define ioc4_first_intr_type ioc4_sio_intr_type + +/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */ +#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */ +#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */ +#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */ +#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */ +#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */ +#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */ +#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */ +#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */ +#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */ +#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */ +#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */ +#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */ +#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */ +#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */ +#define IOC4_SIO_IR_S1_INT 0x00004000 /* */ +#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */ +#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */ +#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */ +#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */ +#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */ +#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */ +#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */ +#define IOC4_SIO_IR_S2_INT 0x00400000 /* */ +#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */ +#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */ +#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */ +#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */ +#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */ +#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */ +#define IOC4_SIO_IR_S3_INT 0x40000000 /* */ +#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */ + +/* Per device interrupt masks */ +#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ + IOC4_SIO_IR_S0_RX_FULL | \ + IOC4_SIO_IR_S0_RX_HIGH | \ + IOC4_SIO_IR_S0_RX_TIMER | \ + IOC4_SIO_IR_S0_DELTA_DCD | \ + IOC4_SIO_IR_S0_DELTA_CTS | \ + IOC4_SIO_IR_S0_INT | \ + IOC4_SIO_IR_S0_TX_EXPLICIT) +#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ + IOC4_SIO_IR_S1_RX_FULL | \ + IOC4_SIO_IR_S1_RX_HIGH | \ + IOC4_SIO_IR_S1_RX_TIMER | \ + IOC4_SIO_IR_S1_DELTA_DCD | \ + IOC4_SIO_IR_S1_DELTA_CTS | \ + IOC4_SIO_IR_S1_INT | \ + IOC4_SIO_IR_S1_TX_EXPLICIT) +#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ + IOC4_SIO_IR_S2_RX_FULL | \ + IOC4_SIO_IR_S2_RX_HIGH | \ + IOC4_SIO_IR_S2_RX_TIMER | \ + IOC4_SIO_IR_S2_DELTA_DCD | \ + IOC4_SIO_IR_S2_DELTA_CTS | \ + IOC4_SIO_IR_S2_INT | \ + IOC4_SIO_IR_S2_TX_EXPLICIT) +#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ + IOC4_SIO_IR_S3_RX_FULL | \ + IOC4_SIO_IR_S3_RX_HIGH | \ + IOC4_SIO_IR_S3_RX_TIMER | \ + IOC4_SIO_IR_S3_DELTA_DCD | \ + IOC4_SIO_IR_S3_DELTA_CTS | \ + IOC4_SIO_IR_S3_INT | \ + IOC4_SIO_IR_S3_TX_EXPLICIT) + +/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */ +#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */ +#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */ +#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */ +#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */ +#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */ +#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */ +#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Kbd/mouse intr */ +#define IOC4_OTHER_IR_ATA_DMAINT 0x00000089 /* ATAPI DMA intr */ +#define IOC4_OTHER_IR_RT_INT 0x00800000 /* RT output pulse */ +#define IOC4_OTHER_IR_GEN_INT1 0x02000000 /* RT input pulse */ +#define IOC4_OTHER_IR_GEN_INT_SHIFT 25 + +/* Per device interrupt masks */ +#define IOC4_OTHER_IR_ATA (IOC4_OTHER_IR_ATA_INT | \ + IOC4_OTHER_IR_ATA_MEMERR | \ + IOC4_OTHER_IR_ATA_DMAINT) +#define IOC4_OTHER_IR_RT (IOC4_OTHER_IR_RT_INT | IOC4_OTHER_IR_GEN_INT1) + +/* Macro to load pending interrupts */ +#define IOC4_PENDING_SIO_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \ + PCI_INW(&((mem)->sio_ies_ro))) +#define IOC4_PENDING_OTHER_INTRS(mem) (PCI_INW(&((mem)->other_ir)) & \ + PCI_INW(&((mem)->other_ies_ro))) + +/* Bitmasks for IOC4_SIO_CR */ +#define IOC4_SIO_SR_CMD_PULSE 0x00000004 /* Byte bus strobe length */ +#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 +#define IOC4_SIO_CR_ARB_DIAG 0x00000070 /* Current non-ATA PCI bus + requester (ro) */ +#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000 +#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010 +#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020 +#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030 +#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040 +#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050 +#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060 +#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070 +#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among + serial ports (ro) */ +#define IOC4_SIO_CR_ATA_DIAG_IDLE 0x00000100 /* 0 -> active request from + ATA port */ +#define IOC4_SIO_CR_ATA_DIAG_ACTIVE 0x00000200 /* 1 -> ATA request is winner */ + +/* Bitmasks for IOC4_INT_OUT */ +#define IOC4_INT_OUT_COUNT 0x0000ffff /* Pulse interval timer */ +#define IOC4_INT_OUT_MODE 0x00070000 /* Mode mask */ +#define IOC4_INT_OUT_MODE_0 0x00000000 /* Set output to 0 */ +#define IOC4_INT_OUT_MODE_1 0x00040000 /* Set output to 1 */ +#define IOC4_INT_OUT_MODE_1PULSE 0x00050000 /* Send 1 pulse */ +#define IOC4_INT_OUT_MODE_PULSES 0x00060000 /* Send 1 pulse every interval */ +#define IOC4_INT_OUT_MODE_SQW 0x00070000 /* Toggle output every interval */ +#define IOC4_INT_OUT_DIAG 0x40000000 /* Diag mode */ +#define IOC4_INT_OUT_INT_OUT 0x80000000 /* Current state of INT_OUT */ + +/* Time constants for IOC4_INT_OUT */ +#define IOC4_INT_OUT_NS_PER_TICK (15 * 520) /* 15 ns PCI clock, multi=520 */ +#define IOC4_INT_OUT_TICKS_PER_PULSE 3 /* Outgoing pulse lasts 3 + ticks */ +#define IOC4_INT_OUT_US_TO_COUNT(x) /* Convert uS to a count value */ \ + (((x) * 10 + IOC4_INT_OUT_NS_PER_TICK / 200) * \ + 100 / IOC4_INT_OUT_NS_PER_TICK - 1) +#define IOC4_INT_OUT_COUNT_TO_US(x) /* Convert count value to uS */ \ + (((x) + 1) * IOC4_INT_OUT_NS_PER_TICK / 1000) +#define IOC4_INT_OUT_MIN_TICKS 3 /* Min period is width of + pulse in "ticks" */ +#define IOC4_INT_OUT_MAX_TICKS IOC4_INT_OUT_COUNT /* Largest possible count */ + +/* Bitmasks for IOC4_GPCR */ +#define IOC4_GPCR_DIR 0x000000ff /* Tristate pin in or out */ +#define IOC4_GPCR_DIR_PIN(x) (1<<(x)) /* Access one of the DIR bits */ +#define IOC4_GPCR_EDGE 0x0000ff00 /* Extint edge or level + sensitive */ +#define IOC4_GPCR_EDGE_PIN(x) (1<<((x)+7 )) /* Access one of the EDGE bits */ + +/* Values for IOC4_GPCR */ +#define IOC4_GPCR_INT_OUT_EN 0x00100000 /* Enable INT_OUT to pin 0 */ +#define IOC4_GPCR_DIR_SER0_XCVR 0x00000010 /* Port 0 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER1_XCVR 0x00000020 /* Port 1 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER2_XCVR 0x00000040 /* Port 2 Transceiver select + enable */ +#define IOC4_GPCR_DIR_SER3_XCVR 0x00000080 /* Port 3 Transceiver select + enable */ + +/* Defs for some of the generic I/O pins */ +#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 + mode sel */ +#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 + mode sel */ +#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 + mode sel */ +#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 + mode sel */ + +#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling + uart 0 mode select */ +#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling + uart 1 mode select */ +#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling + uart 2 mode select */ +#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling + uart 3 mode select */ + +/* Bitmasks for IOC4_ATA_TIMING */ +#define IOC4_ATA_TIMING_ADR_SETUP 0x00000003 /* Clocks of addr set-up */ +#define IOC4_ATA_TIMING_PULSE_WIDTH 0x000001f8 /* Clocks of read or write + pulse width */ +#define IOC4_ATA_TIMING_RECOVERY 0x0000fe00 /* Clocks before next read + or write */ +#define IOC4_ATA_TIMING_USE_IORDY 0x00010000 /* PIO uses IORDY */ + +/* Bitmasks for address list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_ALE_DMA_ADDRESS 0xfffffffffffffffe + +/* Bitmasks for byte count list elements pointed to by IOC4_ATA_DMA_PTR_ */ +#define IOC4_ATA_BCLE_BYTE_COUNT 0x000000000000fffe +#define IOC4_ATA_BCLE_LIST_END 0x0000000080000000 + +/* Bitmasks for IOC4_ATA_BC_ */ +#define IOC4_ATA_BC_BYTE_CNT 0x0001fffe /* Byte count */ + +/* Bitmasks for IOC4_ATA_DMA_CTRL */ +#define IOC4_ATA_DMA_CTRL_STRAT 0x00000001 /* 1 -> start DMA engine */ +#define IOC4_ATA_DMA_CTRL_STOP 0x00000002 /* 1 -> stop DMA engine */ +#define IOC4_ATA_DMA_CTRL_DIR 0x00000004 /* 1 -> ATA bus data copied + to memory */ +#define IOC4_ATA_DMA_CTRL_ACTIVE 0x00000008 /* DMA channel is active */ +#define IOC4_ATA_DMA_CTRL_MEM_ERROR 0x00000010 /* DMA engine encountered + a PCI error */ +/* Bitmasks for IOC4_KM_CSR */ +#define IOC4_KM_CSR_K_WRT_PEND 0x00000001 /* Kbd port xmitting or resetting */ +#define IOC4_KM_CSR_M_WRT_PEND 0x00000002 /* Mouse port xmitting or resetting */ +#define IOC4_KM_CSR_K_LCB 0x00000004 /* Line Cntrl Bit for last KBD write */ +#define IOC4_KM_CSR_M_LCB 0x00000008 /* Same for mouse */ +#define IOC4_KM_CSR_K_DATA 0x00000010 /* State of kbd data line */ +#define IOC4_KM_CSR_K_CLK 0x00000020 /* State of kbd clock line */ +#define IOC4_KM_CSR_K_PULL_DATA 0x00000040 /* Pull kbd data line low */ +#define IOC4_KM_CSR_K_PULL_CLK 0x00000080 /* Pull kbd clock line low */ +#define IOC4_KM_CSR_M_DATA 0x00000100 /* State of mouse data line */ +#define IOC4_KM_CSR_M_CLK 0x00000200 /* State of mouse clock line */ +#define IOC4_KM_CSR_M_PULL_DATA 0x00000400 /* Pull mouse data line low */ +#define IOC4_KM_CSR_M_PULL_CLK 0x00000800 /* Pull mouse clock line low */ +#define IOC4_KM_CSR_EMM_MODE 0x00001000 /* Emulation mode */ +#define IOC4_KM_CSR_SIM_MODE 0x00002000 /* Clock X8 */ +#define IOC4_KM_CSR_K_SM_IDLE 0x00004000 /* Keyboard is idle */ +#define IOC4_KM_CSR_M_SM_IDLE 0x00008000 /* Mouse is idle */ +#define IOC4_KM_CSR_K_TO 0x00010000 /* Keyboard trying to send/receive */ +#define IOC4_KM_CSR_M_TO 0x00020000 /* Mouse trying to send/receive */ +#define IOC4_KM_CSR_K_TO_EN 0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = + cause SIO_IR to assert */ +#define IOC4_KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */ +#define IOC4_KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */ +#define IOC4_KM_CSR_K_CLAMP_THREE \ + 0x00400000 /* Pull K_CLK low after rec. three chars */ +#define IOC4_KM_CSR_M_CLAMP_THREE \ + 0x00800000 /* Pull M_CLK low after rec. three char */ + +/* Bitmasks for IOC4_K_RD and IOC4_M_RD */ +#define IOC4_KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ +#define IOC4_KM_RD_DATA_2_SHIFT 0 +#define IOC4_KM_RD_DATA_1 0x0000ff00 /* 2nd char recvd since last read */ +#define IOC4_KM_RD_DATA_1_SHIFT 8 +#define IOC4_KM_RD_DATA_0 0x00ff0000 /* 1st char recvd since last read */ +#define IOC4_KM_RD_DATA_0_SHIFT 16 +#define IOC4_KM_RD_FRAME_ERR_2 0x01000000 /* Framing or parity error in byte 2 */ +#define IOC4_KM_RD_FRAME_ERR_1 0x02000000 /* Same for byte 1 */ +#define IOC4_KM_RD_FRAME_ERR_0 0x04000000 /* Same for byte 0 */ + +#define IOC4_KM_RD_KBD_MSE 0x08000000 /* 0 if from kbd, 1 if from mouse */ +#define IOC4_KM_RD_OFLO 0x10000000 /* 4th char recvd before this read */ +#define IOC4_KM_RD_VALID_2 0x20000000 /* DATA_2 valid */ +#define IOC4_KM_RD_VALID_1 0x40000000 /* DATA_1 valid */ +#define IOC4_KM_RD_VALID_0 0x80000000 /* DATA_0 valid */ +#define IOC4_KM_RD_VALID_ALL (IOC4_KM_RD_VALID_0 | IOC4_KM_RD_VALID_1 | \ + IOC4_KM_RD_VALID_2) + +/* Bitmasks for IOC4_K_WD & IOC4_M_WD */ +#define IOC4_KM_WD_WRT_DATA 0x000000ff /* Write to keyboard/mouse port */ +#define IOC4_KM_WD_WRT_DATA_SHIFT 0 + +/* Bitmasks for serial RX status byte */ +#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */ +#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */ +#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */ +#define IOC4_RXSB_BREAK 0x08 /* Break character */ +#define IOC4_RXSB_CTS 0x10 /* State of CTS */ +#define IOC4_RXSB_DCD 0x20 /* State of DCD */ +#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */ +#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR & BREAK valid */ + +/* Bitmasks for serial TX control byte */ +#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */ +#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */ +#define IOC4_TXCB_VALID 0x40 /* Byte is valid */ +#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control register */ +#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */ + +/* Bitmasks for IOC4_SBBR_L */ +#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ +#define IOC4_SBBR_L_BASE 0xfffff000 /* Lower serial ring base addr */ + +/* Bitmasks for IOC4_SSCR_<3:0> */ +#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */ +#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ +#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */ +#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */ +#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */ +#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */ +#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */ +#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */ +#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */ +#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */ +#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */ + +/* All producer/comsumer pointers are the same bitfield */ +#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */ +#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */ +#define IOC4_PROD_CONS_PTR_OFF 3 + +/* Bitmasks for IOC4_STPIR_<3:0> */ +/* Reserved for future register definitions */ + +/* Bitmasks for IOC4_STCIR_<3:0> */ +#define IOC4_STCIR_BYTE_CNT 0x0f000000 /* Bytes in unpacker */ +#define IOC4_STCIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRPIR_<3:0> */ +#define IOC4_SRPIR_BYTE_CNT 0x0f000000 /* Bytes in packer */ +#define IOC4_SRPIR_BYTE_CNT_SHIFT 24 + +/* Bitmasks for IOC4_SRCIR_<3:0> */ +#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */ + +/* Bitmasks for IOC4_SHADOW_<3:0> */ +#define IOC4_SHADOW_DR 0x00000001 /* Data ready */ +#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */ +#define IOC4_SHADOW_PE 0x00000004 /* Parity error */ +#define IOC4_SHADOW_FE 0x00000008 /* Framing error */ +#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */ +#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */ +#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */ +#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */ +#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */ +#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */ +#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */ +#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */ +#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */ +#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */ +#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ +#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ +#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */ + +/* Bitmasks for IOC4_SRTR_<3:0> */ +#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */ +#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */ +#define IOC4_SRTR_CNT_VAL_SHIFT 16 +#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */ + +/* Serial port register map used for DMA and PIO serial I/O */ +typedef volatile struct ioc4_serialregs { + ioc4reg_t sscr; + ioc4reg_t stpir; + ioc4reg_t stcir; + ioc4reg_t srpir; + ioc4reg_t srcir; + ioc4reg_t srtr; + ioc4reg_t shadow; +} ioc4_sregs_t; + +/* IOC4 UART register map */ +typedef volatile struct ioc4_uartregs { + union { + char rbr; /* read only, DLAB == 0 */ + char thr; /* write only, DLAB == 0 */ + char dll; /* DLAB == 1 */ + } u1; + union { + char ier; /* DLAB == 0 */ + char dlm; /* DLAB == 1 */ + } u2; + union { + char iir; /* read only */ + char fcr; /* write only */ + } u3; + char i4u_lcr; + char i4u_mcr; + char i4u_lsr; + char i4u_msr; + char i4u_scr; +} ioc4_uart_t; + +#define i4u_rbr u1.rbr +#define i4u_thr u1.thr +#define i4u_dll u1.dll +#define i4u_ier u2.ier +#define i4u_dlm u2.dlm +#define i4u_iir u3.iir +#define i4u_fcr u3.fcr + +/* PCI config space register map */ +typedef volatile struct ioc4_configregs { + ioc4reg_t pci_id; + ioc4reg_t pci_scr; + ioc4reg_t pci_rev; + ioc4reg_t pci_lat; + ioc4reg_t pci_bar0; + ioc4reg_t pci_bar1; + ioc4reg_t pci_bar2_not_implemented; + ioc4reg_t pci_cis_ptr_not_implemented; + ioc4reg_t pci_sidv; + ioc4reg_t pci_rom_bar_not_implemented; + ioc4reg_t pci_cap; + ioc4reg_t pci_rsv; + ioc4reg_t pci_latgntint; + + char pci_fill1[0x58 - 0x3c - 4]; + + ioc4reg_t pci_pcix; + ioc4reg_t pci_pcixstatus; +} ioc4_cfg_t; + +/* PCI memory space register map addressed using pci_bar0 */ +typedef volatile struct ioc4_memregs { + + /* Miscellaneous IOC4 registers */ + ioc4reg_t pci_err_addr_l; + ioc4reg_t pci_err_addr_h; + ioc4reg_t sio_ir; + ioc4reg_t other_ir; + + /* These registers are read-only for general kernel code. To + * modify them use the functions in ioc4.c. + */ + ioc4reg_t sio_ies_ro; + ioc4reg_t other_ies_ro; + ioc4reg_t sio_iec_ro; + ioc4reg_t other_iec_ro; + ioc4reg_t sio_cr; + ioc4reg_t misc_fill1; + ioc4reg_t int_out; + ioc4reg_t misc_fill2; + ioc4reg_t gpcr_s; + ioc4reg_t gpcr_c; + ioc4reg_t gpdr; + ioc4reg_t misc_fill3; + ioc4reg_t gppr_0; + ioc4reg_t gppr_1; + ioc4reg_t gppr_2; + ioc4reg_t gppr_3; + ioc4reg_t gppr_4; + ioc4reg_t gppr_5; + ioc4reg_t gppr_6; + ioc4reg_t gppr_7; + + char misc_fill4[0x100 - 0x5C - 4]; + + /* ATA/ATAP registers */ + ioc4reg_t ata_0; + ioc4reg_t ata_1; + ioc4reg_t ata_2; + ioc4reg_t ata_3; + ioc4reg_t ata_4; + ioc4reg_t ata_5; + ioc4reg_t ata_6; + ioc4reg_t ata_7; + ioc4reg_t ata_aux; + + char ata_fill1[0x140 - 0x120 - 4]; + + ioc4reg_t ata_timing; + ioc4reg_t ata_dma_ptr_l; + ioc4reg_t ata_dma_ptr_h; + ioc4reg_t ata_dma_addr_l; + ioc4reg_t ata_dma_addr_h; + ioc4reg_t ata_bc_dev; + ioc4reg_t ata_bc_mem; + ioc4reg_t ata_dma_ctrl; + + char ata_fill2[0x200 - 0x15C - 4]; + + /* Keyboard and mouse registers */ + ioc4reg_t km_csr; + ioc4reg_t k_rd; + ioc4reg_t m_rd; + ioc4reg_t k_wd; + ioc4reg_t m_wd; + + char km_fill1[0x300 - 0x210 - 4]; + + /* Serial port registers used for DMA serial I/O */ + ioc4reg_t sbbr01_l; + ioc4reg_t sbbr01_h; + ioc4reg_t sbbr23_l; + ioc4reg_t sbbr23_h; + + ioc4_sregs_t port_0; + ioc4_sregs_t port_1; + ioc4_sregs_t port_2; + ioc4_sregs_t port_3; + + ioc4_uart_t uart_0; + ioc4_uart_t uart_1; + ioc4_uart_t uart_2; + ioc4_uart_t uart_3; +} ioc4_mem_t; + +#endif /* 0 */ + +/* + * Bytebus device space + */ +#define IOC4_BYTEBUS_DEV0 0x80000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV1 0xA0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV2 0xC0000L /* Addressed using pci_bar0 */ +#define IOC4_BYTEBUS_DEV3 0xE0000L /* Addressed using pci_bar0 */ + +#if 0 +/* UART clock speed */ +#define IOC4_SER_XIN_CLK 66000000 + +typedef enum ioc4_subdevs_e { + ioc4_subdev_generic, + ioc4_subdev_kbms, + ioc4_subdev_tty0, + ioc4_subdev_tty1, + ioc4_subdev_tty2, + ioc4_subdev_tty3, + ioc4_subdev_rt, + ioc4_nsubdevs +} ioc4_subdev_t; + +/* Subdevice disable bits, + * from the standard INFO_LBL_SUBDEVS + */ +#define IOC4_SDB_TTY0 (1 << ioc4_subdev_tty0) +#define IOC4_SDB_TTY1 (1 << ioc4_subdev_tty1) +#define IOC4_SDB_TTY2 (1 << ioc4_subdev_tty2) +#define IOC4_SDB_TTY3 (1 << ioc4_subdev_tty3) +#define IOC4_SDB_KBMS (1 << ioc4_subdev_kbms) +#define IOC4_SDB_RT (1 << ioc4_subdev_rt) +#define IOC4_SDB_GENERIC (1 << ioc4_subdev_generic) + +#define IOC4_ALL_SUBDEVS ((1 << ioc4_nsubdevs) - 1) + +#define IOC4_SDB_SERIAL (IOC4_SDB_TTY0 | IOC4_SDB_TTY1 | IOC4_SDB_TTY2 | IOC4_SDB_TTY3) + +#define IOC4_STD_SUBDEVS IOC4_ALL_SUBDEVS + +#define IOC4_INTA_SUBDEVS (IOC4_SDB_SERIAL | IOC4_SDB_KBMS | IOC4_SDB_RT | IOC4_SDB_GENERIC) + +extern int ioc4_subdev_enabled(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_enables(vertex_hdl_t, ulong_t); +extern void ioc4_subdev_enable(vertex_hdl_t, ioc4_subdev_t); +extern void ioc4_subdev_disable(vertex_hdl_t, ioc4_subdev_t); + +/* Macros to read and write the SIO_IEC and SIO_IES registers (see the + * comments in ioc4.c for details on why this is necessary + */ +#define IOC4_W_IES 0 +#define IOC4_W_IEC 1 +extern void ioc4_write_ireg(void *, ioc4reg_t, int, ioc4_intr_type_t); + +#define IOC4_WRITE_IES(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IES, type) +#define IOC4_WRITE_IEC(ioc4, val, type) ioc4_write_ireg(ioc4, val, IOC4_W_IEC, type) + +typedef void +ioc4_intr_func_f (intr_arg_t, ioc4reg_t); + +typedef void +ioc4_intr_connect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl, + vertex_hdl_t intr_dev_vhdl, + int (*)(intr_arg_t)); + +typedef void +ioc4_intr_disconnect_f (vertex_hdl_t conn_vhdl, + ioc4_intr_type_t, + ioc4reg_t, + ioc4_intr_func_f *, + intr_arg_t info, + vertex_hdl_t owner_vhdl); + +ioc4_intr_disconnect_f ioc4_intr_disconnect; +ioc4_intr_connect_f ioc4_intr_connect; + +extern int ioc4_is_console(vertex_hdl_t conn_vhdl); + +extern void ioc4_mlreset(ioc4_cfg_t *, ioc4_mem_t *); + +extern intr_func_f ioc4_intr; + +extern ioc4_mem_t *ioc4_mem_ptr(void *ioc4_fastinfo); + +typedef ioc4_intr_func_f *ioc4_intr_func_t; + +#endif /* 0 */ +#endif /* _ASM_IA64_SN_IOC4_H */ diff -Nru a/include/asm-ia64/sn/ioerror.h b/include/asm-ia64/sn/ioerror.h --- a/include/asm-ia64/sn/ioerror.h Sat Feb 15 09:40:41 2003 +++ b/include/asm-ia64/sn/ioerror.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_H #define _ASM_IA64_SN_IOERROR_H @@ -108,7 +108,7 @@ * we have a single structure, and the appropriate fields get filled in * at each layer. * - This provides a way to dump all error related information in any layer - * of error handling (debugging aid). + * of erorr handling (debugging aid). * * A second possibility is to allow each layer to define its own error * data structure, and fill in the proper fields. This has the advantage diff -Nru a/include/asm-ia64/sn/ioerror_handling.h b/include/asm-ia64/sn/ioerror_handling.h --- a/include/asm-ia64/sn/ioerror_handling.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/ioerror_handling.h Fri May 16 04:18:18 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOERROR_HANDLING_H #define _ASM_IA64_SN_IOERROR_HANDLING_H @@ -207,26 +207,17 @@ /* Error state interfaces */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -extern error_return_code_t error_state_set(devfs_handle_t,error_state_t); -extern error_state_t error_state_get(devfs_handle_t); +extern error_return_code_t error_state_set(vertex_hdl_t,error_state_t); +extern error_state_t error_state_get(vertex_hdl_t); #endif -/* System critical graph interfaces */ - -extern boolean_t is_sys_critical_vertex(devfs_handle_t); -extern devfs_handle_t sys_critical_first_child_get(devfs_handle_t); -extern devfs_handle_t sys_critical_next_child_get(devfs_handle_t); -extern devfs_handle_t sys_critical_parent_get(devfs_handle_t); -extern error_return_code_t sys_critical_graph_vertex_add(devfs_handle_t, - devfs_handle_t new); - /* Error action interfaces */ -extern error_return_code_t error_action_set(devfs_handle_t, +extern error_return_code_t error_action_set(vertex_hdl_t, error_action_f, error_context_t, error_priority_t); -extern error_return_code_t error_action_perform(devfs_handle_t); +extern error_return_code_t error_action_perform(vertex_hdl_t); #define INFO_LBL_ERROR_SKIP_ENV "error_skip_env" @@ -243,14 +234,14 @@ hwgraph_info_remove_LBL(v, INFO_LBL_ERROR_SKIP_ENV, 0) /* Skip point interfaces */ -extern error_return_code_t error_skip_point_jump(devfs_handle_t, boolean_t); -extern error_return_code_t error_skip_point_clear(devfs_handle_t); +extern error_return_code_t error_skip_point_jump(vertex_hdl_t, boolean_t); +extern error_return_code_t error_skip_point_clear(vertex_hdl_t); /* REFERENCED */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) inline static int -error_skip_point_mark(devfs_handle_t v) +error_skip_point_mark(vertex_hdl_t v) { label_t *error_env = NULL; int code = 0; @@ -283,10 +274,10 @@ typedef uint64_t counter_t; -extern counter_t error_retry_count_get(devfs_handle_t); -extern error_return_code_t error_retry_count_set(devfs_handle_t,counter_t); -extern counter_t error_retry_count_increment(devfs_handle_t); -extern counter_t error_retry_count_decrement(devfs_handle_t); +extern counter_t error_retry_count_get(vertex_hdl_t); +extern error_return_code_t error_retry_count_set(vertex_hdl_t,counter_t); +extern counter_t error_retry_count_increment(vertex_hdl_t); +extern counter_t error_retry_count_decrement(vertex_hdl_t); /* Except for the PIO Read error typically the other errors are handled in * the context of an asynchronous error interrupt. @@ -298,7 +289,7 @@ * thru the calls the io error handling layer. */ #if defined(CONFIG_SGI_IO_ERROR_HANDLING) -extern boolean_t is_device_shutdown(devfs_handle_t); +extern boolean_t is_device_shutdown(vertex_hdl_t); #define IS_DEVICE_SHUTDOWN(_d) (is_device_shutdown(_d)) #endif diff -Nru a/include/asm-ia64/sn/iograph.h b/include/asm-ia64/sn/iograph.h --- a/include/asm-ia64/sn/iograph.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/iograph.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_IOGRAPH_H #define _ASM_IA64_SN_IOGRAPH_H @@ -77,7 +77,7 @@ #define EDGE_LBL_IOC3 "ioc3" #define EDGE_LBL_LUN "lun" #define EDGE_LBL_LINUX "linux" -#define EDGE_LBL_LINUX_BUS EDGE_LBL_LINUX "/busnum" +#define EDGE_LBL_LINUX_BUS EDGE_LBL_LINUX "/bus/pci-x" #define EDGE_LBL_MACE "mace" /* O2 mace */ #define EDGE_LBL_MACHDEP "machdep" /* Platform depedent devices */ #define EDGE_LBL_MASTER ".master" @@ -127,8 +127,12 @@ #define EDGE_LBL_XBOX_RPS "xbox_rps" /* redundant power supply for xbox unit */ #define EDGE_LBL_IOBRICK "iobrick" #define EDGE_LBL_PBRICK "Pbrick" +#define EDGE_LBL_PEBRICK "PEbrick" +#define EDGE_LBL_PXBRICK "PXbrick" +#define EDGE_LBL_IXBRICK "IXbrick" #define EDGE_LBL_IBRICK "Ibrick" #define EDGE_LBL_XBRICK "Xbrick" +#define EDGE_LBL_CGBRICK "CGbrick" #define EDGE_LBL_CPUBUS "cpubus" /* CPU Interfaces (SysAd) */ /* vertex info labels in hwgraph */ @@ -211,7 +215,7 @@ #include /* For get MAX_PORT_NUM */ int io_brick_map_widget(int, int); -int io_path_map_widget(devfs_handle_t); +int io_path_map_widget(vertex_hdl_t); /* * Map a brick's widget number to a meaningful int diff -Nru a/include/asm-ia64/sn/klclock.h b/include/asm-ia64/sn/klclock.h --- a/include/asm-ia64/sn/klclock.h Tue Dec 3 10:07:32 2002 +++ b/include/asm-ia64/sn/klclock.h Fri May 16 04:18:18 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1996, 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1996, 2001-2003 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 2001 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCLOCK_H diff -Nru a/include/asm-ia64/sn/klconfig.h b/include/asm-ia64/sn/klconfig.h --- a/include/asm-ia64/sn/klconfig.h Tue Feb 25 09:45:30 2003 +++ b/include/asm-ia64/sn/klconfig.h Fri May 16 04:18:17 2003 @@ -6,7 +6,7 @@ * * Derived from IRIX . * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLCONFIG_H @@ -46,18 +46,8 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN1 -#include -#endif - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif - -#ifdef CONFIG_IA64_SGI_SN2 #include -#endif #define KLCFGINFO_MAGIC 0xbeedbabe @@ -398,6 +388,12 @@ #define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) #define KLTYPE_PBRICK (KLCLASS_IOBRICK | 0x2) #define KLTYPE_XBRICK (KLCLASS_IOBRICK | 0x3) +#define KLTYPE_NBRICK (KLCLASS_IOBRICK | 0x4) +#define KLTYPE_PEBRICK (KLCLASS_IOBRICK | 0x5) +#define KLTYPE_PXBRICK (KLCLASS_IOBRICK | 0x6) +#define KLTYPE_IXBRICK (KLCLASS_IOBRICK | 0x7) +#define KLTYPE_CGBRICK (KLCLASS_IOBRICK | 0x8) + #define KLTYPE_PBRICK_BRIDGE KLTYPE_PBRICK @@ -437,11 +433,7 @@ unsigned char brd_flags; /* Enabled, Disabled etc */ unsigned char brd_slot; /* slot number */ unsigned short brd_debugsw; /* Debug switches */ -#ifdef CONFIG_IA64_SGI_SN2 geoid_t brd_geoid; /* geo id */ -#else - moduleid_t brd_module; /* module to which it belongs */ -#endif partid_t brd_partition; /* Partition number */ unsigned short brd_diagval; /* diagnostic value */ unsigned short brd_diagparm; /* diagnostic parameter */ @@ -452,13 +444,11 @@ klconf_off_t brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */ klconf_off_t brd_errinfo; /* Board's error information */ struct lboard_s *brd_parent; /* Logical parent for this brd */ - devfs_handle_t brd_graph_link; /* vertex hdl to connect extern compts */ + vertex_hdl_t brd_graph_link; /* vertex hdl to connect extern compts */ confidence_t brd_confidence; /* confidence that the board is bad */ nasid_t brd_owner; /* who owns this board */ unsigned char brd_nic_flags; /* To handle 8 more NICs */ -#ifdef CONFIG_IA64_SGI_SN2 char pad[32]; /* future expansion */ -#endif char brd_name[32]; } lboard_t; @@ -491,7 +481,8 @@ ((_brd)->brd_next ? \ (NODE_OFFSET_TO_LBOARD(NASID_GET(_brd), (_brd)->brd_next)): NULL) #define KLCF_COMP(_brd, _ndx) \ - (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)])) + ((((_brd)->brd_compts[(_ndx)]) == 0) ? 0 : \ + (NODE_OFFSET_TO_KLINFO(NASID_GET(_brd), (_brd)->brd_compts[(_ndx)]))) #define KLCF_COMP_ERROR(_brd, _comp) \ (NODE_OFFSET_TO_K0(NASID_GET(_brd), (_comp)->errinfo)) @@ -626,9 +617,7 @@ nasid_t port_nasid; unsigned char port_flag; klconf_off_t port_offset; -#ifdef CONFIG_IA64_SGI_SN2 short port_num; -#endif } klport_t; typedef struct klcpu_s { /* CPU */ @@ -638,9 +627,7 @@ unsigned short cpu_speed; /* Speed in MHZ */ unsigned short cpu_scachesz; /* secondary cache size in MB */ unsigned short cpu_scachespeed;/* secondary cache speed in MHz */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klcpu_t ; #define CPU_STRUCT_VERSION 2 @@ -648,28 +635,20 @@ typedef struct klhub_s { /* HUB */ klinfo_t hub_info; uint hub_flags; /* PCFG_HUB_xxx flags */ -#ifdef CONFIG_IA64_SGI_SN2 #define MAX_NI_PORTS 2 klport_t hub_port[MAX_NI_PORTS + 1];/* hub is connected to this */ -#else - klport_t hub_port; /* hub is connected to this */ -#endif nic_t hub_box_nic; /* nic of containing box */ klconf_off_t hub_mfg_nic; /* MFG NIC string */ u64 hub_speed; /* Speed of hub in HZ */ -#ifdef CONFIG_IA64_SGI_SN2 moduleid_t hub_io_module; /* attached io module */ unsigned long pad; -#endif } klhub_t ; typedef struct klhub_uart_s { /* HUB */ klinfo_t hubuart_info; uint hubuart_flags; /* PCFG_HUB_xxx flags */ nic_t hubuart_box_nic; /* nic of containing box */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klhub_uart_t ; #define MEMORY_STRUCT_VERSION 2 @@ -680,9 +659,7 @@ short membnk_dimm_select; /* bank to physical addr mapping*/ short membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */ short membnk_attr; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmembnk_t ; #define KLCONFIG_MEMBNK_SIZE(_info, _bank) \ @@ -701,9 +678,7 @@ char snum_str[MAX_SERIAL_NUM_SIZE]; unsigned long long snum_int; } snum; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmod_serial_num_t; /* Macros needed to access serial number structure in lboard_t. @@ -721,9 +696,7 @@ klport_t xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */ int xbow_master_hub_link; /* type of brd connected+component struct ptr+flags */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klxbow_t ; #define MAX_PCI_SLOTS 8 @@ -742,9 +715,7 @@ pci_t pci_specific ; /* PCI Board config info */ klpci_device_t bri_devices[MAX_PCI_DEVS] ; /* PCI IDs */ klconf_off_t bri_mfg_nic ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klbri_t ; #define MAX_IOC3_TTY 2 @@ -758,9 +729,7 @@ klinfo_t ioc3_enet ; klconf_off_t ioc3_enet_off ; klconf_off_t ioc3_kbd_off ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klioc3_t ; #define MAX_VME_SLOTS 8 @@ -769,18 +738,14 @@ klinfo_t vmeb_info ; vmeb_t vmeb_specific ; klconf_off_t vmeb_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klvmeb_t ; typedef struct klvmed_s { /* VME DEVICE - VME BOARD */ klinfo_t vmed_info ; vmed_t vmed_specific ; klconf_off_t vmed_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klvmed_t ; #define ROUTER_VECTOR_VERS 2 @@ -793,9 +758,7 @@ klport_t rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */ klconf_off_t rou_mfg_nic ; /* MFG NIC string */ u64 rou_vector; /* vector from master node */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klrou_t ; /* @@ -820,25 +783,19 @@ graphics_t gfx_specific; klconf_off_t pad0; /* for compatibility with older proms */ klconf_off_t gfx_mfg_nic; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klgfx_t; typedef struct klxthd_s { klinfo_t xthd_info ; klconf_off_t xthd_mfg_nic ; /* MFG NIC string */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klxthd_t ; typedef struct kltpu_s { /* TPU board */ klinfo_t tpu_info ; klconf_off_t tpu_mfg_nic ; /* MFG NIC string */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } kltpu_t ; typedef struct klgsn_s { /* GSN board */ @@ -860,9 +817,7 @@ scsi_t scsi_specific ; unsigned char scsi_numdevs ; klconf_off_t scsi_devinfo[MAX_SCSI_DEVS] ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscsi_t ; typedef struct klscctl_s { /* SCSI Controller */ @@ -870,49 +825,37 @@ uint type; uint scsi_buscnt; /* # busses this cntlr */ void *scsi_bus[2]; /* Pointer to 2 klscsi_t's */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscctl_t ; typedef struct klscdev_s { /* SCSI device */ klinfo_t scdev_info ; struct scsidisk_data *scdev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klscdev_t ; typedef struct klttydev_s { /* TTY device */ klinfo_t ttydev_info ; struct terminal_data *ttydev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klttydev_t ; typedef struct klenetdev_s { /* ENET device */ klinfo_t enetdev_info ; struct net_data *enetdev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klenetdev_t ; typedef struct klkbddev_s { /* KBD device */ klinfo_t kbddev_info ; struct keyboard_data *kbddev_cfg ; /* driver fills up this */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klkbddev_t ; typedef struct klmsdev_s { /* mouse device */ klinfo_t msdev_info ; void *msdev_cfg ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmsdev_t ; #define MAX_FDDI_DEVS 10 /* XXX Is this true */ @@ -921,17 +864,13 @@ klinfo_t fddi_info ; fddi_t fddi_specific ; klconf_off_t fddi_devinfo[MAX_FDDI_DEVS] ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klfddi_t ; typedef struct klmio_s { /* MIO */ klinfo_t mio_info ; mio_t mio_specific ; -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klmio_t ; /* @@ -942,9 +881,7 @@ klinfo_t usb_info; /* controller info */ void *usb_bus; /* handle to usb_bus_t */ uint64_t usb_controller; /* ptr to controller info */ -#ifdef CONFIG_IA64_SGI_SN2 unsigned long pad; -#endif } klusb_t ; typedef union klcomp_s { @@ -1028,37 +965,18 @@ extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); -extern xwidgetnum_t nodevertex_widgetnum_get(devfs_handle_t node_vtx); -extern devfs_handle_t nodevertex_xbow_peer_get(devfs_handle_t node_vtx); extern lboard_t *find_gfxpipe(int pipenum); -extern void setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum); extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class); -#ifdef CONFIG_IA64_SGI_SN2 -extern lboard_t *find_lboard_module_class(lboard_t *start, geoid_t geoid, - unsigned char brd_class); -#else -extern lboard_t *find_lboard_module_class(lboard_t *start, moduleid_t mod, - unsigned char brd_class); -#endif extern lboard_t *find_nic_lboard(lboard_t *, nic_t); extern lboard_t *find_nic_type_lboard(nasid_t, unsigned char, nic_t); -#ifdef CONFIG_IA64_SGI_SN2 extern lboard_t *find_lboard_modslot(lboard_t *start, geoid_t geoid); extern lboard_t *find_lboard_module(lboard_t *start, geoid_t geoid); -extern lboard_t *get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name); -#else -extern lboard_t *find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot); -extern lboard_t *find_lboard_module(lboard_t *start, moduleid_t mod); -extern lboard_t *get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name); -#endif extern int config_find_nic_router(nasid_t, nic_t, lboard_t **, klrou_t**); extern int config_find_nic_hub(nasid_t, nic_t, lboard_t **, klhub_t**); extern int config_find_xbow(nasid_t, lboard_t **, klxbow_t**); extern int update_klcfg_cpuinfo(nasid_t, int); extern void board_to_path(lboard_t *brd, char *path); -#ifdef CONFIG_IA64_SGI_SN2 extern moduleid_t get_module_id(nasid_t nasid); -#endif extern void nic_name_convert(char *old_name, char *new_name); extern int module_brds(nasid_t nasid, lboard_t **module_brds, int n); extern lboard_t *brd_from_key(uint64_t key); diff -Nru a/include/asm-ia64/sn/kldir.h b/include/asm-ia64/sn/kldir.h --- a/include/asm-ia64/sn/kldir.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/kldir.h Fri May 16 04:18:18 2003 @@ -5,7 +5,7 @@ * * Derived from IRIX , revision 1.21. * - * Copyright (C) 1992-1997,1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_KLDIR_H diff -Nru a/include/asm-ia64/sn/ksys/elsc.h b/include/asm-ia64/sn/ksys/elsc.h --- a/include/asm-ia64/sn/ksys/elsc.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/ksys/elsc.h Fri May 16 04:18:18 2003 @@ -4,89 +4,13 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_ELSC_H #define _ASM_SN_KSYS_ELSC_H #include #include - -#ifdef CONFIG_IA64_SGI_SN1 - -#define ELSC_ACP_MAX 86 /* 84+cr+lf */ -#define ELSC_LINE_MAX (ELSC_ACP_MAX - 2) - -typedef sc_cq_t elsc_cq_t; - -/* - * ELSC structure passed around as handle - */ - -typedef l1sc_t elsc_t; - -void elsc_init(elsc_t *e, nasid_t nasid); - -int elsc_process(elsc_t *e); -int elsc_msg_check(elsc_t *e, char *msg, int msg_max); -int elsc_msg_callback(elsc_t *e, - void (*callback)(void *callback_data, char *msg), - void *callback_data); -char *elsc_errmsg(int code); - -int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len); -int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len); -int elsc_nvram_magic(elsc_t *e); -int elsc_command(elsc_t *e, int only_if_message); -int elsc_parse(elsc_t *e, char *p1, char *p2, char *p3); -int elsc_ust_write(elsc_t *e, uchar_t c); -int elsc_ust_read(elsc_t *e, char *c); - - - -/* - * System controller commands - */ - -int elsc_version(elsc_t *e, char *result); -int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2); -int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2); -int elsc_module_set(elsc_t *e, int module); -int elsc_module_get(elsc_t *e); -int elsc_partition_set(elsc_t *e, int partition); -int elsc_partition_get(elsc_t *e); -int elsc_domain_set(elsc_t *e, int domain); -int elsc_domain_get(elsc_t *e); -int elsc_cluster_set(elsc_t *e, int cluster); -int elsc_cluster_get(elsc_t *e); -int elsc_cell_set(elsc_t *e, int cell); -int elsc_cell_get(elsc_t *e); -int elsc_bist_set(elsc_t *e, char bist_status); -char elsc_bist_get(elsc_t *e); -int elsc_lock(elsc_t *e, int retry_interval_usec, int timeout_usec, u_char lock_val); -int elsc_unlock(elsc_t *e); -int elsc_display_char(elsc_t *e, int led, int chr); -int elsc_display_digit(elsc_t *e, int led, int num, int l_case); -int elsc_display_mesg(elsc_t *e, char *chr); /* 8-char input */ -int elsc_password_set(elsc_t *e, char *password); /* 4-char input */ -int elsc_password_get(elsc_t *e, char *password); /* 4-char output */ -int elsc_rpwr_query(elsc_t *e, int is_master); -int elsc_power_query(elsc_t *e); -int elsc_power_down(elsc_t *e, int sec); -int elsc_power_cycle(elsc_t *e); -int elsc_system_reset(elsc_t *e); -int elsc_dip_switches(elsc_t *e); - -int _elsc_hbt(elsc_t *e, int ival, int rdly); - -#define elsc_hbt_enable(e, ival, rdly) _elsc_hbt(e, ival, rdly) -#define elsc_hbt_disable(e) _elsc_hbt(e, 0, 0) -#define elsc_hbt_send(e) _elsc_hbt(e, 0, 1) - -elsc_t *get_elsc(void); - -#endif /* CONFIG_IA64_SGI_SN1 */ - /* * Error codes diff -Nru a/include/asm-ia64/sn/ksys/l1.h b/include/asm-ia64/sn/ksys/l1.h --- a/include/asm-ia64/sn/ksys/l1.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/ksys/l1.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_KSYS_L1_H @@ -16,162 +16,6 @@ #include #include - -#ifdef CONFIG_IA64_SGI_SN1 - -#define BRL1_QSIZE 128 /* power of 2 is more efficient */ -#define BRL1_BUFSZ 264 /* needs to be large enough - * to hold 2 flags, escaped - * CRC, type/subchannel byte, - * and escaped payload - */ - -#define BRL1_IQS 32 -#define BRL1_OQS 4 - - -typedef struct sc_cq_s { - u_char buf[BRL1_QSIZE]; - int ipos, opos, tent_next; -} sc_cq_t; - -/* An l1sc_t struct can be associated with the local (C-brick) L1 or an L1 - * on an R-brick. In the R-brick case, the l1sc_t records a vector path - * to the R-brick's junk bus UART. In the C-brick case, we just use the - * following flag to denote the local uart. - * - * This value can't be confused with a network vector because the least- - * significant nibble of a network vector cannot be greater than 8. - */ -#define BRL1_LOCALHUB_UART ((net_vec_t)0xf) - -/* L1<->Bedrock reserved subchannels */ - -/* console channels */ -#define SC_CONS_CPU0 0x00 -#define SC_CONS_CPU1 0x01 -#define SC_CONS_CPU2 0x02 -#define SC_CONS_CPU3 0x03 - -#define L1_ELSCUART_SUBCH(p) (p) -#define L1_ELSCUART_CPU(ch) (ch) - -#define SC_CONS_SYSTEM CPUS_PER_NODE - -/* mapping subchannels to queues */ -#define MAP_IQ(s) (s) -#define MAP_OQ(s) (s) - -#define BRL1_NUM_SUBCHANS 32 -#define BRL1_CMD_SUBCH 16 -#define BRL1_EVENT_SUBCH (BRL1_NUM_SUBCHANS - 1) -#define BRL1_SUBCH_RSVD 0 -#define BRL1_SUBCH_FREE (-1) - -/* constants for L1 hwgraph vertex info */ -#define CBRICK_L1 (__psint_t)1 -#define IOBRICK_L1 (__psint_t)2 -#define RBRICK_L1 (__psint_t)3 - - -struct l1sc_s; -/* Saved off interrupt frame */ -typedef struct brl1_intr_frame { - int bf_irq; /* irq received */ - void *bf_dev_id; /* device information */ - struct pt_regs *bf_regs; /* register frame */ -} brl1_intr_frame_t; - -typedef void (*brl1_notif_t)(int, void *, struct pt_regs *, struct l1sc_s *, int); -typedef int (*brl1_uartf_t)(struct l1sc_s *); - -/* structure for controlling a subchannel */ -typedef struct brl1_sch_s { - int use; /* if this subchannel is free, - * use == BRL1_SUBCH_FREE */ - uint target; /* type, rack and slot of component to - * which this subchannel is directed */ - atomic_t packet_arrived; /* true if packet arrived on - * this subchannel */ - sc_cq_t * iqp; /* input queue for this subchannel */ - sv_t arrive_sv; /* used to wait for a packet */ - spinlock_t data_lock; /* synchronize access to input queues and - * other fields of the brl1_sch_s struct */ - brl1_notif_t tx_notify; /* notify higher layer that transmission may - * continue */ - brl1_notif_t rx_notify; /* notify higher layer that a packet has been - * received */ - brl1_intr_frame_t irq_frame; /* saved off irq information */ -} brl1_sch_t; - -/* br<->l1 protocol states */ -#define BRL1_IDLE 0 -#define BRL1_FLAG 1 -#define BRL1_HDR 2 -#define BRL1_BODY 3 -#define BRL1_ESC 4 -#define BRL1_RESET 7 - - -/* - * l1sc_t structure-- tracks protocol state, open subchannels, etc. - */ -typedef struct l1sc_s { - nasid_t nasid; /* nasid with which this instance - * of the structure is associated */ - moduleid_t modid; /* module id of this brick */ - u_char verbose; /* non-zero if elscuart routines should - * prefix output */ - net_vec_t uart; /* vector path to UART, or BRL1_LOCALUART */ - int sent; /* number of characters sent */ - int send_len; /* number of characters in send buf */ - brl1_uartf_t putc_f; /* pointer to UART putc function */ - brl1_uartf_t getc_f; /* pointer to UART getc function */ - - spinlock_t send_lock; /* arbitrates send synchronization */ - spinlock_t recv_lock; /* arbitrates uart receive access */ - spinlock_t subch_lock; /* arbitrates subchannel allocation */ - cpuid_t intr_cpu; /* cpu that receives L1 interrupts */ - - u_char send_in_use; /* non-zero if send buffer contains an - * unsent or partially-sent packet */ - u_char fifo_space; /* current depth of UART send FIFO */ - - u_char brl1_state; /* current state of the receive side */ - u_char brl1_last_hdr; /* last header byte received */ - - char send[BRL1_BUFSZ]; /* send buffer */ - - int sol; /* "start of line" (see elscuart routines) */ - int cons_listen; /* non-zero if the elscuart interface should - * also check the system console subchannel */ - brl1_sch_t subch[BRL1_NUM_SUBCHANS]; - /* subchannels provided by link */ - - sc_cq_t garbage_q; /* a place to put unsolicited packets */ - sc_cq_t oq[BRL1_OQS]; /* elscuart output queues */ -} l1sc_t; - - -/* error codes */ -#define BRL1_VALID 0 -#define BRL1_FULL_Q (-1) -#define BRL1_CRC (-2) -#define BRL1_PROTOCOL (-3) -#define BRL1_NO_MESSAGE (-4) -#define BRL1_LINK (-5) -#define BRL1_BUSY (-6) - -#define SC_SUCCESS BRL1_VALID -#define SC_NMSG BRL1_NO_MESSAGE -#define SC_BUSY BRL1_BUSY -#define SC_NOPEN (-7) -#define SC_BADSUBCH (-8) -#define SC_TIMEDOUT (-9) -#define SC_NSUBCH (-10) - -#endif /* CONFIG_IA64_SGI_SN1 */ - /* L1 Target Addresses */ /* * L1 commands and responses use source/target addresses that are @@ -181,39 +25,11 @@ * id (L1 functionality is divided into several independent "tasks" * that can each receive command requests and transmit responses) */ -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_TYPE_SHFT 28 -#define L1_ADDR_TYPE_MASK 0xF0000000 -#else -#define L1_ADDR_TYPE_SHFT 8 -#define L1_ADDR_TYPE_MASK 0xFF00 -#endif /* CONFIG_IA64_SGI_SN1 */ #define L1_ADDR_TYPE_L1 0x00 /* L1 system controller */ #define L1_ADDR_TYPE_L2 0x01 /* L2 system controller */ #define L1_ADDR_TYPE_L3 0x02 /* L3 system controller */ #define L1_ADDR_TYPE_CBRICK 0x03 /* attached C brick */ #define L1_ADDR_TYPE_IOBRICK 0x04 /* attached I/O brick */ - -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_RACK_SHFT 18 -#define L1_ADDR_RACK_MASK 0x0FFC0000 -#define L1_ADDR_RACK_LOCAL 0x3ff /* local brick's rack */ -#else -#define L1_ADDR_RACK_SHFT 16 -#define L1_ADDR_RACK_MASK 0xFFFF00 -#define L1_ADDR_RACK_LOCAL 0xffff /* local brick's rack */ -#endif /* CONFIG_IA64_SGI_SN1 */ - -#ifdef CONFIG_IA64_SGI_SN1 -#define L1_ADDR_BAY_SHFT 12 -#define L1_ADDR_BAY_MASK 0x0003F000 -#define L1_ADDR_BAY_LOCAL 0x3f /* local brick's bay */ -#else -#define L1_ADDR_BAY_SHFT 0 -#define L1_ADDR_BAY_MASK 0xFF -#define L1_ADDR_BAY_LOCAL 0xff /* local brick's bay */ -#endif /* CONFIG_IA64_SGI_SN1 */ - #define L1_ADDR_TASK_SHFT 0 #define L1_ADDR_TASK_MASK 0x0000001F #define L1_ADDR_TASK_INVALID 0x00 /* invalid task */ @@ -296,7 +112,9 @@ #define L1_BRICKTYPE_X 0x58 /* X */ #define L1_BRICKTYPE_X2 0x59 /* Y */ #define L1_BRICKTYPE_N 0x4e /* N */ +#define L1_BRICKTYPE_PE 0x25 /* % */ #define L1_BRICKTYPE_PX 0x23 /* # */ +#define L1_BRICKTYPE_IX 0x3d /* = */ /* EEPROM codes (for the "read EEPROM" request) */ /* c brick */ @@ -339,50 +157,10 @@ #define bzero(d, n) memset((d), 0, (n)) -#ifdef CONFIG_IA64_SGI_SN1 - -#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00) - -/* public interfaces to L1 system controller */ - -int sc_open( l1sc_t *sc, uint target ); -int sc_close( l1sc_t *sc, int ch ); -int sc_construct_msg( l1sc_t *sc, int ch, - char *msg, int msg_len, - uint addr_task, short req_code, - int req_nargs, ... ); -int sc_interpret_resp( char *resp, int resp_nargs, ... ); -int sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait ); -int sc_recv( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block ); -int sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ); -int sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len ); -int sc_poll( l1sc_t *sc, int ch ); -void sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart ); -void sc_intr_enable( l1sc_t *sc ); - -int elsc_rack_bay_get(l1sc_t *e, uint *rack, uint *bay); -int elsc_rack_bay_type_get(l1sc_t *e, uint *rack, - uint *bay, uint *brick_type); -int elsc_cons_subch(l1sc_t *e, uint ch); -int elsc_cons_node(l1sc_t *e); -int elsc_display_line(l1sc_t *e, char *line, int lnum); - -extern l1sc_t *get_elsc( void ); -#define get_l1sc get_elsc -#define get_master_l1sc get_l1sc - -int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, - uint *bay, uint *brick_type ); -int iobrick_module_get( l1sc_t *sc ); -int iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up ); -int iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up ); -int iobrick_sc_version( l1sc_t *sc, char *result ); -#else int elsc_display_line(nasid_t nasid, char *line, int lnum); int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, uint *bay, uint *brick_type ); int iobrick_module_get( nasid_t nasid ); -#endif /* CONFIG_IA64_SGI_SN1 */ #endif /* _ASM_SN_KSYS_L1_H */ diff -Nru a/include/asm-ia64/sn/labelcl.h b/include/asm-ia64/sn/labelcl.h --- a/include/asm-ia64/sn/labelcl.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/labelcl.h Fri May 16 04:18:18 2003 @@ -4,13 +4,11 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_LABELCL_H #define _ASM_IA64_SN_LABELCL_H -#include - #define LABELCL_MAGIC 0x4857434c /* 'HWLC' */ #define LABEL_LENGTH_MAX 256 /* Includes NULL char */ #define INFO_DESC_PRIVATE (-1) /* default */ @@ -77,18 +75,18 @@ extern labelcl_info_t *labelcl_info_create(void); extern int labelcl_info_destroy(labelcl_info_t *); -extern int labelcl_info_add_LBL(struct devfs_entry *, char *, arb_info_desc_t, arbitrary_info_t); -extern int labelcl_info_remove_LBL(struct devfs_entry *, char *, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_replace_LBL(struct devfs_entry *, char *, arb_info_desc_t, +extern int labelcl_info_add_LBL(vertex_hdl_t, char *, arb_info_desc_t, arbitrary_info_t); +extern int labelcl_info_remove_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *); +extern int labelcl_info_replace_LBL(vertex_hdl_t, char *, arb_info_desc_t, arbitrary_info_t, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_get_LBL(struct devfs_entry *, char *, arb_info_desc_t *, +extern int labelcl_info_get_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *); -extern int labelcl_info_get_next_LBL(struct devfs_entry *, char *, arb_info_desc_t *, +extern int labelcl_info_get_next_LBL(vertex_hdl_t, char *, arb_info_desc_t *, arbitrary_info_t *, labelcl_info_place_t *); -extern int labelcl_info_replace_IDX(struct devfs_entry *, int, arbitrary_info_t, +extern int labelcl_info_replace_IDX(vertex_hdl_t, int, arbitrary_info_t, arbitrary_info_t *); -extern int labelcl_info_connectpt_set(struct devfs_entry *, struct devfs_entry *); -extern int labelcl_info_get_IDX(struct devfs_entry *, int, arbitrary_info_t *); -extern struct devfs_entry *device_info_connectpt_get(struct devfs_entry *); +extern int labelcl_info_connectpt_set(vertex_hdl_t, vertex_hdl_t); +extern int labelcl_info_get_IDX(vertex_hdl_t, int, arbitrary_info_t *); +extern struct devfs_handle_t device_info_connectpt_get(vertex_hdl_t); #endif /* _ASM_IA64_SN_LABELCL_H */ diff -Nru a/include/asm-ia64/sn/leds.h b/include/asm-ia64/sn/leds.h --- a/include/asm-ia64/sn/leds.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/leds.h Fri May 16 04:18:17 2003 @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include @@ -13,25 +13,14 @@ #include #include #include - -#ifdef CONFIG_IA64_SGI_SN1 -#define LED0 0xc0000b00100000c0LL -#define LED_CPU_SHIFT 3 -#else #include + #define LED0 (LOCAL_MMR_ADDR(SH_REAL_JUNK_BUS_LED0)) #define LED_CPU_SHIFT 16 -#endif #define LED_CPU_HEARTBEAT 0x01 #define LED_CPU_ACTIVITY 0x02 -#ifdef LED_WAR -#define LED_ALWAYS_SET 0x64 /* SN2 hw workaround: always set 0x60 */ -#define LED_MASK_AUTOTEST 0x9e -#else /* LED_WAR */ #define LED_ALWAYS_SET 0x00 -#define LED_MASK_AUTOTEST 0xfe -#endif /* LED_WAR */ /* * Basic macros for flashing the LEDS on an SGI, SN1. @@ -40,14 +29,8 @@ static __inline__ void set_led_bits(u8 value, u8 mask) { -#if 0 - pda.led_state = (pda.led_state & ~mask) | (value & mask); -#ifdef CONFIG_IA64_SGI_SN1 - *pda.led_address = (long) pda.led_state; -#else - *pda.led_address = (short) pda.led_state; -#endif -#endif + pda->led_state = (pda->led_state & ~mask) | (value & mask); + *pda->led_address = (short) pda->led_state; } #endif /* _ASM_IA64_SN_LEDS_H */ diff -Nru a/include/asm-ia64/sn/mca.h b/include/asm-ia64/sn/mca.h --- a/include/asm-ia64/sn/mca.h Sat Mar 9 02:24:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,128 +0,0 @@ -/* - * File: mca.h - * Purpose: Machine check handling specific to the SN platform defines - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include -#include -#include -#include - -#ifdef CONFIG_IA64_SGI_SN - -typedef u64 __uint64_t; - -typedef struct { - __uint64_t sh_event_occurred; - __uint64_t sh_first_error; - __uint64_t sh_event_overflow; - __uint64_t sh_pi_first_error; - __uint64_t sh_pi_error_summary; - __uint64_t sh_pi_error_overflow; - __uint64_t sh_pi_error_detail_1; - __uint64_t sh_pi_error_detail_2; - __uint64_t sh_pi_hw_time_stamp; - __uint64_t sh_pi_uncorrected_detail_1; - __uint64_t sh_pi_uncorrected_detail_2; - __uint64_t sh_pi_uncorrected_detail_3; - __uint64_t sh_pi_uncorrected_detail_4; - __uint64_t sh_pi_uncor_time_stamp; - __uint64_t sh_pi_corrected_detail_1; - __uint64_t sh_pi_corrected_detail_2; - __uint64_t sh_pi_corrected_detail_3; - __uint64_t sh_pi_corrected_detail_4; - __uint64_t sh_pi_cor_time_stamp; - __uint64_t sh_mem_error_summary; - __uint64_t sh_mem_error_overflow; - __uint64_t sh_misc_err_hdr_lower; - __uint64_t sh_misc_err_hdr_upper; - __uint64_t sh_dir_uc_err_hdr_lower; - __uint64_t sh_dir_uc_err_hdr_upper; - __uint64_t sh_dir_cor_err_hdr_lower; - __uint64_t sh_dir_cor_err_hdr_upper; - __uint64_t sh_mem_error_mask; - __uint64_t sh_md_uncor_time_stamp; - __uint64_t sh_md_cor_time_stamp; - __uint64_t sh_md_hw_time_stamp; - __uint64_t sh_xn_error_summary; - __uint64_t sh_xn_first_error; - __uint64_t sh_xn_error_overflow; - __uint64_t sh_xniilb_error_summary; - __uint64_t sh_xniilb_first_error; - __uint64_t sh_xniilb_error_overflow; - __uint64_t sh_xniilb_error_detail_1; - __uint64_t sh_xniilb_error_detail_2; - __uint64_t sh_xniilb_error_detail_3; - __uint64_t sh_xnpi_error_summary; - __uint64_t sh_xnpi_first_error; - __uint64_t sh_xnpi_error_overflow; - __uint64_t sh_xnpi_error_detail_1; - __uint64_t sh_xnmd_error_summary; - __uint64_t sh_xnmd_first_error; - __uint64_t sh_xnmd_error_overflow; - __uint64_t sh_xnmd_ecc_err_report; - __uint64_t sh_xnmd_error_detail_1; - __uint64_t sh_lb_error_summary; - __uint64_t sh_lb_first_error; - __uint64_t sh_lb_error_overflow; - __uint64_t sh_lb_error_detail_1; - __uint64_t sh_lb_error_detail_2; - __uint64_t sh_lb_error_detail_3; - __uint64_t sh_lb_error_detail_4; - __uint64_t sh_lb_error_detail_5; -} sal_log_shub_state_t; - -typedef struct { -sal_log_section_hdr_t header; - struct - { - __uint64_t err_status : 1, - guid : 1, - oem_data : 1, - reserved : 61; - } valid; - __uint64_t err_status; - efi_guid_t guid; - __uint64_t shub_nic; - sal_log_shub_state_t shub_state; -} sal_log_plat_info_t; - - -extern void sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc); - -#ifdef platform_plat_specific_err_print -#undef platform_plat_specific_err_print -#endif -#define platform_plat_specific_err_print sal_log_plat_print - -#endif /* CONFIG_IA64_SGI_SN */ diff -Nru a/include/asm-ia64/sn/mmtimer_private.h b/include/asm-ia64/sn/mmtimer_private.h --- a/include/asm-ia64/sn/mmtimer_private.h Sat Mar 9 02:24:40 2002 +++ b/include/asm-ia64/sn/mmtimer_private.h Fri May 16 04:18:17 2003 @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. * * Helper file for the SN implementation of mmtimers * diff -Nru a/include/asm-ia64/sn/module.h b/include/asm-ia64/sn/module.h --- a/include/asm-ia64/sn/module.h Mon Feb 24 05:28:24 2003 +++ b/include/asm-ia64/sn/module.h Fri May 16 04:18:17 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_MODULE_H #define _ASM_IA64_SN_MODULE_H @@ -32,9 +32,6 @@ #define MODULE_FORMAT_BRIEF 1 #define MODULE_FORMAT_LONG 2 - -#ifdef CONFIG_IA64_SGI_SN2 - /* * Module id format * @@ -141,6 +138,7 @@ #define MODULE_NBRICK 7 #define MODULE_PEBRICK 8 #define MODULE_PXBRICK 9 +#define MODULE_IXBRICK 10 /* * Moduleid_t comparison macros @@ -150,118 +148,6 @@ ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK))) #define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#else -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) - -/* - * Module id format - * - * 15-12 Brick type (enumerated) - * 11-6 Rack ID (encoded class, group, number) - * 5-0 Brick position in rack (0-63) - */ -/* - * Macros for getting the brick type - */ -#define MODULE_BTYPE_MASK 0xf000 -#define MODULE_BTYPE_SHFT 12 -#define MODULE_GET_BTYPE(_m) (((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT) -#define MODULE_BT_TO_CHAR(_b) (brick_types[(_b)]) -#define MODULE_GET_BTCHAR(_m) (MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m))) - -/* - * Macros for getting the rack ID. - */ -#define MODULE_RACK_MASK 0x0fc0 -#define MODULE_RACK_SHFT 6 -#define MODULE_GET_RACK(_m) (((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT) - -/* - * Macros for getting the brick position - */ -#define MODULE_BPOS_MASK 0x003f -#define MODULE_BPOS_SHFT 0 -#define MODULE_GET_BPOS(_m) (((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT) - -/* - * Macros for constructing moduleid_t's - */ -#define RBT_TO_MODULE(_r, _b, _t) ((_r) << MODULE_RACK_SHFT | \ - (_b) << MODULE_BPOS_SHFT | \ - (_t) << MODULE_BTYPE_SHFT) - -/* - * Macros for encoding and decoding rack IDs - * A rack number consists of three parts: - * class 1 bit, 0==CPU/mixed, 1==I/O - * group 2 bits for CPU/mixed, 3 bits for I/O - * number 3 bits for CPU/mixed, 2 bits for I/O (1 based) - */ -#define RACK_GROUP_BITS(_r) (RACK_GET_CLASS(_r) ? 3 : 2) -#define RACK_NUM_BITS(_r) (RACK_GET_CLASS(_r) ? 2 : 3) - -#define RACK_CLASS_MASK(_r) 0x20 -#define RACK_CLASS_SHFT(_r) 5 -#define RACK_GET_CLASS(_r) \ - (((_r) & RACK_CLASS_MASK(_r)) >> RACK_CLASS_SHFT(_r)) -#define RACK_ADD_CLASS(_r, _c) \ - ((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r)) - -#define RACK_GROUP_SHFT(_r) RACK_NUM_BITS(_r) -#define RACK_GROUP_MASK(_r) \ - ( (((unsigned)1<> RACK_GROUP_SHFT(_r)) -#define RACK_ADD_GROUP(_r, _g) \ - ((_r) |= (_g) << RACK_GROUP_SHFT(_r) & RACK_GROUP_MASK(_r)) - -#define RACK_NUM_SHFT(_r) 0 -#define RACK_NUM_MASK(_r) \ - ( (((unsigned)1<> RACK_NUM_SHFT(_r)) + 1 ) -#define RACK_ADD_NUM(_r, _n) \ - ((_r) |= ((_n) - 1) << RACK_NUM_SHFT(_r) & RACK_NUM_MASK(_r)) - -/* - * Brick type definitions - */ -#define MAX_BRICK_TYPES 16 /* 1 << (MODULE_RACK_SHFT - MODULE_BTYPE_SHFT */ - -extern char brick_types[]; - -#define MODULE_CBRICK 0 -#define MODULE_RBRICK 1 -#define MODULE_IBRICK 2 -#define MODULE_KBRICK 3 -#define MODULE_XBRICK 4 -#define MODULE_DBRICK 5 -#define MODULE_PBRICK 6 -#define MODULE_NBRICK 7 -#define MODULE_PEBRICK 8 -#define MODULE_PXBRICK 9 - -/* - * Moduleid_t comparison macros - */ -/* Don't compare the brick type: only the position is significant */ -#define MODULE_CMP(_m1, _m2) (((_m1)&(MODULE_RACK_MASK|MODULE_BPOS_MASK)) -\ - ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK))) -#define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#else - -/* - * Some code that uses this macro will not be conditionally compiled. - */ -#define MODULE_GET_BTCHAR(_m) ('?') -#define MODULE_CMP(_m1, _m2) ((_m1) - (_m2)) -#define MODULE_MATCH(_m1, _m2) (MODULE_CMP((_m1),(_m2)) == 0) - -#endif /* SN1 */ -#endif /* SN2 */ - typedef struct module_s module_t; struct module_s { @@ -271,23 +157,15 @@ /* List of nodes in this module */ cnodeid_t nodes[MODULE_MAX_NODES]; -#ifdef CONFIG_IA64_SGI_SN2 geoid_t geoid[MODULE_MAX_NODES]; struct { char moduleid[8]; } io[MODULE_MAX_NODES]; -#endif int nodecnt; /* Number of nodes in array */ - /* Fields for Module System Controller */ int mesgpend; /* Message pending */ int shutdown; /* Shutdown in progress */ struct semaphore thdcnt; /* Threads finished counter */ - -#ifdef CONFIG_IA64_SGI_SN1 - elsc_t elsc; - spinlock_t elsclock; -#endif time_t intrhist[MODULE_HIST_CNT]; int histptr; @@ -314,10 +192,6 @@ extern int nummodules; extern module_t *module_lookup(moduleid_t id); - -#if defined(CONFIG_IA64_SGI_SN1) -extern elsc_t *get_elsc(void); -#endif extern int get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info); diff -Nru a/include/asm-ia64/sn/nag.h b/include/asm-ia64/sn/nag.h --- a/include/asm-ia64/sn/nag.h Sat Mar 9 02:24:40 2002 +++ b/include/asm-ia64/sn/nag.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nru a/include/asm-ia64/sn/nic.h b/include/asm-ia64/sn/nic.h --- a/include/asm-ia64/sn/nic.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,129 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_NIC_H -#define _ASM_IA64_SN_NIC_H - -#include -#include -#include - -#define MCR_DATA(x) ((int) ((x) & 1)) -#define MCR_DONE(x) ((x) & 2) -#define MCR_PACK(pulse, sample) ((pulse) << 10 | (sample) << 2) - -typedef __psunsigned_t nic_data_t; - -typedef int -nic_access_f(nic_data_t data, - int pulse, int sample, int delay); - -typedef nic_access_f *nic_access_t; - -typedef struct nic_vmce_s *nic_vmce_t; -typedef void nic_vmc_func(devfs_handle_t v); - -/* - * PRIVATE data for Dallas NIC - */ - -typedef struct nic_state_t { - nic_access_t access; - nic_data_t data; - int last_disc; - int done; - int bit_index; - int disc_marker; - uchar_t bits[64]; -} nic_state_t; - -/* - * Public interface for Dallas NIC - * - * - * Access Routine - * - * nic_setup requires an access routine that pulses the NIC line for a - * specified duration, samples the NIC line after a specified duration, - * then delays for a third specified duration (for precharge). - * - * This general scheme allows us to access NICs through any medium - * (e.g. hub regs, bridge regs, vector writes, system ctlr commands). - * - * The access routine should return the sample value 0 or 1, or if an - * error occurs, return a negative error code. Negative error codes from - * the access routine will abort the NIC operation and be propagated - * through out of the top-level NIC call. - */ - -#define NIC_OK 0 -#define NIC_DONE 1 -#define NIC_FAIL 2 -#define NIC_BAD_CRC 3 -#define NIC_NOT_PRESENT 4 -#define NIC_REDIR_LOOP 5 -#define NIC_PARAM 6 -#define NIC_NOMEM 7 - -uint64_t nic_get_phase_bits(void); - -extern int nic_setup(nic_state_t *ns, - nic_access_t access, - nic_data_t data); - -extern int nic_next(nic_state_t *ns, - char *serial, - char *family, - char *crc); - -extern int nic_read_one_page(nic_state_t *ns, - char *family, - char *serial, - char *crc, - int start, - uchar_t *redirect, - uchar_t *byte); - -extern int nic_read_mfg(nic_state_t *ns, - char *family, - char *serial, - char *crc, - uchar_t *pageA, - uchar_t *pageB); - -extern int nic_info_get(nic_access_t access, - nic_data_t data, - char *info); - -extern int nic_item_info_get(char *buf, char *item, char **item_info); - -nic_access_f nic_access_mcr32; - -extern char *nic_vertex_info_get(devfs_handle_t v); - -extern char *nic_vertex_info_set(nic_access_t access, - nic_data_t data, - devfs_handle_t v); - -extern int nic_vertex_info_match(devfs_handle_t vertex, - char *name); - -extern char *nic_bridge_vertex_info(devfs_handle_t vertex, - nic_data_t data); -extern char *nic_hq4_vertex_info(devfs_handle_t vertex, - nic_data_t data); -extern char *nic_ioc3_vertex_info(devfs_handle_t vertex, - nic_data_t data, - int32_t *gpcr_s); - -extern char *nic_hub_vertex_info(devfs_handle_t vertex); - -extern nic_vmce_t nic_vmc_add(char *, nic_vmc_func *); -extern void nic_vmc_del(nic_vmce_t); - -#endif /* _ASM_IA64_SN_NIC_H */ diff -Nru a/include/asm-ia64/sn/nodepda.h b/include/asm-ia64/sn/nodepda.h --- a/include/asm-ia64/sn/nodepda.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/nodepda.h Fri May 16 04:18:17 2003 @@ -3,27 +3,21 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_NODEPDA_H #define _ASM_IA64_SN_NODEPDA_H #include +#include #include #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#endif #include #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#endif - /* * NUMA Node-Specific Data structures are defined in this file. * In particular, this is the location of the node PDA. @@ -31,23 +25,6 @@ */ /* - * Subnode PDA structures. Each node needs a few data structures that - * correspond to the PIs on the HUB chip that supports the node. - */ -#if defined(CONFIG_IA64_SGI_SN1) -struct subnodepda_s { - intr_vecblk_t intr_dispatch0; - intr_vecblk_t intr_dispatch1; -}; - -typedef struct subnodepda_s subnode_pda_t; - - -struct synergy_perf_s; -#endif - - -/* * Node-specific data structure. * * One of these structures is allocated on each node of a NUMA system. @@ -66,24 +43,20 @@ /* the second cpu on a node is */ /* node_first_cpu+1. */ - devfs_handle_t xbow_vhdl; + vertex_hdl_t xbow_vhdl; nasid_t xbow_peer; /* NASID of our peer hub on xbow */ struct semaphore xbow_sema; /* Sema for xbow synchronization */ slotid_t slotdesc; -#ifdef CONFIG_IA64_SGI_SN2 geoid_t geoid; -#else - moduleid_t module_id; /* Module ID (redundant local copy) */ -#endif module_t *module; /* Pointer to containing module */ xwidgetnum_t basew_id; - devfs_handle_t basew_xc; + vertex_hdl_t basew_xc; int hubticks; int num_routers; /* XXX not setup! Total routers in the system */ char *hwg_node_name; /* hwgraph node name */ - devfs_handle_t node_vertex; /* Hwgraph vertex for this node */ + vertex_hdl_t node_vertex; /* Hwgraph vertex for this node */ void *pdinfo; /* Platform-dependent per-node info */ @@ -95,27 +68,9 @@ /* * The BTEs on this node are shared by the local cpus */ - bteinfo_t bte_if[BTES_PER_NODE]; /* Virtual Interface */ - char bte_cleanup[5 * L1_CACHE_BYTES] ____cacheline_aligned; - -#if defined(CONFIG_IA64_SGI_SN1) - subnode_pda_t snpda[NUM_SUBNODES]; - /* - * New extended memory reference counters - */ - void *migr_refcnt_counterbase; - void *migr_refcnt_counterbuffer; - size_t migr_refcnt_cbsize; - int migr_refcnt_numsets; - hubstat_t hubstats; - int synergy_perf_enabled; - int synergy_perf_freq; - spinlock_t synergy_perf_lock; - uint64_t synergy_inactive_intervals; - uint64_t synergy_active_intervals; - struct synergy_perf_s *synergy_perf_data; - struct synergy_perf_s *synergy_perf_first; /* reporting consistency .. */ -#endif /* CONFIG_IA64_SGI_SN1 */ + struct bteinfo_s bte_if[BTES_PER_NODE]; /* Virtual Interface */ + struct timer_list bte_recovery_timer; + spinlock_t bte_recovery_lock; /* * Array of pointers to the nodepdas for each node. @@ -126,18 +81,16 @@ typedef struct nodepda_s nodepda_t; -#ifdef CONFIG_IA64_SGI_SN2 -#define NR_IVECS 256 struct irqpda_s { int num_irq_used; - char irq_flags[NR_IVECS]; + char irq_flags[NR_IRQS]; + struct pci_dev *device_dev[NR_IRQS]; + char share_count[NR_IRQS]; + struct pci_dev *current; }; typedef struct irqpda_s irqpda_t; -#endif /* CONFIG_IA64_SGI_SN2 */ - - /* * Access Functions for node PDA. @@ -156,21 +109,11 @@ #define nodepda pda->p_nodepda /* Ptr to this node's PDA */ #define NODEPDA(cnode) (nodepda->pernode_pdaindr[cnode]) -#if defined(CONFIG_IA64_SGI_SN1) -#define subnodepda pda.p_subnodepda /* Ptr to this node's subnode PDA */ -#define SUBNODEPDA(cnode,sn) (&(NODEPDA(cnode)->snpda[sn])) -#define SNPDA(npda,sn) (&(npda)->snpda[sn]) -#endif - /* * Macros to access data structures inside nodepda */ -#ifdef CONFIG_IA64_SGI_SN2 #define NODE_MODULEID(cnode) geo_module((NODEPDA(cnode)->geoid)) -#else -#define NODE_MODULEID(cnode) (NODEPDA(cnode)->module_id) -#endif #define NODE_SLOTID(cnode) (NODEPDA(cnode)->slotdesc) @@ -184,8 +127,8 @@ * Check if given a compact node id the corresponding node has all the * cpus disabled. */ -#define is_headless_node(cnode) 0 /*((cnode == CNODEID_NONE) || \ - (node_data(cnode)->active_cpu_count == 0)) */ +#define is_headless_node(cnode) ((cnode == CNODEID_NONE) || \ + (node_data(cnode)->active_cpu_count == 0)) /* * Check if given a node vertex handle the corresponding node has all the diff -Nru a/include/asm-ia64/sn/pci/bridge.h b/include/asm-ia64/sn/pci/bridge.h --- a/include/asm-ia64/sn/pci/bridge.h Tue Feb 25 10:47:18 2003 +++ b/include/asm-ia64/sn/pci/bridge.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_BRIDGE_H #define _ASM_SN_PCI_BRIDGE_H @@ -36,7 +36,6 @@ #include #include -#ifndef CONFIG_IA64_SGI_SN1 #include extern int io_get_sh_swapper(nasid_t); @@ -45,7 +44,6 @@ #define BRIDGE_REG_SET32(reg) \ *(volatile uint32_t *) (((uint64_t)reg)^4) -#endif /* CONFIG_IA64_SGI_SN1 */ /* I/O page size */ @@ -111,7 +109,6 @@ * Generated from Bridge spec dated 04oct95 */ -#ifndef CONFIG_IA64_SGI_SN1 /* * pic_widget_cfg_s is a local definition of widget_cfg_t but with @@ -605,292 +602,6 @@ } b_external_flash; } bridge_t; -#else /* CONFIG_IA64_SGI_SN1 */ - - -typedef volatile struct bridge_s { - - /* Local Registers 0x000000-0x00FFFF */ - - /* standard widget configuration 0x000000-0x000057 */ - widget_cfg_t b_widget; /* 0x000000 */ - - /* helper fieldnames for accessing bridge widget */ - -#define b_wid_id b_widget.w_id -#define b_wid_stat b_widget.w_status -#define b_wid_err_upper b_widget.w_err_upper_addr -#define b_wid_err_lower b_widget.w_err_lower_addr -#define b_wid_control b_widget.w_control -#define b_wid_req_timeout b_widget.w_req_timeout -#define b_wid_int_upper b_widget.w_intdest_upper_addr -#define b_wid_int_lower b_widget.w_intdest_lower_addr -#define b_wid_err_cmdword b_widget.w_err_cmd_word -#define b_wid_llp b_widget.w_llp_cfg -#define b_wid_tflush b_widget.w_tflush - - /* - * we access these through synergy unswizzled space, so the address - * gets twiddled (i.e. references to 0x4 actually go to 0x0 and vv.) - * That's why we put the register first and filler second. - */ - /* bridge-specific widget configuration 0x000058-0x00007F */ - bridgereg_t b_wid_aux_err; /* 0x00005C */ - bridgereg_t _pad_000058; - - bridgereg_t b_wid_resp_upper; /* 0x000064 */ - bridgereg_t _pad_000060; - - bridgereg_t b_wid_resp_lower; /* 0x00006C */ - bridgereg_t _pad_000068; - - bridgereg_t b_wid_tst_pin_ctrl; /* 0x000074 */ - bridgereg_t _pad_000070; - - bridgereg_t _pad_000078[2]; - - /* PMU & Map 0x000080-0x00008F */ - bridgereg_t b_dir_map; /* 0x000084 */ - bridgereg_t _pad_000080; - bridgereg_t _pad_000088[2]; - - /* SSRAM 0x000090-0x00009F */ - bridgereg_t b_ram_perr_or_map_fault;/* 0x000094 */ - bridgereg_t _pad_000090; -#define b_ram_perr b_ram_perr_or_map_fault /* Bridge */ -#define b_map_fault b_ram_perr_or_map_fault /* Xbridge */ - bridgereg_t _pad_000098[2]; - - /* Arbitration 0x0000A0-0x0000AF */ - bridgereg_t b_arb; /* 0x0000A4 */ - bridgereg_t _pad_0000A0; - bridgereg_t _pad_0000A8[2]; - - /* Number In A Can 0x0000B0-0x0000BF */ - bridgereg_t b_nic; /* 0x0000B4 */ - bridgereg_t _pad_0000B0; - bridgereg_t _pad_0000B8[2]; - - /* PCI/GIO 0x0000C0-0x0000FF */ - bridgereg_t b_bus_timeout; /* 0x0000C4 */ - bridgereg_t _pad_0000C0; -#define b_pci_bus_timeout b_bus_timeout - - bridgereg_t b_pci_cfg; /* 0x0000CC */ - bridgereg_t _pad_0000C8; - - bridgereg_t b_pci_err_upper; /* 0x0000D4 */ - bridgereg_t _pad_0000D0; - - bridgereg_t b_pci_err_lower; /* 0x0000DC */ - bridgereg_t _pad_0000D8; - bridgereg_t _pad_0000E0[8]; -#define b_gio_err_lower b_pci_err_lower -#define b_gio_err_upper b_pci_err_upper - - /* Interrupt 0x000100-0x0001FF */ - bridgereg_t b_int_status; /* 0x000104 */ - bridgereg_t _pad_000100; - - bridgereg_t b_int_enable; /* 0x00010C */ - bridgereg_t _pad_000108; - - bridgereg_t b_int_rst_stat; /* 0x000114 */ - bridgereg_t _pad_000110; - - bridgereg_t b_int_mode; /* 0x00011C */ - bridgereg_t _pad_000118; - - bridgereg_t b_int_device; /* 0x000124 */ - bridgereg_t _pad_000120; - - bridgereg_t b_int_host_err; /* 0x00012C */ - bridgereg_t _pad_000128; - - struct { - bridgereg_t addr; /* 0x0001{34,,,6C} */ - bridgereg_t __pad; /* 0x0001{30,,,68} */ - } b_int_addr[8]; /* 0x000130 */ - - bridgereg_t b_err_int_view; /* 0x000174 */ - bridgereg_t _pad_000170; - - bridgereg_t b_mult_int; /* 0x00017c */ - bridgereg_t _pad_000178; - - struct { - bridgereg_t intr; /* 0x0001{84,,,BC} */ - bridgereg_t __pad; /* 0x0001{80,,,B8} */ - } b_force_always[8]; /* 0x000180 */ - - struct { - bridgereg_t intr; /* 0x0001{C4,,,FC} */ - bridgereg_t __pad; /* 0x0001{C0,,,F8} */ - } b_force_pin[8]; /* 0x0001C0 */ - - /* Device 0x000200-0x0003FF */ - struct { - bridgereg_t reg; /* 0x0002{04,,,3C} */ - bridgereg_t __pad; /* 0x0002{00,,,38} */ - } b_device[8]; /* 0x000200 */ - - struct { - bridgereg_t reg; /* 0x0002{44,,,7C} */ - bridgereg_t __pad; /* 0x0002{40,,,78} */ - } b_wr_req_buf[8]; /* 0x000240 */ - - struct { - bridgereg_t reg; /* 0x0002{84,,,8C} */ - bridgereg_t __pad; /* 0x0002{80,,,88} */ - } b_rrb_map[2]; /* 0x000280 */ -#define b_even_resp b_rrb_map[0].reg /* 0x000284 */ -#define b_odd_resp b_rrb_map[1].reg /* 0x00028C */ - - bridgereg_t b_resp_status; /* 0x000294 */ - bridgereg_t _pad_000290; - - bridgereg_t b_resp_clear; /* 0x00029C */ - bridgereg_t _pad_000298; - - bridgereg_t _pad_0002A0[24]; - - /* Xbridge only */ - struct { - bridgereg_t upper; /* 0x0003{04,,,F4} */ - bridgereg_t __pad1; /* 0x0003{00,,,F0} */ - bridgereg_t lower; /* 0x0003{0C,,,FC} */ - bridgereg_t __pad2; /* 0x0003{08,,,F8} */ - } b_buf_addr_match[16]; - - /* Performance Monitor Registers (even only) */ - struct { - bridgereg_t flush_w_touch; /* 0x000404,,,5C4 */ - bridgereg_t __pad1; /* 0x000400,,,5C0 */ - - bridgereg_t flush_wo_touch; /* 0x00040C,,,5CC */ - bridgereg_t __pad2; /* 0x000408,,,5C8 */ - - bridgereg_t inflight; /* 0x000414,,,5D4 */ - bridgereg_t __pad3; /* 0x000410,,,5D0 */ - - bridgereg_t prefetch; /* 0x00041C,,,5DC */ - bridgereg_t __pad4; /* 0x000418,,,5D8 */ - - bridgereg_t total_pci_retry; /* 0x000424,,,5E4 */ - bridgereg_t __pad5; /* 0x000420,,,5E0 */ - - bridgereg_t max_pci_retry; /* 0x00042C,,,5EC */ - bridgereg_t __pad6; /* 0x000428,,,5E8 */ - - bridgereg_t max_latency; /* 0x000434,,,5F4 */ - bridgereg_t __pad7; /* 0x000430,,,5F0 */ - - bridgereg_t clear_all; /* 0x00043C,,,5FC */ - bridgereg_t __pad8; /* 0x000438,,,5F8 */ - } b_buf_count[8]; - - char _pad_000600[0x010000 - 0x000600]; - - /* - * The Xbridge has 1024 internal ATE's and the Bridge has 128. - * Make enough room for the Xbridge ATE's and depend on runtime - * checks to limit access to bridge ATE's. - */ - - /* Internal Address Translation Entry RAM 0x010000-0x011fff */ - union { - bridge_ate_t wr; /* write-only */ - struct { - bridgereg_t rd; /* read-only */ - bridgereg_t _p_pad; - } hi; - } b_int_ate_ram[XBRIDGE_INTERNAL_ATES]; - -#define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd - - /* the xbridge read path for internal ates starts at 0x12000. - * I don't believe we ever try to read the ates. - */ - /* Internal Address Translation Entry RAM LOW 0x012000-0x013fff */ - struct { - bridgereg_t rd; - bridgereg_t _p_pad; - } xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES]; - - char _pad_014000[0x20000 - 0x014000]; - - /* PCI Device Configuration Spaces 0x020000-0x027FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - union { - uchar_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } b_type0_cfg_dev[8]; /* 0x020000 */ - - /* PCI Type 1 Configuration Space 0x028000-0x028FFF */ - union { /* make all access sizes available. */ - uchar_t c[0x1000 / 1]; - uint16_t s[0x1000 / 2]; - uint32_t l[0x1000 / 4]; - uint64_t d[0x1000 / 8]; - union { - uchar_t c[0x100 / 1]; - uint16_t s[0x100 / 2]; - uint32_t l[0x100 / 4]; - uint64_t d[0x100 / 8]; - } f[8]; - } b_type1_cfg; /* 0x028000-0x029000 */ - - char _pad_029000[0x007000]; /* 0x029000-0x030000 */ - - /* PCI Interrupt Acknowledge Cycle 0x030000 */ - union { - uchar_t c[8 / 1]; - uint16_t s[8 / 2]; - uint32_t l[8 / 4]; - uint64_t d[8 / 8]; - } b_pci_iack; /* 0x030000 */ - - uchar_t _pad_030007[0x04fff8]; /* 0x030008-0x07FFFF */ - - /* External Address Translation Entry RAM 0x080000-0x0FFFFF */ - bridge_ate_t b_ext_ate_ram[0x10000]; - - /* Reserved 0x100000-0x1FFFFF */ - char _pad_100000[0x200000-0x100000]; - - /* PCI/GIO Device Spaces 0x200000-0xBFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x100000 / 1]; - uint16_t s[0x100000 / 2]; - uint32_t l[0x100000 / 4]; - uint64_t d[0x100000 / 8]; - } b_devio_raw[10]; /* 0x200000 */ - - /* b_devio macro is a bit strange; it reflects the - * fact that the Bridge ASIC provides 2M for the - * first two DevIO windows and 1M for the other six. - */ -#define b_devio(n) b_devio_raw[((n)<2)?(n*2):(n+2)] - - /* External Flash Proms 1,0 0xC00000-0xFFFFFF */ - union { /* make all access sizes available. */ - uchar_t c[0x400000 / 1]; /* read-only */ - uint16_t s[0x400000 / 2]; /* read-write */ - uint32_t l[0x400000 / 4]; /* read-only */ - uint64_t d[0x400000 / 8]; /* read-only */ - } b_external_flash; /* 0xC00000 */ -} bridge_t; - -#endif /* CONFIG_IA64_SGI_SN1 */ - - #define berr_field berr_un.berr_st #endif /* __ASSEMBLY__ */ @@ -1428,8 +1139,7 @@ #define BRIDGE_ISR_ERRORS \ (BRIDGE_ISR_LINK_ERROR|BRIDGE_ISR_PCIBUS_ERROR| \ BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR| \ - BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_PCIX_ARB_ERR| \ - PIC_ISR_INT_RAM_PERR) + BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_INT_RAM_PERR) /* * List of Errors which are fatal and kill the sytem @@ -1598,22 +1308,6 @@ #define BRIDGE_TMO_PCI_RETRY_CNT_MAX 0x3ff -#ifdef SN0 -/* - * The NASID should be shifted by this amount and stored into the - * interrupt(x) register. - */ -#define BRIDGE_INT_ADDR_NASID_SHFT 8 - -/* - * The BRIDGE_INT_ADDR_DEST_IO bit should be set to send an interrupt to - * memory. - */ -#define BRIDGE_INT_ADDR_DEST_IO (1 << 17) -#define BRIDGE_INT_ADDR_DEST_MEM 0 -#define BRIDGE_INT_ADDR_MASK (1 << 17) -#endif - /* Bridge device(x) register bits definition */ #define BRIDGE_DEV_ERR_LOCK_EN (1ull << 28) #define BRIDGE_DEV_PAGE_CHK_DIS (1ull << 27) @@ -1728,6 +1422,38 @@ #define BRIDGE_PCI_IO_LIMIT BRIDGE_PCIIO_XTALK_ALIAS_LIMIT /* + * Macros for Xtalk to Bridge bus (PCI) PIO + * refer to section 5.2.1 Figure 4 of the "PCI Interface Chip (PIC) Volume II + * Programmer's Reference" (Revision 0.8 as of this writing). + * + * These are PIC bridge specific. A separate set of macros was defined + * because PIC deviates from Bridge/Xbridge by not supporting a big-window + * alias for PCI I/O space, and also redefines XTALK addresses + * 0x0000C0000000L and 0x000100000000L to be PCI MEM aliases for the second + * bus. + */ + +/* XTALK addresses that map into PIC Bridge Bus addr space */ +#define PICBRIDGE0_PIO32_XTALK_ALIAS_BASE 0x000040000000L +#define PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT 0x00007FFFFFFFL +#define PICBRIDGE0_PIO64_XTALK_ALIAS_BASE 0x000080000000L +#define PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT 0x0000BFFFFFFFL +#define PICBRIDGE1_PIO32_XTALK_ALIAS_BASE 0x0000C0000000L +#define PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT 0x0000FFFFFFFFL +#define PICBRIDGE1_PIO64_XTALK_ALIAS_BASE 0x000100000000L +#define PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT 0x00013FFFFFFFL + +/* XTALK addresses that map into PCI addresses */ +#define PICBRIDGE0_PCI_MEM32_BASE PICBRIDGE0_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM32_LIMIT PICBRIDGE0_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE0_PCI_MEM64_BASE PICBRIDGE0_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE0_PCI_MEM64_LIMIT PICBRIDGE0_PIO64_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM32_BASE PICBRIDGE1_PIO32_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM32_LIMIT PICBRIDGE1_PIO32_XTALK_ALIAS_LIMIT +#define PICBRIDGE1_PCI_MEM64_BASE PICBRIDGE1_PIO64_XTALK_ALIAS_BASE +#define PICBRIDGE1_PCI_MEM64_LIMIT PICBRIDGE1_PIO64_XTALK_ALIAS_LIMIT + +/* * Macros for Bridge bus (PCI/GIO) to Xtalk DMA */ /* Bridge Bus DMA addresses */ @@ -1844,9 +1570,6 @@ #define ATE_SWAPSHIFT 29 #define ATE_SWAP_ON(x) ((x) |= (1 << ATE_SWAPSHIFT)) #define ATE_SWAP_OFF(x) ((x) &= ~(1 << ATE_SWAPSHIFT)) - -#define is_xbridge(bridge) IS_XBRIDGE(bridge->b_wid_id) -#define is_pic(bridge) IS_PIC_BRIDGE(bridge->b_wid_id) /* extern declarations */ diff -Nru a/include/asm-ia64/sn/pci/pci_bus_cvlink.h b/include/asm-ia64/sn/pci/pci_bus_cvlink.h --- a/include/asm-ia64/sn/pci/pci_bus_cvlink.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/pci/pci_bus_cvlink.h Fri May 16 04:18:18 2003 @@ -4,13 +4,12 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_CVLINK_H #define _ASM_SN_PCI_CVLINK_H #include -#include #include #include #include @@ -50,11 +49,11 @@ (((struct sn_widget_sysdata *)((pci_bus)->sysdata))->vhdl) struct sn_widget_sysdata { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; }; struct sn_device_sysdata { - devfs_handle_t vhdl; + vertex_hdl_t vhdl; int isa64; int isPIC; volatile unsigned int *dma_buf_sync; diff -Nru a/include/asm-ia64/sn/pci/pci_defs.h b/include/asm-ia64/sn/pci/pci_defs.h --- a/include/asm-ia64/sn/pci/pci_defs.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/pci/pci_defs.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCI_DEFS_H #define _ASM_SN_PCI_PCI_DEFS_H @@ -321,6 +321,112 @@ #ifndef __ASSEMBLY__ +#ifdef LITTLE_ENDIAN + +/* + * PCI config space definition + */ +typedef volatile struct pci_cfg_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[6]; + uint32_t cardbus; + uint16_t subsys_vendor_id; + uint16_t subsys_dev_id; + uint32_t exp_rom; + uint32_t res[2]; + uchar_t int_line; + uchar_t int_pin; + uchar_t min_gnt; + uchar_t max_lat; +} pci_cfg_t; + +/* + * PCI Type 1 config space definition for PCI to PCI Bridges (PPBs) + */ +typedef volatile struct pci_cfg1_s { + uint16_t vendor_id; + uint16_t dev_id; + uint16_t cmd; + uint16_t status; + uchar_t rev; + uchar_t prog_if; + uchar_t sub_class; + uchar_t class; + uchar_t line_size; + uchar_t lt; + uchar_t hdr_type; + uchar_t bist; + uint32_t bar[2]; + uchar_t pri_bus_num; + uchar_t snd_bus_num; + uchar_t sub_bus_num; + uchar_t slt; + uchar_t io_base; + uchar_t io_limit; + uint16_t snd_status; + uint16_t mem_base; + uint16_t mem_limit; + uint16_t pmem_base; + uint16_t pmem_limit; + uint32_t pmem_base_upper; + uint32_t pmem_limit_upper; + uint16_t io_base_upper; + uint16_t io_limit_upper; + uint32_t res; + uint32_t exp_rom; + uchar_t int_line; + uchar_t int_pin; + uint16_t ppb_control; + +} pci_cfg1_t; + +/* + * PCI-X Capability + */ +typedef volatile struct cap_pcix_cmd_reg_s { + uint16_t data_parity_enable: 1, + enable_relaxed_order: 1, + max_mem_read_cnt: 2, + max_split: 3, + reserved1: 9; +} cap_pcix_cmd_reg_t; + +typedef volatile struct cap_pcix_stat_reg_s { + uint32_t func_num: 3, + dev_num: 5, + bus_num: 8, + bit64_device: 1, + mhz133_capable: 1, + split_complt_discard: 1, + unexpect_split_complt: 1, + device_complex: 1, + max_mem_read_cnt: 2, + max_out_split: 3, + max_cum_read: 3, + split_complt_err: 1, + reserved1: 2; +} cap_pcix_stat_reg_t; + +typedef volatile struct cap_pcix_type0_s { + uchar_t pcix_cap_id; + uchar_t pcix_cap_nxt; + cap_pcix_cmd_reg_t pcix_type0_command; + cap_pcix_stat_reg_t pcix_type0_status; +} cap_pcix_type0_t; + +#else + /* * PCI config space definition */ @@ -388,6 +494,8 @@ uchar_t int_line; } pci_cfg1_t; + + /* * PCI-X Capability */ @@ -422,5 +530,6 @@ cap_pcix_stat_reg_t pcix_type0_status; } cap_pcix_type0_t; +#endif #endif /* __ASSEMBLY__ */ #endif /* _ASM_SN_PCI_PCI_DEFS_H */ diff -Nru a/include/asm-ia64/sn/pci/pciba.h b/include/asm-ia64/sn/pci/pciba.h --- a/include/asm-ia64/sn/pci/pciba.h Tue Dec 3 10:07:33 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,121 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file "COPYING" in the main directory of - * this archive for more details. - * - * Copyright (C) 1997, 2001 Silicon Graphics, Inc. All rights reserved. - * - */ - -#ifndef _ASM_SN_PCI_PCIBA_H -#define _ASM_SN_PCI_PCIBA_H - -#include -#include -#include - -/* for application compatibility with IRIX (why do I bother?) */ - -#ifndef __KERNEL__ -typedef u_int8_t uint8_t; -typedef u_int16_t uint16_t; -typedef u_int32_t uint32_t; -#endif - -#define PCI_CFG_VENDOR_ID PCI_VENDOR_ID -#define PCI_CFG_COMMAND PCI_COMMAND -#define PCI_CFG_REV_ID PCI_REVISION_ID -#define PCI_CFG_HEADER_TYPE PCI_HEADER_TYPE -#define PCI_CFG_BASE_ADDR(n) PCI_BASE_ADDRESS_##n - - -/* /hw/.../pci/[slot]/config accepts ioctls to read - * and write specific registers as follows: - * - * "t" is the native type (char, short, uint32, uint64) - * to read from CFG space; results will be arranged in - * byte significance (ie. first byte from PCI is lowest - * or last byte in result). - * - * "r" is the byte offset in PCI CFG space of the first - * byte of the register (it's least significant byte, - * in the little-endian PCI numbering). This can actually - * be as much as 16 bits wide, and is intended to match - * the layout of a "Type 1 Configuration Space" address: - * the register number in the low eight bits, then three - * bits for the function number and five bits for the - * slot number. - */ -#define PCIIOCCFGRD(t,r) _IOR(0,(r),t) -#define PCIIOCCFGWR(t,r) _IOW(0,(r),t) - -/* Some common config register access commands. - * Use these as examples of how to construct - * values for other registers you want to access. - */ - -/* PCIIOCGETID: arg is ptr to 32-bit int, - * returns the 32-bit ID value with VENDOR - * in the bottom 16 bits and DEVICE in the top. - */ -#define PCIIOCGETID PCIIOCCFGRD(uint32_t,PCI_CFG_VENDOR_ID) - -/* PCIIOCSETCMD: arg is ptr to a 16-bit short, - * which will be written to the CMD register. - */ -#define PCIIOCSETCMD PCIIOCCFGWR(uint16_t,PCI_CFG_COMMAND) - -/* PCIIOCGETREV: arg is ptr to an 8-bit char, - * which will get the 8-bit revision number. - */ -#define PCIIOCGETREV PCIIOCCFGRD(uint8_t,PCI_CFG_REV_ID) - -/* PCIIOCGETHTYPE: arg is ptr to an 8-bit char, - * which will get the 8-bit header type. - */ -#define PCIIOCGETHTYPE PCIIOCCFGRD(uint8_t,PCI_CFG_HEADER_TYPE) - -/* PCIIOCGETBASE(n): arg is ptr to a 32-bit int, - * which will get the value of the BASE register. - */ - -/* FIXME chadt: this doesn't tell me whether or not this will work - with non-constant 'n.' */ -#define PCIIOCGETBASE(n) PCIIOCCFGRD(uint32_t,PCI_CFG_BASE_ADDR(n)) - - -/* /hw/.../pci/[slot]/dma accepts ioctls to allocate - * and free physical memory for use in user-triggered - * DMA operations. - */ -#define PCIIOCDMAALLOC _IOWR(0,1,uint64_t) -#define PCIIOCDMAFREE _IOW(0,1,uint64_t) - -/* pio cache-mode ioctl defines. current only uncached accelerated */ -#define PCIBA_CACHE_MODE_SET 1 -#define PCIBA_CACHE_MODE_CLEAR 2 -#ifdef PIOMAP_UNC_ACC -#define PCIBA_UNCACHED_ACCEL PIOMAP_UNC_ACC -#endif - -/* The parameter for PCIIOCDMAALLOC needs to contain - * both the size of the request and the flag values - * to be used in setting up the DMA. - * - -FIXME chadt: gonna have to revisit this: what flags would an IRIXer like to - have available? - - * Any flags normally useful in pciio_dmamap - * or pciio_dmatrans function calls can6 be used here. */ -#define PCIIOCDMAALLOC_REQUEST_PACK(flags,size) \ - ((((uint64_t)(flags))<<32)| \ - (((uint64_t)(size))&0xFFFFFFFF)) - - -#ifdef __KERNEL__ -extern int pciba_init(void); -#endif - - -#endif /* _ASM_SN_PCI_PCIBA_H */ diff -Nru a/include/asm-ia64/sn/pci/pcibr.h b/include/asm-ia64/sn/pci/pcibr.h --- a/include/asm-ia64/sn/pci/pcibr.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/pci/pcibr.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_H #define _ASM_SN_PCI_PCIBR_H @@ -59,9 +59,7 @@ * code and part number registered by pcibr_init(). */ -extern void pcibr_init(void); - -extern int pcibr_attach(devfs_handle_t); +extern int pcibr_attach(vertex_hdl_t); /* ===================================================================== * bus provider function table @@ -94,7 +92,7 @@ * smarts on the part of the compilation system). */ -extern pcibr_piomap_t pcibr_piomap_alloc(devfs_handle_t dev, +extern pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, @@ -110,24 +108,24 @@ extern void pcibr_piomap_done(pcibr_piomap_t piomap); -extern caddr_t pcibr_piotrans_addr(devfs_handle_t dev, +extern caddr_t pcibr_piotrans_addr(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, iopaddr_t pci_addr, size_t byte_count, unsigned flags); -extern iopaddr_t pcibr_piospace_alloc(devfs_handle_t dev, +extern iopaddr_t pcibr_piospace_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_space_t space, size_t byte_count, size_t alignment); -extern void pcibr_piospace_free(devfs_handle_t dev, +extern void pcibr_piospace_free(vertex_hdl_t dev, pciio_space_t space, iopaddr_t pciaddr, size_t byte_count); -extern pcibr_dmamap_t pcibr_dmamap_alloc(devfs_handle_t dev, +extern pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t dev, device_desc_t dev_desc, size_t byte_count_max, unsigned flags); @@ -150,109 +148,97 @@ * (This node id can be different for each PCI bus.) */ -extern cnodeid_t pcibr_get_dmatrans_node(devfs_handle_t pconn_vhdl); +extern cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t pconn_vhdl); -extern iopaddr_t pcibr_dmatrans_addr(devfs_handle_t dev, +extern iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t dev, device_desc_t dev_desc, paddr_t paddr, size_t byte_count, unsigned flags); -extern alenlist_t pcibr_dmatrans_list(devfs_handle_t dev, +extern alenlist_t pcibr_dmatrans_list(vertex_hdl_t dev, device_desc_t dev_desc, alenlist_t palenlist, unsigned flags); extern void pcibr_dmamap_drain(pcibr_dmamap_t map); -extern void pcibr_dmaaddr_drain(devfs_handle_t vhdl, +extern void pcibr_dmaaddr_drain(vertex_hdl_t vhdl, paddr_t addr, size_t bytes); -extern void pcibr_dmalist_drain(devfs_handle_t vhdl, +extern void pcibr_dmalist_drain(vertex_hdl_t vhdl, alenlist_t list); typedef unsigned pcibr_intr_ibit_f(pciio_info_t info, pciio_intr_line_t lines); -extern void pcibr_intr_ibit_set(devfs_handle_t, pcibr_intr_ibit_f *); +extern void pcibr_intr_ibit_set(vertex_hdl_t, pcibr_intr_ibit_f *); -extern pcibr_intr_t pcibr_intr_alloc(devfs_handle_t dev, +extern pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t dev, device_desc_t dev_desc, pciio_intr_line_t lines, - devfs_handle_t owner_dev); + vertex_hdl_t owner_dev); extern void pcibr_intr_free(pcibr_intr_t intr); -#ifdef CONFIG_IA64_SGI_SN1 -extern int pcibr_intr_connect(pcibr_intr_t intr); -#else extern int pcibr_intr_connect(pcibr_intr_t intr, intr_func_t, intr_arg_t); -#endif extern void pcibr_intr_disconnect(pcibr_intr_t intr); -extern devfs_handle_t pcibr_intr_cpu_get(pcibr_intr_t intr); +extern vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t intr); -extern void pcibr_provider_startup(devfs_handle_t pcibr); +extern void pcibr_provider_startup(vertex_hdl_t pcibr); -extern void pcibr_provider_shutdown(devfs_handle_t pcibr); +extern void pcibr_provider_shutdown(vertex_hdl_t pcibr); -extern int pcibr_reset(devfs_handle_t dev); +extern int pcibr_reset(vertex_hdl_t dev); -extern int pcibr_write_gather_flush(devfs_handle_t dev); +extern int pcibr_write_gather_flush(vertex_hdl_t dev); -extern pciio_endian_t pcibr_endian_set(devfs_handle_t dev, +extern pciio_endian_t pcibr_endian_set(vertex_hdl_t dev, pciio_endian_t device_end, pciio_endian_t desired_end); -extern pciio_priority_t pcibr_priority_set(devfs_handle_t dev, +extern pciio_priority_t pcibr_priority_set(vertex_hdl_t dev, pciio_priority_t device_prio); -extern uint64_t pcibr_config_get(devfs_handle_t conn, +extern uint64_t pcibr_config_get(vertex_hdl_t conn, unsigned reg, unsigned size); -extern void pcibr_config_set(devfs_handle_t conn, +extern void pcibr_config_set(vertex_hdl_t conn, unsigned reg, unsigned size, uint64_t value); -extern int pcibr_error_devenable(devfs_handle_t pconn_vhdl, +extern int pcibr_error_devenable(vertex_hdl_t pconn_vhdl, int error_code); -#ifdef PIC_LATER -extern pciio_slot_t pcibr_error_extract(devfs_handle_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *addrp); -#endif - -extern int pcibr_wrb_flush(devfs_handle_t pconn_vhdl); -extern int pcibr_rrb_check(devfs_handle_t pconn_vhdl, +extern int pcibr_wrb_flush(vertex_hdl_t pconn_vhdl); +extern int pcibr_rrb_check(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1, int *count_reserved, int *count_pool); -#ifndef CONFIG_IA64_SGI_SN1 -extern int pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, +extern int pcibr_alloc_all_rrbs(vertex_hdl_t vhdl, int even_odd, int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4); -#endif typedef void -rrb_alloc_funct_f (devfs_handle_t xconn_vhdl, +rrb_alloc_funct_f (vertex_hdl_t xconn_vhdl, int *vendor_list); typedef rrb_alloc_funct_f *rrb_alloc_funct_t; -void pcibr_set_rrb_callback(devfs_handle_t xconn_vhdl, +void pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_f *func); -extern int pcibr_device_unregister(devfs_handle_t); -extern int pcibr_dma_enabled(devfs_handle_t); +extern int pcibr_device_unregister(vertex_hdl_t); +extern int pcibr_dma_enabled(vertex_hdl_t); /* * Bridge-specific flags that can be set via pcibr_device_flags_set * and cleared via pcibr_device_flags_clear. Other flags are @@ -320,7 +306,7 @@ * "flags" are defined above. NOTE: this includes turning * things *OFF* as well as turning them *ON* ... */ -extern int pcibr_device_flags_set(devfs_handle_t dev, +extern int pcibr_device_flags_set(vertex_hdl_t dev, pcibr_device_flags_t flags); /* @@ -331,7 +317,7 @@ * <0 on failure, which occurs when we're unable to allocate any * buffers to a channel that desires at least one buffer. */ -extern int pcibr_rrb_alloc(devfs_handle_t pconn_vhdl, +extern int pcibr_rrb_alloc(vertex_hdl_t pconn_vhdl, int *count_vchan0, int *count_vchan1); @@ -345,19 +331,15 @@ extern xwidget_intr_preset_f pcibr_xintr_preset; -extern void pcibr_hints_fix_rrbs(devfs_handle_t); -extern void pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t); -extern void pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong); -extern void pcibr_hints_handsoff(devfs_handle_t); - -#ifdef CONFIG_IA64_SGI_SN1 -typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t); -#else +extern void pcibr_hints_fix_rrbs(vertex_hdl_t); +extern void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); +extern void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, ulong); +extern void pcibr_hints_handsoff(vertex_hdl_t); + typedef unsigned pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t, int); -#endif -extern void pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *); +extern void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); -extern int pcibr_asic_rev(devfs_handle_t); +extern int pcibr_asic_rev(vertex_hdl_t); #endif /* __ASSEMBLY__ */ #endif /* #if defined(__KERNEL__) */ @@ -433,7 +415,7 @@ short resp_bs_bridge_mode; int resp_has_host; char resp_host_slot; - devfs_handle_t resp_slot_conn; + vertex_hdl_t resp_slot_conn; char resp_slot_conn_name[MAXDEVNAME]; int resp_slot_status; int resp_l1_bus_num; @@ -460,10 +442,8 @@ bridgereg_t resp_b_int_device; bridgereg_t resp_b_int_enable; bridgereg_t resp_b_int_host; -#ifndef CONFIG_IA64_SGI_SN1 picreg_t resp_p_int_enable; picreg_t resp_p_int_host; -#endif struct pcibr_slot_func_info_resp_s { int resp_f_status; char resp_f_slot_name[MAXDEVNAME]; diff -Nru a/include/asm-ia64/sn/pci/pcibr_private.h b/include/asm-ia64/sn/pci/pcibr_private.h --- a/include/asm-ia64/sn/pci/pcibr_private.h Mon Feb 24 10:18:26 2003 +++ b/include/asm-ia64/sn/pci/pcibr_private.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIBR_PRIVATE_H #define _ASM_SN_PCI_PCIBR_PRIVATE_H @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -45,7 +46,7 @@ cfg_p pcibr_func_config_addr(bridge_t *, pciio_bus_t bus, pciio_slot_t, pciio_function_t, int); unsigned pcibr_slot_config_get(bridge_t *, pciio_slot_t, int); unsigned pcibr_func_config_get(bridge_t *, pciio_slot_t, pciio_function_t, int); -void pcibr_debug(uint32_t, devfs_handle_t, char *, ...); +void pcibr_debug(uint32_t, vertex_hdl_t, char *, ...); void pcibr_slot_config_set(bridge_t *, pciio_slot_t, int, unsigned); void pcibr_func_config_set(bridge_t *, pciio_slot_t, pciio_function_t, int, unsigned); @@ -171,6 +172,7 @@ unsigned bi_ibits; /* which Bridge interrupt bit(s) */ pcibr_soft_t bi_soft; /* shortcut to soft info */ struct pcibr_intr_cbuf_s bi_ibuf; /* circular buffer of wrap ptrs */ + unsigned bi_last_intr; /* For Shub lb lost intr. bug */ }; @@ -254,11 +256,7 @@ struct pcibr_intr_wrap_s { pcibr_soft_t iw_soft; /* which bridge */ volatile bridgereg_t *iw_stat; /* ptr to b_int_status */ -#ifdef CONFIG_IA64_SGI_SN1 - bridgereg_t iw_intr; /* bit in b_int_status */ -#else bridgereg_t iw_ibit; /* bit in b_int_status */ -#endif pcibr_intr_list_t iw_list; /* ghostbusters! */ int iw_hdlrcnt; /* running handler count */ int iw_shared; /* if Bridge bit is shared */ @@ -293,6 +291,8 @@ #define PCIBR_BRIDGETYPE_PIC 2 #define IS_XBRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_XBRIDGE) #define IS_PIC_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_PIC) +#define IS_PIC_BUSNUM_SOFT(ps, bus) \ + (IS_PIC_SOFT(ps) && ((ps)->bs_busnum == (bus))) #define IS_BRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_BRIDGE) #define IS_XBRIDGE_OR_PIC_SOFT(ps) (IS_XBRIDGE_SOFT(ps) || IS_PIC_SOFT(ps)) @@ -348,13 +348,13 @@ */ struct pcibr_soft_s { - devfs_handle_t bs_conn; /* xtalk connection point */ - devfs_handle_t bs_vhdl; /* vertex owned by pcibr */ + vertex_hdl_t bs_conn; /* xtalk connection point */ + vertex_hdl_t bs_vhdl; /* vertex owned by pcibr */ uint64_t bs_int_enable; /* Mask of enabled intrs */ bridge_t *bs_base; /* PIO pointer to Bridge chip */ char *bs_name; /* hw graph name */ xwidgetnum_t bs_xid; /* Bridge's xtalk ID number */ - devfs_handle_t bs_master; /* xtalk master vertex */ + vertex_hdl_t bs_master; /* xtalk master vertex */ xwidgetnum_t bs_mxid; /* master's xtalk ID number */ pciio_slot_t bs_first_slot; /* first existing slot */ pciio_slot_t bs_last_slot; /* last existing slot */ @@ -372,9 +372,6 @@ short bs_int_ate_size; /* number of internal ates */ short bs_bridge_type; /* see defines above */ short bs_bridge_mode; /* see defines above */ -#ifdef CONFIG_IA64_SGI_SN1 -#define bs_xbridge bs_bridge_type -#endif int bs_rev_num; /* revision number of Bridge */ /* bs_dma_flags are the forced dma flags used on all DMAs. Used for @@ -382,9 +379,6 @@ */ unsigned bs_dma_flags; /* forced DMA flags */ -#ifdef CONFIG_IA64_SGI_SN1 - l1sc_t *bs_l1sc; /* io brick l1 system cntr */ -#endif moduleid_t bs_moduleid; /* io brick moduleid */ short bs_bricktype; /* io brick type */ @@ -394,7 +388,7 @@ */ spinlock_t bs_lock; - devfs_handle_t bs_noslot_conn; /* NO-SLOT connection point */ + vertex_hdl_t bs_noslot_conn; /* NO-SLOT connection point */ pcibr_info_t bs_noslot_info; struct pcibr_soft_slot_s { /* information we keep about each CFG slot */ @@ -411,7 +405,7 @@ */ int has_host; pciio_slot_t host_slot; - devfs_handle_t slot_conn; + vertex_hdl_t slot_conn; /* PCI Hot-Plug status word */ int slot_status; @@ -531,13 +525,8 @@ int bs_rrb_avail[2]; int bs_rrb_res[8]; int bs_rrb_res_dflt[8]; -#ifdef CONFIG_IA64_SGI_SN1 - int bs_rrb_valid[16]; - int bs_rrb_valid_dflt[16]; -#else int bs_rrb_valid[8][4]; int bs_rrb_valid_dflt[8][4]; -#endif struct { /* Each Bridge interrupt bit has a single XIO * interrupt channel allocated. @@ -578,7 +567,7 @@ #ifdef LATER toid_t bserr_toutid; /* Timeout started by errintr */ #endif /* LATER */ - iopaddr_t bserr_addr; /* Address where error occurred */ + iopaddr_t bserr_addr; /* Address where error occured */ uint64_t bserr_intstat; /* interrupts active at error dump */ } bs_errinfo; @@ -599,16 +588,6 @@ * in Megabytes), and they generally tend to take once and never * release. */ -#ifdef CONFIG_IA64_SGI_SN1 - struct br_pcisp_info { - iopaddr_t pci_io_base; - iopaddr_t pci_io_last; - iopaddr_t pci_swin_base; - iopaddr_t pci_swin_last; - iopaddr_t pci_mem_base; - iopaddr_t pci_mem_last; - } bs_spinfo; -#endif /* CONFIG_IA64_SGI_SN1 */ struct pciio_win_map_s bs_io_win_map; /* I/O addr space */ struct pciio_win_map_s bs_swin_map; /* Small window addr space */ struct pciio_win_map_s bs_mem_win_map; /* Memory addr space */ @@ -655,8 +634,6 @@ pcibr_intr_bits_f *ph_intr_bits; /* map PCI INT[ABCD] to Bridge Int(n) */ }; -extern int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev; - /* * Number of bridge non-fatal error interrupts we can see before * we decide to disable that interrupt. @@ -689,7 +666,6 @@ #define NEW(ptr) NEWA(ptr,1) #define DEL(ptr) DELA(ptr,1) -#ifndef CONFIG_IA64_SGI_SN1 /* * Additional PIO spaces per slot are * recorded in this structure. @@ -701,7 +677,6 @@ iopaddr_t start; /* Starting address of the PIO space */ size_t count; /* size of PIO space */ }; -#endif /* CONFIG_IA64_SGI_SN1 */ /* Use io spin locks. This ensures that all the PIO writes from a particular * CPU to a particular IO device are synched before the start of the next @@ -715,11 +690,9 @@ #define pcibr_unlock(pcibr_soft, s) #endif /* PCI_LATER */ -#ifndef CONFIG_IA64_SGI_SN1 #define PCIBR_VALID_SLOT(ps, s) (s < PCIBR_NUM_SLOTS(ps)) #define PCIBR_D64_BASE_UNSET (0xFFFFFFFFFFFFFFFF) #define PCIBR_D32_BASE_UNSET (0xFFFFFFFF) -#endif #define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev" #define PCIBR_SOFT_LIST 1 @@ -728,8 +701,35 @@ struct pcibr_list_s { pcibr_list_p bl_next; pcibr_soft_t bl_soft; - devfs_handle_t bl_vhdl; + vertex_hdl_t bl_vhdl; }; #endif /* PCIBR_SOFT_LIST */ + + +// Devices per widget: 2 buses, 2 slots per bus, 8 functions per slot. +#define DEV_PER_WIDGET (2*2*8) + +struct sn_flush_device_list { + int bus; + int pin; + struct bar_list { + unsigned long start; + unsigned long end; + } bar_list[PCI_ROM_RESOURCE]; + unsigned long force_int_addr; + volatile unsigned long flush_addr; + spinlock_t flush_lock; +}; + +struct sn_flush_nasid_entry { + struct sn_flush_device_list **widget_p; + unsigned long iio_itte1; + unsigned long iio_itte2; + unsigned long iio_itte3; + unsigned long iio_itte4; + unsigned long iio_itte5; + unsigned long iio_itte6; + unsigned long iio_itte7; +}; #endif /* _ASM_SN_PCI_PCIBR_PRIVATE_H */ diff -Nru a/include/asm-ia64/sn/pci/pciio.h b/include/asm-ia64/sn/pci/pciio.h --- a/include/asm-ia64/sn/pci/pciio.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/pci/pciio.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_H #define _ASM_SN_PCI_PCIIO_H @@ -277,7 +277,7 @@ #define PCIIO_PIOMAP_WIN(n) (0x8+(n)) typedef pciio_piomap_t -pciio_piomap_alloc_f (devfs_handle_t dev, /* set up mapping for this device */ +pciio_piomap_alloc_f (vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pcipio_addr, /* starting address */ @@ -297,7 +297,7 @@ pciio_piomap_done_f (pciio_piomap_t pciio_piomap); typedef caddr_t -pciio_piotrans_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_piotrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pciio_addr, /* starting address */ @@ -305,7 +305,7 @@ unsigned flags); typedef caddr_t -pciio_pio_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_pio_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ pciio_space_t space, /* which address space */ iopaddr_t pciio_addr, /* starting address */ @@ -314,14 +314,14 @@ unsigned flags); typedef iopaddr_t -pciio_piospace_alloc_f (devfs_handle_t dev, /* PIO space for this device */ +pciio_piospace_alloc_f (vertex_hdl_t dev, /* PIO space for this device */ device_desc_t dev_desc, /* Device descriptor */ pciio_space_t space, /* which address space */ size_t byte_count, /* Number of bytes of space */ size_t alignment); /* Alignment of allocation */ typedef void -pciio_piospace_free_f (devfs_handle_t dev, /* Device freeing space */ +pciio_piospace_free_f (vertex_hdl_t dev, /* Device freeing space */ pciio_space_t space, /* Which space is freed */ iopaddr_t pci_addr, /* Address being freed */ size_t size); /* Size freed */ @@ -329,7 +329,7 @@ /* DMA MANAGEMENT */ typedef pciio_dmamap_t -pciio_dmamap_alloc_f (devfs_handle_t dev, /* set up mappings for this device */ +pciio_dmamap_alloc_f (vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -342,123 +342,107 @@ paddr_t paddr, /* map for this address */ size_t byte_count); /* map this many bytes */ -typedef alenlist_t -pciio_dmamap_list_f (pciio_dmamap_t dmamap, /* use these mapping resources */ - alenlist_t alenlist, /* map this address/length list */ - unsigned flags); - typedef void pciio_dmamap_done_f (pciio_dmamap_t dmamap); typedef iopaddr_t -pciio_dmatrans_addr_f (devfs_handle_t dev, /* translate for this device */ +pciio_dmatrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); /* defined in dma.h */ -typedef alenlist_t -pciio_dmatrans_list_f (devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system address/length list */ - unsigned flags); /* defined in dma.h */ - typedef void pciio_dmamap_drain_f (pciio_dmamap_t map); typedef void -pciio_dmaaddr_drain_f (devfs_handle_t vhdl, +pciio_dmaaddr_drain_f (vertex_hdl_t vhdl, paddr_t addr, size_t bytes); typedef void -pciio_dmalist_drain_f (devfs_handle_t vhdl, +pciio_dmalist_drain_f (vertex_hdl_t vhdl, alenlist_t list); /* INTERRUPT MANAGEMENT */ typedef pciio_intr_t -pciio_intr_alloc_f (devfs_handle_t dev, /* which PCI device */ +pciio_intr_alloc_f (vertex_hdl_t dev, /* which PCI device */ device_desc_t dev_desc, /* device descriptor */ pciio_intr_line_t lines, /* which line(s) will be used */ - devfs_handle_t owner_dev); /* owner of this intr */ + vertex_hdl_t owner_dev); /* owner of this intr */ typedef void pciio_intr_free_f (pciio_intr_t intr_hdl); -#ifdef CONFIG_IA64_SGI_SN1 -typedef int -pciio_intr_connect_f (pciio_intr_t intr_hdl); /* pciio intr resource handle */ -#else typedef int pciio_intr_connect_f (pciio_intr_t intr_hdl, intr_func_t intr_func, intr_arg_t intr_arg); /* pciio intr resource handle */ -#endif typedef void pciio_intr_disconnect_f (pciio_intr_t intr_hdl); -typedef devfs_handle_t +typedef vertex_hdl_t pciio_intr_cpu_get_f (pciio_intr_t intr_hdl); /* pciio intr resource handle */ /* CONFIGURATION MANAGEMENT */ typedef void -pciio_provider_startup_f (devfs_handle_t pciio_provider); +pciio_provider_startup_f (vertex_hdl_t pciio_provider); typedef void -pciio_provider_shutdown_f (devfs_handle_t pciio_provider); +pciio_provider_shutdown_f (vertex_hdl_t pciio_provider); typedef int -pciio_reset_f (devfs_handle_t conn); /* pci connection point */ +pciio_reset_f (vertex_hdl_t conn); /* pci connection point */ typedef int -pciio_write_gather_flush_f (devfs_handle_t dev); /* Device flushing buffers */ +pciio_write_gather_flush_f (vertex_hdl_t dev); /* Device flushing buffers */ typedef pciio_endian_t /* actual endianness */ -pciio_endian_set_f (devfs_handle_t dev, /* specify endianness for this device */ +pciio_endian_set_f (vertex_hdl_t dev, /* specify endianness for this device */ pciio_endian_t device_end, /* endianness of device */ pciio_endian_t desired_end); /* desired endianness */ typedef pciio_priority_t -pciio_priority_set_f (devfs_handle_t pcicard, +pciio_priority_set_f (vertex_hdl_t pcicard, pciio_priority_t device_prio); typedef uint64_t -pciio_config_get_f (devfs_handle_t conn, /* pci connection point */ +pciio_config_get_f (vertex_hdl_t conn, /* pci connection point */ unsigned reg, /* register byte offset */ unsigned size); /* width in bytes (1..4) */ typedef void -pciio_config_set_f (devfs_handle_t conn, /* pci connection point */ +pciio_config_set_f (vertex_hdl_t conn, /* pci connection point */ unsigned reg, /* register byte offset */ unsigned size, /* width in bytes (1..4) */ uint64_t value); /* value to store */ typedef int -pciio_error_devenable_f (devfs_handle_t pconn_vhdl, int error_code); +pciio_error_devenable_f (vertex_hdl_t pconn_vhdl, int error_code); typedef pciio_slot_t -pciio_error_extract_f (devfs_handle_t vhdl, +pciio_error_extract_f (vertex_hdl_t vhdl, pciio_space_t *spacep, iopaddr_t *addrp); typedef void -pciio_driver_reg_callback_f (devfs_handle_t conn, +pciio_driver_reg_callback_f (vertex_hdl_t conn, int key1, int key2, int error); typedef void -pciio_driver_unreg_callback_f (devfs_handle_t conn, /* pci connection point */ +pciio_driver_unreg_callback_f (vertex_hdl_t conn, /* pci connection point */ int key1, int key2, int error); typedef int -pciio_device_unregister_f (devfs_handle_t conn); +pciio_device_unregister_f (vertex_hdl_t conn); typedef int -pciio_dma_enabled_f (devfs_handle_t conn); +pciio_dma_enabled_f (vertex_hdl_t conn); /* * Adapters that provide a PCI interface adhere to this software interface. @@ -477,10 +461,8 @@ pciio_dmamap_alloc_f *dmamap_alloc; pciio_dmamap_free_f *dmamap_free; pciio_dmamap_addr_f *dmamap_addr; - pciio_dmamap_list_f *dmamap_list; pciio_dmamap_done_f *dmamap_done; pciio_dmatrans_addr_f *dmatrans_addr; - pciio_dmatrans_list_f *dmatrans_list; pciio_dmamap_drain_f *dmamap_drain; pciio_dmaaddr_drain_f *dmaaddr_drain; pciio_dmalist_drain_f *dmalist_drain; @@ -525,10 +507,8 @@ extern pciio_dmamap_alloc_f pciio_dmamap_alloc; extern pciio_dmamap_free_f pciio_dmamap_free; extern pciio_dmamap_addr_f pciio_dmamap_addr; -extern pciio_dmamap_list_f pciio_dmamap_list; extern pciio_dmamap_done_f pciio_dmamap_done; extern pciio_dmatrans_addr_f pciio_dmatrans_addr; -extern pciio_dmatrans_list_f pciio_dmatrans_list; extern pciio_dmamap_drain_f pciio_dmamap_drain; extern pciio_dmaaddr_drain_f pciio_dmaaddr_drain; extern pciio_dmalist_drain_f pciio_dmalist_drain; @@ -580,34 +560,31 @@ unsigned flags); extern void -pciio_error_register (devfs_handle_t pconn, /* which slot */ +pciio_error_register (vertex_hdl_t pconn, /* which slot */ error_handler_f *efunc, /* function to call */ error_handler_arg_t einfo); /* first parameter */ extern void pciio_driver_unregister(char *driver_prefix); -typedef void pciio_iter_f(devfs_handle_t pconn); /* a connect point */ - -extern void pciio_iterate(char *driver_prefix, - pciio_iter_f *func); +typedef void pciio_iter_f(vertex_hdl_t pconn); /* a connect point */ /* Interfaces used by PCI Bus Providers to talk to * the Generic PCI layer. */ -extern devfs_handle_t -pciio_device_register (devfs_handle_t connectpt, /* vertex at center of bus */ - devfs_handle_t master, /* card's master ASIC (pci provider) */ +extern vertex_hdl_t +pciio_device_register (vertex_hdl_t connectpt, /* vertex at center of bus */ + vertex_hdl_t master, /* card's master ASIC (pci provider) */ pciio_slot_t slot, /* card's slot (0..?) */ pciio_function_t func, /* card's func (0..?) */ pciio_vendor_id_t vendor, /* card's vendor number */ pciio_device_id_t device); /* card's device number */ extern void -pciio_device_unregister(devfs_handle_t connectpt); +pciio_device_unregister(vertex_hdl_t connectpt); extern pciio_info_t pciio_device_info_new (pciio_info_t pciio_info, /* preallocated info struct */ - devfs_handle_t master, /* card's master ASIC (pci provider) */ + vertex_hdl_t master, /* card's master ASIC (pci provider) */ pciio_slot_t slot, /* card's slot (0..?) */ pciio_function_t func, /* card's func (0..?) */ pciio_vendor_id_t vendor, /* card's vendor number */ @@ -616,24 +593,24 @@ extern void pciio_device_info_free(pciio_info_t pciio_info); -extern devfs_handle_t +extern vertex_hdl_t pciio_device_info_register( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info); /* details about conn point */ extern void pciio_device_info_unregister( - devfs_handle_t connectpt, /* vertex at center of bus */ + vertex_hdl_t connectpt, /* vertex at center of bus */ pciio_info_t pciio_info); /* details about conn point */ extern int pciio_device_attach( - devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + vertex_hdl_t pcicard, /* vertex created by pciio_device_register */ int drv_flags); extern int pciio_device_detach( - devfs_handle_t pcicard, /* vertex created by pciio_device_register */ + vertex_hdl_t pcicard, /* vertex created by pciio_device_register */ int drv_flags); @@ -654,20 +631,12 @@ size_t size); /* size of free range */ /* allocate window from mapping resource */ -#ifdef CONFIG_IA64_SGI_SN1 -extern iopaddr_t -pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ - pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ - size_t size, /* size of allocation */ - size_t align); /* alignment of allocation */ -#else extern iopaddr_t pciio_device_win_alloc(pciio_win_map_t win_map, /* win map */ pciio_win_alloc_t win_alloc, /* opaque allocation cookie */ size_t start, /* start unit, or 0 */ size_t size, /* size of allocation */ size_t align); /* alignment of allocation */ -#endif /* free previously allocated window */ extern void @@ -680,11 +649,11 @@ */ /* Generic PCI interrupt interfaces */ -extern devfs_handle_t pciio_intr_dev_get(pciio_intr_t pciio_intr); -extern devfs_handle_t pciio_intr_cpu_get(pciio_intr_t pciio_intr); +extern vertex_hdl_t pciio_intr_dev_get(pciio_intr_t pciio_intr); +extern vertex_hdl_t pciio_intr_cpu_get(pciio_intr_t pciio_intr); /* Generic PCI pio interfaces */ -extern devfs_handle_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap); +extern vertex_hdl_t pciio_pio_dev_get(pciio_piomap_t pciio_piomap); extern pciio_slot_t pciio_pio_slot_get(pciio_piomap_t pciio_piomap); extern pciio_space_t pciio_pio_space_get(pciio_piomap_t pciio_piomap); extern iopaddr_t pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap); @@ -692,26 +661,26 @@ extern caddr_t pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap); /* Generic PCI dma interfaces */ -extern devfs_handle_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); +extern vertex_hdl_t pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap); /* Register/unregister PCI providers and get implementation handle */ -extern void pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns); -extern void pciio_provider_unregister(devfs_handle_t provider); -extern pciio_provider_t *pciio_provider_fns_get(devfs_handle_t provider); +extern void pciio_provider_register(vertex_hdl_t provider, pciio_provider_t *pciio_fns); +extern void pciio_provider_unregister(vertex_hdl_t provider); +extern pciio_provider_t *pciio_provider_fns_get(vertex_hdl_t provider); /* Generic pci slot information access interface */ -extern pciio_info_t pciio_info_chk(devfs_handle_t vhdl); -extern pciio_info_t pciio_info_get(devfs_handle_t vhdl); -extern pciio_info_t pciio_hostinfo_get(devfs_handle_t vhdl); -extern void pciio_info_set(devfs_handle_t vhdl, pciio_info_t widget_info); -extern devfs_handle_t pciio_info_dev_get(pciio_info_t pciio_info); -extern devfs_handle_t pciio_info_hostdev_get(pciio_info_t pciio_info); +extern pciio_info_t pciio_info_chk(vertex_hdl_t vhdl); +extern pciio_info_t pciio_info_get(vertex_hdl_t vhdl); +extern pciio_info_t pciio_hostinfo_get(vertex_hdl_t vhdl); +extern void pciio_info_set(vertex_hdl_t vhdl, pciio_info_t widget_info); +extern vertex_hdl_t pciio_info_dev_get(pciio_info_t pciio_info); +extern vertex_hdl_t pciio_info_hostdev_get(pciio_info_t pciio_info); extern pciio_bus_t pciio_info_bus_get(pciio_info_t pciio_info); extern pciio_slot_t pciio_info_slot_get(pciio_info_t pciio_info); extern pciio_function_t pciio_info_function_get(pciio_info_t pciio_info); extern pciio_vendor_id_t pciio_info_vendor_id_get(pciio_info_t pciio_info); extern pciio_device_id_t pciio_info_device_id_get(pciio_info_t pciio_info); -extern devfs_handle_t pciio_info_master_get(pciio_info_t pciio_info); +extern vertex_hdl_t pciio_info_master_get(pciio_info_t pciio_info); extern arbitrary_info_t pciio_info_mfast_get(pciio_info_t pciio_info); extern pciio_provider_t *pciio_info_pops_get(pciio_info_t pciio_info); extern error_handler_f *pciio_info_efunc_get(pciio_info_t); @@ -722,8 +691,8 @@ extern iopaddr_t pciio_info_rom_base_get(pciio_info_t); extern size_t pciio_info_rom_size_get(pciio_info_t); extern int pciio_info_type1_get(pciio_info_t); -extern int pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *); -extern int pciio_dma_enabled(devfs_handle_t); +extern int pciio_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); +extern int pciio_dma_enabled(vertex_hdl_t); #endif /* C or C++ */ #endif /* _ASM_SN_PCI_PCIIO_H */ diff -Nru a/include/asm-ia64/sn/pci/pciio_private.h b/include/asm-ia64/sn/pci/pciio_private.h --- a/include/asm-ia64/sn/pci/pciio_private.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/pci/pciio_private.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_SN_PCI_PCIIO_PRIVATE_H #define _ASM_SN_PCI_PCIIO_PRIVATE_H @@ -24,7 +24,7 @@ */ struct pciio_piomap_s { unsigned pp_flags; /* PCIIO_PIOMAP flags */ - devfs_handle_t pp_dev; /* associated pci card */ + vertex_hdl_t pp_dev; /* associated pci card */ pciio_slot_t pp_slot; /* which slot the card is in */ pciio_space_t pp_space; /* which address space */ iopaddr_t pp_pciaddr; /* starting offset of mapping */ @@ -37,7 +37,7 @@ */ struct pciio_dmamap_s { unsigned pd_flags; /* PCIIO_DMAMAP flags */ - devfs_handle_t pd_dev; /* associated pci card */ + vertex_hdl_t pd_dev; /* associated pci card */ pciio_slot_t pd_slot; /* which slot the card is in */ }; @@ -47,7 +47,7 @@ struct pciio_intr_s { unsigned pi_flags; /* PCIIO_INTR flags */ - devfs_handle_t pi_dev; /* associated pci card */ + vertex_hdl_t pi_dev; /* associated pci card */ device_desc_t pi_dev_desc; /* override device descriptor */ pciio_intr_line_t pi_lines; /* which interrupt line(s) */ intr_func_t pi_func; /* handler function (when connected) */ @@ -100,13 +100,13 @@ struct pciio_info_s { char *c_fingerprint; - devfs_handle_t c_vertex; /* back pointer to vertex */ + vertex_hdl_t c_vertex; /* back pointer to vertex */ pciio_bus_t c_bus; /* which bus the card is in */ pciio_slot_t c_slot; /* which slot the card is in */ pciio_function_t c_func; /* which func (on multi-func cards) */ pciio_vendor_id_t c_vendor; /* PCI card "vendor" code */ pciio_device_id_t c_device; /* PCI card "device" code */ - devfs_handle_t c_master; /* PCI bus provider */ + vertex_hdl_t c_master; /* PCI bus provider */ arbitrary_info_t c_mfast; /* cached fastinfo from c_master */ pciio_provider_t *c_pops; /* cached provider from c_master */ error_handler_f *c_efunc; /* error handling function */ diff -Nru a/include/asm-ia64/sn/pda.h b/include/asm-ia64/sn/pda.h --- a/include/asm-ia64/sn/pda.h Tue Feb 25 02:48:06 2003 +++ b/include/asm-ia64/sn/pda.h Fri May 16 04:18:18 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PDA_H #define _ASM_IA64_SN_PDA_H @@ -26,15 +26,6 @@ * all SN per-cpu data structures. */ -#ifdef BUS_INT_WAR -#define POLL_ENTRIES 50 -typedef struct { - int irq; - int interval; - short tick; -} sn_poll_entry_t; -#endif - typedef struct pda_s { /* Having a pointer in the begining of PDA tends to increase @@ -48,31 +39,27 @@ /* * Support for SN LEDs */ -#ifdef CONFIG_IA64_SGI_SN1 - volatile long *led_address; -#else volatile short *led_address; -#endif u8 led_state; u8 hb_state; /* supports blinking heartbeat leds */ + u8 shub_1_1_found; unsigned int hb_count; unsigned int idle_flag; -#ifdef CONFIG_IA64_SGI_SN2 - struct irqpda_s *p_irqpda; /* Pointer to CPU irq data */ -#endif volatile unsigned long *bedrock_rev_id; volatile unsigned long *pio_write_status_addr; volatile unsigned long *pio_shub_war_cam_addr; volatile unsigned long *mem_write_status_addr; - bteinfo_t *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ + struct bteinfo_s *cpu_bte_if[BTES_PER_NODE]; /* cpu interface order */ -#ifdef BUS_INT_WAR - sn_poll_entry_t pda_poll_entries[POLL_ENTRIES]; - int pda_poll_entry_count; -#endif + unsigned long sn_soft_irr[4]; + unsigned long sn_in_service_ivecs[4]; + short cnodeid_to_nasid_table[NR_NODES]; + int sn_lb_int_war_ticks; + int sn_last_irq; + int sn_first_irq; } pda_t; @@ -96,5 +83,9 @@ #define pdacpu(cpu) (&per_cpu(pda_percpu, cpu)) +/* + * Use this macro to test if shub 1.1 wars should be enabled + */ +#define enable_shub_wars_1_1() (pda->shub_1_1_found) #endif /* _ASM_IA64_SN_PDA_H */ diff -Nru a/include/asm-ia64/sn/pio.h b/include/asm-ia64/sn/pio.h --- a/include/asm-ia64/sn/pio.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/pio.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PIO_H #define _ASM_IA64_SN_PIO_H @@ -32,19 +32,11 @@ typedef struct piomap { uint pio_bus; uint pio_adap; -#ifdef LATER - iospace_t pio_iospace; -#endif int pio_flag; int pio_reg; char pio_name[7]; /* to identify the mapped device */ struct piomap *pio_next; /* dlist to link active piomap's */ struct piomap *pio_prev; /* for debug and error reporting */ -#ifdef LATER - void (*pio_errfunc)(); /* Pointer to an error function */ - /* Used only for piomaps allocated - * in user level vme driver */ -#endif iopaddr_t pio_iopmask; /* valid iop address bit mask */ iobush_t pio_bushandle; /* bus-level handle */ } piomap_t; @@ -57,54 +49,6 @@ /* Macro to get/set PIO error function */ #define pio_seterrf(p,f) (p)->pio_errfunc = (f) #define pio_geterrf(p) (p)->pio_errfunc - - -/* - * pio_mapalloc() - allocates a handle that specifies a mapping from kernel - * virtual to io space. The returned handle piomap is used - * with the access functions to make sure that the mapping - * to the iospace exists. - * pio_mapfree() - frees the mapping as specified in the piomap handle. - * pio_mapaddr() - returns the kv address that maps to piomap'ed io address. - */ -#ifdef LATER -extern piomap_t *pio_mapalloc(uint,uint,iospace_t*,int,char*); -extern void pio_mapfree(piomap_t*); -extern caddr_t pio_mapaddr(piomap_t*,iopaddr_t); -extern piomap_t *pio_ioaddr(int, iobush_t, iopaddr_t, piomap_t *); - -/* - * PIO access functions. - */ -extern int pio_badaddr(piomap_t*,iopaddr_t,int); -extern int pio_badaddr_val(piomap_t*,iopaddr_t,int,void*); -extern int pio_wbadaddr(piomap_t*,iopaddr_t,int); -extern int pio_wbadaddr_val(piomap_t*,iopaddr_t,int,int); -extern int pio_bcopyin(piomap_t*,iopaddr_t,void *,int, int, int); -extern int pio_bcopyout(piomap_t*,iopaddr_t,void *,int, int, int); - - -/* - * PIO RMW functions using piomap. - */ -extern void pio_orb_rmw(piomap_t*, iopaddr_t, unsigned char); -extern void pio_orh_rmw(piomap_t*, iopaddr_t, unsigned short); -extern void pio_orw_rmw(piomap_t*, iopaddr_t, unsigned long); -extern void pio_andb_rmw(piomap_t*, iopaddr_t, unsigned char); -extern void pio_andh_rmw(piomap_t*, iopaddr_t, unsigned short); -extern void pio_andw_rmw(piomap_t*, iopaddr_t, unsigned long); - - -/* - * Old RMW function interface - */ -extern void orb_rmw(volatile void*, unsigned int); -extern void orh_rmw(volatile void*, unsigned int); -extern void orw_rmw(volatile void*, unsigned int); -extern void andb_rmw(volatile void*, unsigned int); -extern void andh_rmw(volatile void*, unsigned int); -extern void andw_rmw(volatile void*, unsigned int); -#endif /* LATER */ /* diff -Nru a/include/asm-ia64/sn/pio_flush.h b/include/asm-ia64/sn/pio_flush.h --- a/include/asm-ia64/sn/pio_flush.h Sat Mar 9 02:24:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,65 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#include - -#ifndef _ASM_IA64_PIO_FLUSH_H -#define _ASM_IA64_PIO_FLUSH_H - -/* - * This macro flushes all outstanding PIOs performed by this cpu to the - * intended destination SHUB. This in essence ensures that all PIO's - * issues by this cpu has landed at it's destination. - * - * This macro expects the caller: - * 1. The thread is locked. - * 2. All prior PIO operations has been fenced. - * - */ - -#if defined (CONFIG_IA64_SGI_SN) - -#include - -#if defined (CONFIG_IA64_SGI_SN2) - -#define PIO_FLUSH() \ - { \ - while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000) { \ - udelay(5); \ - } \ - __ia64_mf_a(); \ - } - -#elif defined (CONFIG_IA64_SGI_SN1) - -/* - * For SN1 we need to first read any local Bedrock's MMR and then poll on the - * Synergy MMR. - */ -#define PIO_FLUSH() \ - { \ - (volatile unsigned long) (*pda.bedrock_rev_id); \ - while (!(volatile unsigned long) (*pda.pio_write_status_addr)) { \ - udelay(5); \ - } \ - __ia64_mf_a(); \ - } -#endif -#else -/* - * For all ARCHITECTURE type, this is a NOOP. - */ - -#define PIO_FLUSH() - -#endif - -#endif /* _ASM_IA64_PIO_FLUSH_H */ diff -Nru a/include/asm-ia64/sn/prio.h b/include/asm-ia64/sn/prio.h --- a/include/asm-ia64/sn/prio.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/prio.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_PRIO_H #define _ASM_IA64_SN_PRIO_H diff -Nru a/include/asm-ia64/sn/router.h b/include/asm-ia64/sn/router.h --- a/include/asm-ia64/sn/router.h Fri Feb 14 15:30:42 2003 +++ b/include/asm-ia64/sn/router.h Fri May 16 04:18:17 2003 @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_ROUTER_H @@ -494,7 +494,7 @@ slotid_t ri_slotnum; /* Which slot are we in? */ router_reg_t ri_glbl_parms[GLBL_PARMS_REGS]; /* Global parms0&1 register contents*/ - devfs_handle_t ri_vertex; /* hardware graph vertex */ + vertex_hdl_t ri_vertex; /* hardware graph vertex */ router_reg_t ri_prot_conf; /* protection config. register */ int64_t ri_per_minute; /* Ticks per minute */ @@ -506,7 +506,7 @@ * the bottom of the structure, below the user stuff. */ char ri_hist_type; /* histogram type */ - devfs_handle_t ri_guardian; /* guardian node for the router */ + vertex_hdl_t ri_guardian; /* guardian node for the router */ int64_t ri_last_print; /* When did we last print */ char ri_print; /* Should we print */ char ri_just_blink; /* Should we blink the LEDs */ @@ -549,7 +549,7 @@ * Router info hanging in the nodepda */ typedef struct nodepda_router_info_s { - devfs_handle_t router_vhdl; /* vertex handle of the router */ + vertex_hdl_t router_vhdl; /* vertex handle of the router */ short router_port; /* port thru which we entered */ short router_portmask; moduleid_t router_module; /* module in which router is there */ @@ -593,9 +593,9 @@ */ struct { /* vertex handle for the router */ - devfs_handle_t vhdl; + vertex_hdl_t vhdl; /* guardian for this router */ - devfs_handle_t guard; + vertex_hdl_t guard; /* vector router from the guardian to the router */ net_vec_t vec; } k_elt; @@ -648,8 +648,7 @@ int router_reg_read(router_info_t *rip, int regno, router_reg_t *val); int router_reg_write(router_info_t *rip, int regno, router_reg_t val); -int router_get_info(devfs_handle_t routerv, router_info_t *, int); -int router_init(cnodeid_t cnode,int writeid, nodepda_router_info_t *npda_rip); +int router_get_info(vertex_hdl_t routerv, router_info_t *, int); int router_set_leds(router_info_t *rip); void router_print_state(router_info_t *rip, int level, void (*pf)(int, char *, ...),int print_where); @@ -658,7 +657,7 @@ int probe_routers(void); void get_routername(unsigned char brd_type,char *rtrname); -void router_guardians_set(devfs_handle_t hwgraph_root); +void router_guardians_set(vertex_hdl_t hwgraph_root); int router_hist_reselect(router_info_t *, int64_t); #endif /* __ASSEMBLY__ */ diff -Nru a/include/asm-ia64/sn/sgi.h b/include/asm-ia64/sn/sgi.h --- a/include/asm-ia64/sn/sgi.h Tue Dec 3 10:07:33 2002 +++ b/include/asm-ia64/sn/sgi.h Fri May 23 03:37:38 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -17,14 +17,15 @@ #include /* for copy_??_user */ #include #include +#include +#include + +typedef hwgfs_handle_t vertex_hdl_t; typedef int64_t __psint_t; /* needed by klgraph.c */ typedef enum { B_FALSE, B_TRUE } boolean_t; -#define ctob(x) ((uint64_t)(x)*NBPC) -#define btoc(x) (((uint64_t)(x)+(NBPC-1))/NBPC) - /* ** Possible return values from graph routines. @@ -50,28 +51,13 @@ typedef uint64_t vhandl_t; -#ifndef NBPP -#define NBPP 4096 -#endif - -#ifndef D_MP -#define D_MP 1 -#endif +#define NBPP PAGE_SIZE +#define _PAGESZ PAGE_SIZE #ifndef MAXDEVNAME #define MAXDEVNAME 256 #endif -#ifndef NBPC -#define NBPC 0 -#endif - -#ifndef _PAGESZ -#define _PAGESZ 4096 -#endif - -typedef uint64_t mrlock_t; /* needed by devsupport.c */ - #define HUB_PIO_CONVEYOR 0x1 #define CNODEID_NONE ((cnodeid_t)-1) #define XTALK_PCI_PART_NUM "030-1275-" @@ -81,10 +67,6 @@ #define COPYIN(a, b, c) copy_from_user(b,a,c) #define COPYOUT(a, b, c) copy_to_user(b,a,c) -#define kvtophys(x) (alenaddr_t) (x) -#define POFFMASK (NBPP - 1) -#define poff(X) ((__psunsigned_t)(X) & POFFMASK) - #define BZERO(a,b) memset(a, 0, b) #define kern_malloc(x) kmalloc(x, GFP_KERNEL) @@ -141,12 +123,6 @@ #define PRINT_PANIC panic -#ifdef CONFIG_SMP -#define cpu_enabled(cpu) (test_bit(cpu, &cpu_online_map)) -#else -#define cpu_enabled(cpu) (1) -#endif - /* print_register() defs */ /* @@ -172,6 +148,31 @@ extern void print_register(unsigned long long, struct reg_desc *); -#include /* for now */ +/****************************************** + * Definitions that do not exist in linux * + ******************************************/ + +#define DELAY(a) + +/************************************************ + * Routines redefined to use linux equivalents. * + ************************************************/ + +/* #define FIXME(s) printk("FIXME: [ %s ] in %s at %s:%d\n", s, __FUNCTION__, __FILE__, __LINE__) */ + +#define FIXME(s) + +/* move to stubs.c yet */ +#define dev_to_vhdl(dev) 0 +#define get_timestamp() 0 +#define us_delay(a) +#define v_mapphys(a,b,c) 0 // printk("Fixme: v_mapphys - soft->base 0x%p\n", b); +#define splhi() 0 +#define splx(s) + +extern void * snia_kmem_alloc_node(register size_t, register int, cnodeid_t); +extern void * snia_kmem_zalloc(size_t, int); +extern void * snia_kmem_zalloc_node(register size_t, register int, cnodeid_t ); +extern int is_specified(char *); #endif /* _ASM_IA64_SN_SGI_H */ diff -Nru a/include/asm-ia64/sn/simulator.h b/include/asm-ia64/sn/simulator.h --- a/include/asm-ia64/sn/simulator.h Sat Mar 9 02:24:40 2002 +++ b/include/asm-ia64/sn/simulator.h Fri May 16 04:18:19 2003 @@ -5,7 +5,7 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #include diff -Nru a/include/asm-ia64/sn/slotnum.h b/include/asm-ia64/sn/slotnum.h --- a/include/asm-ia64/sn/slotnum.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/slotnum.h Fri May 16 04:18:18 2003 @@ -4,23 +4,14 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SLOTNUM_H #define _ASM_IA64_SN_SLOTNUM_H -#include typedef unsigned char slotid_t; -#if defined (CONFIG_IA64_SGI_SN1) -#include -#elif defined (CONFIG_IA64_SGI_SN2) #include -#else - -#error <> - -#endif /* !CONFIG_IA64_SGI_SN1 */ #endif /* _ASM_IA64_SN_SLOTNUM_H */ diff -Nru a/include/asm-ia64/sn/sn1/addrs.h b/include/asm-ia64/sn/sn1/addrs.h --- a/include/asm-ia64/sn/sn1/addrs.h Tue Dec 3 10:07:33 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,275 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_ADDRS_H -#define _ASM_IA64_SN_SN1_ADDRS_H - -#include - -#ifdef CONFIG_IA64_SGI_SN1 -/* - * SN1 (on a TRex) Address map - * - * This file contains a set of definitions and macros which are used - * to reference into the major address spaces (CAC, HSPEC, IO, MSPEC, - * and UNCAC) used by the SN1 architecture. It also contains addresses - * for "major" statically locatable PROM/Kernel data structures, such as - * the partition table, the configuration data structure, etc. - * We make an implicit assumption that the processor using this file - * follows the R12K's provisions for specifying uncached attributes; - * should this change, the base registers may very well become processor- - * dependent. - * - * For more information on the address spaces, see the "Local Resources" - * chapter of the Hub specification. - * - * NOTE: This header file is included both by C and by assembler source - * files. Please bracket any language-dependent definitions - * appropriately. - */ - - -/* - * Some of the macros here need to be casted to appropriate types when used - * from C. They definitely must not be casted from assembly language so we - * use some new ANSI preprocessor stuff to paste these on where needed. - */ - -#define CACHEABLE_MEM_SPACE 0xe000000000000000 -#define CAC_BASE CACHEABLE_MEM_SPACE -#define HSPEC_BASE 0xc0000b0000000000 -#define HSPEC_SWIZ_BASE 0xc000030000000000 -#define IO_BASE 0xc0000a0000000000 -#define IO_SWIZ_BASE 0xc000020000000000 -#define MSPEC_BASE 0xc000090000000000 -#define UNCAC_BASE 0xc000000000000000 -#define TO_PHYS_MASK 0x000000ffffffffff - -#define TO_PHYS(x) ( ((x) & TO_PHYS_MASK)) -#define TO_CAC(x) (CAC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_UNCAC(x) (UNCAC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_MSPEC(x) (MSPEC_BASE | ((x) & TO_PHYS_MASK)) -#define TO_HSPEC(x) (HSPEC_BASE | ((x) & TO_PHYS_MASK)) - - -/* - * The following couple of definitions will eventually need to be variables, - * since the amount of address space assigned to each node depends on - * whether the system is running in N-mode (more nodes with less memory) - * or M-mode (fewer nodes with more memory). We expect that it will - * be a while before we need to make this decision dynamically, though, - * so for now we just use defines bracketed by an ifdef. - */ - -#if defined(N_MODE) - -#define NODE_SIZE_BITS 32 -#define BWIN_SIZE_BITS 28 - -#define NASID_BITS 8 -#define NASID_BITMASK (0xffLL) -#define NASID_SHFT 32 -#define NASID_META_BITS 1 -#define NASID_LOCAL_BITS 7 - -#define BDDIR_UPPER_MASK (UINT64_CAST 0x1ffffff << 4) -#define BDECC_UPPER_MASK (UINT64_CAST 0x1fffffff ) - -#else /* !defined(N_MODE), assume that M-mode is desired */ - -#define NODE_SIZE_BITS 33 -#define BWIN_SIZE_BITS 29 - -#define NASID_BITMASK (0x7fLL) -#define NASID_BITS 7 -#define NASID_SHFT 33 -#define NASID_META_BITS 0 -#define NASID_LOCAL_BITS 7 - -#define BDDIR_UPPER_MASK (UINT64_CAST 0x3ffffff << 4) -#define BDECC_UPPER_MASK (UINT64_CAST 0x3fffffff) - -#endif /* defined(N_MODE) */ - -#define NODE_ADDRSPACE_SIZE (UINT64_CAST 1 << NODE_SIZE_BITS) - -#define NASID_MASK (UINT64_CAST NASID_BITMASK << NASID_SHFT) -#define NASID_GET(_pa) (int) ((UINT64_CAST (_pa) >> \ - NASID_SHFT) & NASID_BITMASK) - -#ifndef __ASSEMBLY__ -#define NODE_SWIN_BASE(nasid, widget) \ - ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN) \ - : RAW_NODE_SWIN_BASE(nasid, widget)) -#else -#define NODE_SWIN_BASE(nasid, widget) \ - (NODE_IO_BASE(nasid) + (UINT64_CAST (widget) << SWIN_SIZE_BITS)) -#endif /* __ASSEMBLY__ */ - -/* - * The following definitions pertain to the IO special address - * space. They define the location of the big and little windows - * of any given node. - */ - -#define BWIN_INDEX_BITS 3 -#define BWIN_SIZE (UINT64_CAST 1 << BWIN_SIZE_BITS) -#define BWIN_SIZEMASK (BWIN_SIZE - 1) -#define BWIN_WIDGET_MASK 0x7 -#define NODE_BWIN_BASE0(nasid) (NODE_IO_BASE(nasid) + BWIN_SIZE) -#define NODE_BWIN_BASE(nasid, bigwin) (NODE_BWIN_BASE0(nasid) + \ - (UINT64_CAST (bigwin) << BWIN_SIZE_BITS)) - -#define BWIN_WIDGETADDR(addr) ((addr) & BWIN_SIZEMASK) -#define BWIN_WINDOWNUM(addr) (((addr) >> BWIN_SIZE_BITS) & BWIN_WIDGET_MASK) -/* - * Verify if addr belongs to large window address of node with "nasid" - * - * - * NOTE: "addr" is expected to be XKPHYS address, and NOT physical - * address - * - * - */ - -#define NODE_BWIN_ADDR(nasid, addr) \ - (((addr) >= NODE_BWIN_BASE0(nasid)) && \ - ((addr) < (NODE_BWIN_BASE(nasid, HUB_NUM_BIG_WINDOW) + \ - BWIN_SIZE))) - -/* - * The following define the major position-independent aliases used - * in SN1. - * CALIAS -- Varies in size, points to the first n bytes of memory - * on the reader's node. - */ - -#define CALIAS_BASE CAC_BASE - - - -#define BRIDGE_REG_PTR(_base, _off) ((volatile bridgereg_t *) \ - ((__psunsigned_t)(_base) + (__psunsigned_t)(_off))) - -#define SN0_WIDGET_BASE(_nasid, _wid) (NODE_SWIN_BASE((_nasid), (_wid))) - - - -/* - * needed by symmon so it needs to be outside #if PROM - * (see also POD_ELSCSIZE) - */ -#define IP27PROM_ELSC_BASE_A PHYS_TO_K0(0x020e0000) -#define IP27PROM_ELSC_BASE_B PHYS_TO_K0(0x020e0800) -#define IP27PROM_ELSC_BASE_C PHYS_TO_K0(0x020e1000) -#define IP27PROM_ELSC_BASE_D PHYS_TO_K0(0x020e1800) -#define IP27PROM_ELSC_SHFT 11 -#define IP27PROM_ELSC_SIZE (1 << IP27PROM_ELSC_SHFT) - -#define FREEMEM_BASE PHYS_TO_K0(0x4000000) - -#define IO6PROM_STACK_SHFT 14 /* stack per cpu */ -#define IO6PROM_STACK_SIZE (1 << IO6PROM_STACK_SHFT) - - -#define KL_UART_BASE LOCAL_HSPEC(HSPEC_UART_0) /* base of UART regs */ -#define KL_UART_CMD LOCAL_HSPEC(HSPEC_UART_0) /* UART command reg */ -#define KL_UART_DATA LOCAL_HSPEC(HSPEC_UART_1) /* UART data reg */ - -#if !__ASSEMBLY__ -/* Address 0x400 to 0x1000 ualias points to cache error eframe + misc - * CACHE_ERR_SP_PTR could either contain an address to the stack, or - * the stack could start at CACHE_ERR_SP_PTR - */ -#define CACHE_ERR_EFRAME 0x400 - -#define CACHE_ERR_ECCFRAME (CACHE_ERR_EFRAME + EF_SIZE) -#define CACHE_ERR_SP_PTR (0x1000 - 32) /* why -32? TBD */ -#define CACHE_ERR_IBASE_PTR (0x1000 - 40) -#define CACHE_ERR_SP (CACHE_ERR_SP_PTR - 16) -#define CACHE_ERR_AREA_SIZE (ARCS_SPB_OFFSET - CACHE_ERR_EFRAME) - -#endif /* !__ASSEMBLY__ */ - - - -#define _ARCSPROM - -#ifdef _STANDALONE - -/* - * The PROM needs to pass the device base address and the - * device pci cfg space address to the device drivers during - * install. The COMPONENT->Key field is used for this purpose. - * Macros needed by SN1 device drivers to convert the - * COMPONENT->Key field to the respective base address. - * Key field looks as follows: - * - * +----------------------------------------------------+ - * |devnasid | widget |pciid |hubwidid|hstnasid | adap | - * | 2 | 1 | 1 | 1 | 2 | 1 | - * +----------------------------------------------------+ - * | | | | | | | - * 64 48 40 32 24 8 0 - * - * These are used by standalone drivers till the io infrastructure - * is in place. - */ - -#ifndef __ASSEMBLY__ - -#define uchar unsigned char - -#define KEY_DEVNASID_SHFT 48 -#define KEY_WIDID_SHFT 40 -#define KEY_PCIID_SHFT 32 -#define KEY_HUBWID_SHFT 24 -#define KEY_HSTNASID_SHFT 8 - -#define MK_SN0_KEY(nasid, widid, pciid) \ - ((((__psunsigned_t)nasid)<< KEY_DEVNASID_SHFT |\ - ((__psunsigned_t)widid) << KEY_WIDID_SHFT) |\ - ((__psunsigned_t)pciid) << KEY_PCIID_SHFT) - -#define ADD_HUBWID_KEY(key,hubwid)\ - (key|=((__psunsigned_t)hubwid << KEY_HUBWID_SHFT)) - -#define ADD_HSTNASID_KEY(key,hstnasid)\ - (key|=((__psunsigned_t)hstnasid << KEY_HSTNASID_SHFT)) - -#define GET_DEVNASID_FROM_KEY(key) ((short)(key >> KEY_DEVNASID_SHFT)) -#define GET_WIDID_FROM_KEY(key) ((uchar)(key >> KEY_WIDID_SHFT)) -#define GET_PCIID_FROM_KEY(key) ((uchar)(key >> KEY_PCIID_SHFT)) -#define GET_HUBWID_FROM_KEY(key) ((uchar)(key >> KEY_HUBWID_SHFT)) -#define GET_HSTNASID_FROM_KEY(key) ((short)(key >> KEY_HSTNASID_SHFT)) - -#define PCI_64_TARGID_SHFT 60 - -#define GET_PCIBASE_FROM_KEY(key) (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_DEVIO(GET_PCIID_FROM_KEY(key))) - -#define GET_PCICFGBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))\ - | BRIDGE_TYPE0_CFG_DEV(GET_PCIID_FROM_KEY(key))) - -#define GET_WIDBASE_FROM_KEY(key) \ - (NODE_SWIN_BASE(GET_DEVNASID_FROM_KEY(key),\ - GET_WIDID_FROM_KEY(key))) - -#define PUT_INSTALL_STATUS(c,s) c->Revision = s -#define GET_INSTALL_STATUS(c) c->Revision - -#endif /* __ASSEMBLY__ */ - -#endif /* _STANDALONE */ -#endif /* CONFIG_IA64_SGI_SN1 */ - -#endif /* _ASM_IA64_SN_SN1_ADDRS_H */ diff -Nru a/include/asm-ia64/sn/sn1/arch.h b/include/asm-ia64/sn/sn1/arch.h --- a/include/asm-ia64/sn/sn1/arch.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,89 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_ARCH_H -#define _ASM_IA64_SN_SN1_ARCH_H - -#if defined(N_MODE) -#error "ERROR constants defined only for M-mode" -#endif - -#include -#include - -#define CPUS_PER_NODE 4 /* CPUs on a single hub */ -#define CPUS_PER_SUBNODE 2 /* CPUs on a single hub PI */ - -/* - * This is the maximum number of NASIDS that can be present in a system. - * This include ALL nodes in ALL partitions connected via NUMALINK. - * (Highest NASID plus one.) - */ -#define MAX_NASIDS 128 - -/* - * This is the maximum number of nodes that can be part of a kernel. - * Effectively, it's the maximum number of compact node ids (cnodeid_t). - * This is not necessarily the same as MAX_NASIDS. - */ -#define MAX_COMPACT_NODES 128 - -/* - * MAX_REGIONS refers to the maximum number of hardware partitioned regions. - */ -#define MAX_REGIONS 64 -#define MAX_NONPREMIUM_REGIONS 16 -#define MAX_PREMIUM_REGIONS MAX_REGIONS - -/* - * Slot constants for IP35 - */ - -#define MAX_MEM_SLOTS 8 /* max slots per node */ - -#if defined(N_MODE) -#error "N-mode not supported" -#endif - -#define SLOT_SHIFT (30) -#define SLOT_MIN_MEM_SIZE (64*1024*1024) - - -/* - * MAX_PARITIONS refers to the maximum number of logically defined - * partitions the system can support. - */ -#define MAX_PARTITIONS MAX_REGIONS - - -#define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) - -/* - * New stuff in here from Irix sys/pfdat.h. - */ -#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) -#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) -#define slot_getbasepfn(node,slot) (mkpfn(COMPACT_TO_NASID_NODEID(node), slot<> SUBNODE_SHFT) -#define LOCALCPU(slice) (((slice) & LOCALCPU_MASK) >> LOCALCPU_SHFT) -#define TO_SLICE(subn, local) (((subn) << SUBNODE_SHFT) | \ - ((local) << LOCALCPU_SHFT)) - -#endif /* _ASM_IA64_SN_SN1_ARCH_H */ diff -Nru a/include/asm-ia64/sn/sn1/bedrock.h b/include/asm-ia64/sn/sn1/bedrock.h --- a/include/asm-ia64/sn/sn1/bedrock.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,74 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_BEDROCK_H -#define _ASM_IA64_SN_SN1_BEDROCK_H - - -/* The secret password; used to release protection */ -#define HUB_PASSWORD 0x53474972756c6573ull - -#define CHIPID_HUB 0x3012 -#define CHIPID_ROUTER 0x3017 - -#define BEDROCK_REV_1_0 1 -#define BEDROCK_REV_1_1 2 - -#define MAX_HUB_PATH 80 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Translation of uncached attributes */ -#define UATTR_HSPEC 0 -#define UATTR_IO 1 -#define UATTR_MSPEC 2 -#define UATTR_UNCAC 3 - -#if __ASSEMBLY__ - -/* - * Get nasid into register, r (uses at) - */ -#define GET_NASID_ASM(r) \ - dli r, LOCAL_HUB_ADDR(LB_REV_ID); \ - ld r, (r); \ - and r, LRI_NODEID_MASK; \ - dsrl r, LRI_NODEID_SHFT - -#endif /* __ASSEMBLY__ */ - -#ifndef __ASSEMBLY__ - -#include - -/* hub-as-widget iograph info, labelled by INFO_LBL_XWIDGET */ -typedef struct v_hub_s *v_hub_t; -typedef uint64_t rtc_time_t; - -struct nodepda_s; -int hub_check_pci_equiv(void *addra, void *addrb); -void capture_hub_stats(cnodeid_t, struct nodepda_s *); -void init_hub_stats(cnodeid_t, struct nodepda_s *); - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_IA64_SN_SN1_BEDROCK_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubdev.h b/include/asm-ia64/sn/sn1/hubdev.h --- a/include/asm-ia64/sn/sn1/hubdev.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,21 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_HUBDEV_H -#define _ASM_IA64_SN_SN1_HUBDEV_H - -extern void hubdev_init(void); -extern void hubdev_register(int (*attach_method)(devfs_handle_t)); -extern int hubdev_unregister(int (*attach_method)(devfs_handle_t)); -extern int hubdev_docallouts(devfs_handle_t hub); - -extern caddr_t hubdev_prombase_get(devfs_handle_t hub); -extern cnodeid_t hubdev_cnodeid_get(devfs_handle_t hub); - -#endif /* _ASM_IA64_SN_SN1_HUBDEV_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubio.h b/include/asm-ia64/sn/sn1/hubio.h --- a/include/asm-ia64/sn/sn1/hubio.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,5016 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#ifndef _ASM_IA64_SN_SN1_HUBIO_H -#define _ASM_IA64_SN_SN1_HUBIO_H - - -#define IIO_WID 0x00400000 /* - * Crosstalk Widget - * Identification This - * register is also - * accessible from - * Crosstalk at - * address 0x0. - */ - - - -#define IIO_WSTAT 0x00400008 /* - * Crosstalk Widget - * Status - */ - - - -#define IIO_WCR 0x00400020 /* - * Crosstalk Widget - * Control Register - */ - - - -#define IIO_ILAPR 0x00400100 /* - * IO Local Access - * Protection Register - */ - - - -#define IIO_ILAPO 0x00400108 /* - * IO Local Access - * Protection Override - */ - - - -#define IIO_IOWA 0x00400110 /* - * IO Outbound Widget - * Access - */ - - - -#define IIO_IIWA 0x00400118 /* - * IO Inbound Widget - * Access - */ - - - -#define IIO_IIDEM 0x00400120 /* - * IO Inbound Device - * Error Mask - */ - - - -#define IIO_ILCSR 0x00400128 /* - * IO LLP Control and - * Status Register - */ - - - -#define IIO_ILLR 0x00400130 /* IO LLP Log Register */ - - - -#define IIO_IIDSR 0x00400138 /* - * IO Interrupt - * Destination - */ - - - -#define IIO_IGFX0 0x00400140 /* - * IO Graphics - * Node-Widget Map 0 - */ - - - -#define IIO_IGFX1 0x00400148 /* - * IO Graphics - * Node-Widget Map 1 - */ - - - -#define IIO_ISCR0 0x00400150 /* - * IO Scratch Register - * 0 - */ - - - -#define IIO_ISCR1 0x00400158 /* - * IO Scratch Register - * 1 - */ - - - -#define IIO_ITTE1 0x00400160 /* - * IO Translation - * Table Entry 1 - */ - - - -#define IIO_ITTE2 0x00400168 /* - * IO Translation - * Table Entry 2 - */ - - - -#define IIO_ITTE3 0x00400170 /* - * IO Translation - * Table Entry 3 - */ - - - -#define IIO_ITTE4 0x00400178 /* - * IO Translation - * Table Entry 4 - */ - - - -#define IIO_ITTE5 0x00400180 /* - * IO Translation - * Table Entry 5 - */ - - - -#define IIO_ITTE6 0x00400188 /* - * IO Translation - * Table Entry 6 - */ - - - -#define IIO_ITTE7 0x00400190 /* - * IO Translation - * Table Entry 7 - */ - - - -#define IIO_IPRB0 0x00400198 /* IO PRB Entry 0 */ - - - -#define IIO_IPRB8 0x004001A0 /* IO PRB Entry 8 */ - - - -#define IIO_IPRB9 0x004001A8 /* IO PRB Entry 9 */ - - - -#define IIO_IPRBA 0x004001B0 /* IO PRB Entry A */ - - - -#define IIO_IPRBB 0x004001B8 /* IO PRB Entry B */ - - - -#define IIO_IPRBC 0x004001C0 /* IO PRB Entry C */ - - - -#define IIO_IPRBD 0x004001C8 /* IO PRB Entry D */ - - - -#define IIO_IPRBE 0x004001D0 /* IO PRB Entry E */ - - - -#define IIO_IPRBF 0x004001D8 /* IO PRB Entry F */ - - - -#define IIO_IXCC 0x004001E0 /* - * IO Crosstalk Credit - * Count Timeout - */ - - - -#define IIO_IMEM 0x004001E8 /* - * IO Miscellaneous - * Error Mask - */ - - - -#define IIO_IXTT 0x004001F0 /* - * IO Crosstalk - * Timeout Threshold - */ - - - -#define IIO_IECLR 0x004001F8 /* - * IO Error Clear - * Register - */ - - - -#define IIO_IBCR 0x00400200 /* - * IO BTE Control - * Register - */ - - - -#define IIO_IXSM 0x00400208 /* - * IO Crosstalk - * Spurious Message - */ - - - -#define IIO_IXSS 0x00400210 /* - * IO Crosstalk - * Spurious Sideband - */ - - - -#define IIO_ILCT 0x00400218 /* IO LLP Channel Test */ - - - -#define IIO_IIEPH1 0x00400220 /* - * IO Incoming Error - * Packet Header, Part - * 1 - */ - - - -#define IIO_IIEPH2 0x00400228 /* - * IO Incoming Error - * Packet Header, Part - * 2 - */ - - - -#define IIO_IPCA 0x00400300 /* - * IO PRB Counter - * Adjust - */ - - - -#define IIO_IPRTE0 0x00400308 /* - * IO PIO Read Address - * Table Entry 0 - */ - - - -#define IIO_IPRTE1 0x00400310 /* - * IO PIO Read Address - * Table Entry 1 - */ - - - -#define IIO_IPRTE2 0x00400318 /* - * IO PIO Read Address - * Table Entry 2 - */ - - - -#define IIO_IPRTE3 0x00400320 /* - * IO PIO Read Address - * Table Entry 3 - */ - - - -#define IIO_IPRTE4 0x00400328 /* - * IO PIO Read Address - * Table Entry 4 - */ - - - -#define IIO_IPRTE5 0x00400330 /* - * IO PIO Read Address - * Table Entry 5 - */ - - - -#define IIO_IPRTE6 0x00400338 /* - * IO PIO Read Address - * Table Entry 6 - */ - - - -#define IIO_IPRTE7 0x00400340 /* - * IO PIO Read Address - * Table Entry 7 - */ - - - -#define IIO_IPDR 0x00400388 /* - * IO PIO Deallocation - * Register - */ - - - -#define IIO_ICDR 0x00400390 /* - * IO CRB Entry - * Deallocation - * Register - */ - - - -#define IIO_IFDR 0x00400398 /* - * IO IOQ FIFO Depth - * Register - */ - - - -#define IIO_IIAP 0x004003A0 /* - * IO IIQ Arbitration - * Parameters - */ - - - -#define IIO_ICMR 0x004003A8 /* - * IO CRB Management - * Register - */ - - - -#define IIO_ICCR 0x004003B0 /* - * IO CRB Control - * Register - */ - - - -#define IIO_ICTO 0x004003B8 /* IO CRB Timeout */ - - - -#define IIO_ICTP 0x004003C0 /* - * IO CRB Timeout - * Prescalar - */ - - - -#define IIO_ICRB0_A 0x00400400 /* IO CRB Entry 0_A */ - - - -#define IIO_ICRB0_B 0x00400408 /* IO CRB Entry 0_B */ - - - -#define IIO_ICRB0_C 0x00400410 /* IO CRB Entry 0_C */ - - - -#define IIO_ICRB0_D 0x00400418 /* IO CRB Entry 0_D */ - - - -#define IIO_ICRB1_A 0x00400420 /* IO CRB Entry 1_A */ - - - -#define IIO_ICRB1_B 0x00400428 /* IO CRB Entry 1_B */ - - - -#define IIO_ICRB1_C 0x00400430 /* IO CRB Entry 1_C */ - - - -#define IIO_ICRB1_D 0x00400438 /* IO CRB Entry 1_D */ - - - -#define IIO_ICRB2_A 0x00400440 /* IO CRB Entry 2_A */ - - - -#define IIO_ICRB2_B 0x00400448 /* IO CRB Entry 2_B */ - - - -#define IIO_ICRB2_C 0x00400450 /* IO CRB Entry 2_C */ - - - -#define IIO_ICRB2_D 0x00400458 /* IO CRB Entry 2_D */ - - - -#define IIO_ICRB3_A 0x00400460 /* IO CRB Entry 3_A */ - - - -#define IIO_ICRB3_B 0x00400468 /* IO CRB Entry 3_B */ - - - -#define IIO_ICRB3_C 0x00400470 /* IO CRB Entry 3_C */ - - - -#define IIO_ICRB3_D 0x00400478 /* IO CRB Entry 3_D */ - - - -#define IIO_ICRB4_A 0x00400480 /* IO CRB Entry 4_A */ - - - -#define IIO_ICRB4_B 0x00400488 /* IO CRB Entry 4_B */ - - - -#define IIO_ICRB4_C 0x00400490 /* IO CRB Entry 4_C */ - - - -#define IIO_ICRB4_D 0x00400498 /* IO CRB Entry 4_D */ - - - -#define IIO_ICRB5_A 0x004004A0 /* IO CRB Entry 5_A */ - - - -#define IIO_ICRB5_B 0x004004A8 /* IO CRB Entry 5_B */ - - - -#define IIO_ICRB5_C 0x004004B0 /* IO CRB Entry 5_C */ - - - -#define IIO_ICRB5_D 0x004004B8 /* IO CRB Entry 5_D */ - - - -#define IIO_ICRB6_A 0x004004C0 /* IO CRB Entry 6_A */ - - - -#define IIO_ICRB6_B 0x004004C8 /* IO CRB Entry 6_B */ - - - -#define IIO_ICRB6_C 0x004004D0 /* IO CRB Entry 6_C */ - - - -#define IIO_ICRB6_D 0x004004D8 /* IO CRB Entry 6_D */ - - - -#define IIO_ICRB7_A 0x004004E0 /* IO CRB Entry 7_A */ - - - -#define IIO_ICRB7_B 0x004004E8 /* IO CRB Entry 7_B */ - - - -#define IIO_ICRB7_C 0x004004F0 /* IO CRB Entry 7_C */ - - - -#define IIO_ICRB7_D 0x004004F8 /* IO CRB Entry 7_D */ - - - -#define IIO_ICRB8_A 0x00400500 /* IO CRB Entry 8_A */ - - - -#define IIO_ICRB8_B 0x00400508 /* IO CRB Entry 8_B */ - - - -#define IIO_ICRB8_C 0x00400510 /* IO CRB Entry 8_C */ - - - -#define IIO_ICRB8_D 0x00400518 /* IO CRB Entry 8_D */ - - - -#define IIO_ICRB9_A 0x00400520 /* IO CRB Entry 9_A */ - - - -#define IIO_ICRB9_B 0x00400528 /* IO CRB Entry 9_B */ - - - -#define IIO_ICRB9_C 0x00400530 /* IO CRB Entry 9_C */ - - - -#define IIO_ICRB9_D 0x00400538 /* IO CRB Entry 9_D */ - - - -#define IIO_ICRBA_A 0x00400540 /* IO CRB Entry A_A */ - - - -#define IIO_ICRBA_B 0x00400548 /* IO CRB Entry A_B */ - - - -#define IIO_ICRBA_C 0x00400550 /* IO CRB Entry A_C */ - - - -#define IIO_ICRBA_D 0x00400558 /* IO CRB Entry A_D */ - - - -#define IIO_ICRBB_A 0x00400560 /* IO CRB Entry B_A */ - - - -#define IIO_ICRBB_B 0x00400568 /* IO CRB Entry B_B */ - - - -#define IIO_ICRBB_C 0x00400570 /* IO CRB Entry B_C */ - - - -#define IIO_ICRBB_D 0x00400578 /* IO CRB Entry B_D */ - - - -#define IIO_ICRBC_A 0x00400580 /* IO CRB Entry C_A */ - - - -#define IIO_ICRBC_B 0x00400588 /* IO CRB Entry C_B */ - - - -#define IIO_ICRBC_C 0x00400590 /* IO CRB Entry C_C */ - - - -#define IIO_ICRBC_D 0x00400598 /* IO CRB Entry C_D */ - - - -#define IIO_ICRBD_A 0x004005A0 /* IO CRB Entry D_A */ - - - -#define IIO_ICRBD_B 0x004005A8 /* IO CRB Entry D_B */ - - - -#define IIO_ICRBD_C 0x004005B0 /* IO CRB Entry D_C */ - - - -#define IIO_ICRBD_D 0x004005B8 /* IO CRB Entry D_D */ - - - -#define IIO_ICRBE_A 0x004005C0 /* IO CRB Entry E_A */ - - - -#define IIO_ICRBE_B 0x004005C8 /* IO CRB Entry E_B */ - - - -#define IIO_ICRBE_C 0x004005D0 /* IO CRB Entry E_C */ - - - -#define IIO_ICRBE_D 0x004005D8 /* IO CRB Entry E_D */ - - - -#define IIO_ICSML 0x00400600 /* - * IO CRB Spurious - * Message Low - */ - - - -#define IIO_ICSMH 0x00400608 /* - * IO CRB Spurious - * Message High - */ - - - -#define IIO_IDBSS 0x00400610 /* - * IO Debug Submenu - * Select - */ - - - -#define IIO_IBLS0 0x00410000 /* - * IO BTE Length - * Status 0 - */ - - - -#define IIO_IBSA0 0x00410008 /* - * IO BTE Source - * Address 0 - */ - - - -#define IIO_IBDA0 0x00410010 /* - * IO BTE Destination - * Address 0 - */ - - - -#define IIO_IBCT0 0x00410018 /* - * IO BTE Control - * Terminate 0 - */ - - - -#define IIO_IBNA0 0x00410020 /* - * IO BTE Notification - * Address 0 - */ - - - -#define IIO_IBIA0 0x00410028 /* - * IO BTE Interrupt - * Address 0 - */ - - - -#define IIO_IBLS1 0x00420000 /* - * IO BTE Length - * Status 1 - */ - - - -#define IIO_IBSA1 0x00420008 /* - * IO BTE Source - * Address 1 - */ - - - -#define IIO_IBDA1 0x00420010 /* - * IO BTE Destination - * Address 1 - */ - - - -#define IIO_IBCT1 0x00420018 /* - * IO BTE Control - * Terminate 1 - */ - - - -#define IIO_IBNA1 0x00420020 /* - * IO BTE Notification - * Address 1 - */ - - - -#define IIO_IBIA1 0x00420028 /* - * IO BTE Interrupt - * Address 1 - */ - - - -#define IIO_IPCR 0x00430000 /* - * IO Performance - * Control - */ - - - -#define IIO_IPPR 0x00430008 /* - * IO Performance - * Profiling - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register echoes some information from the * - * LB_REV_ID register. It is available through Crosstalk as described * - * above. The REV_NUM and MFG_NUM fields receive their values from * - * the REVISION and MANUFACTURER fields in the LB_REV_ID register. * - * The PART_NUM field's value is the Crosstalk device ID number that * - * Steve Miller assigned to the Bedrock chip. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wid_u { - bdrkreg_t ii_wid_regval; - struct { - bdrkreg_t w_rsvd_1 : 1; - bdrkreg_t w_mfg_num : 11; - bdrkreg_t w_part_num : 16; - bdrkreg_t w_rev_num : 4; - bdrkreg_t w_rsvd : 32; - } ii_wid_fld_s; -} ii_wid_u_t; - -#else - -typedef union ii_wid_u { - bdrkreg_t ii_wid_regval; - struct { - bdrkreg_t w_rsvd : 32; - bdrkreg_t w_rev_num : 4; - bdrkreg_t w_part_num : 16; - bdrkreg_t w_mfg_num : 11; - bdrkreg_t w_rsvd_1 : 1; - } ii_wid_fld_s; -} ii_wid_u_t; - -#endif - - - - -/************************************************************************ - * * - * The fields in this register are set upon detection of an error * - * and cleared by various mechanisms, as explained in the * - * description. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wstat_u { - bdrkreg_t ii_wstat_regval; - struct { - bdrkreg_t w_pending : 4; - bdrkreg_t w_xt_crd_to : 1; - bdrkreg_t w_xt_tail_to : 1; - bdrkreg_t w_rsvd_3 : 3; - bdrkreg_t w_tx_mx_rty : 1; - bdrkreg_t w_rsvd_2 : 6; - bdrkreg_t w_llp_tx_cnt : 8; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_crazy : 1; - bdrkreg_t w_rsvd : 31; - } ii_wstat_fld_s; -} ii_wstat_u_t; - -#else - -typedef union ii_wstat_u { - bdrkreg_t ii_wstat_regval; - struct { - bdrkreg_t w_rsvd : 31; - bdrkreg_t w_crazy : 1; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_llp_tx_cnt : 8; - bdrkreg_t w_rsvd_2 : 6; - bdrkreg_t w_tx_mx_rty : 1; - bdrkreg_t w_rsvd_3 : 3; - bdrkreg_t w_xt_tail_to : 1; - bdrkreg_t w_xt_crd_to : 1; - bdrkreg_t w_pending : 4; - } ii_wstat_fld_s; -} ii_wstat_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This is a read-write enabled register. It controls * - * various aspects of the Crosstalk flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_wcr_u { - bdrkreg_t ii_wcr_regval; - struct { - bdrkreg_t w_wid : 4; - bdrkreg_t w_tag : 1; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_dst_crd : 3; - bdrkreg_t w_f_bad_pkt : 1; - bdrkreg_t w_dir_con : 1; - bdrkreg_t w_e_thresh : 5; - bdrkreg_t w_rsvd : 41; - } ii_wcr_fld_s; -} ii_wcr_u_t; - -#else - -typedef union ii_wcr_u { - bdrkreg_t ii_wcr_regval; - struct { - bdrkreg_t w_rsvd : 41; - bdrkreg_t w_e_thresh : 5; - bdrkreg_t w_dir_con : 1; - bdrkreg_t w_f_bad_pkt : 1; - bdrkreg_t w_dst_crd : 3; - bdrkreg_t w_rsvd_1 : 8; - bdrkreg_t w_tag : 1; - bdrkreg_t w_wid : 4; - } ii_wcr_fld_s; -} ii_wcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register's value is a bit vector that guards * - * access to local registers within the II as well as to external * - * Crosstalk widgets. Each bit in the register corresponds to a * - * particular region in the system; a region consists of one, two or * - * four nodes (depending on the value of the REGION_SIZE field in the * - * LB_REV_ID register, which is documented in Section 8.3.1.1). The * - * protection provided by this register applies to PIO read * - * operations as well as PIO write operations. The II will perform a * - * PIO read or write request only if the bit for the requestor's * - * region is set; otherwise, the II will not perform the requested * - * operation and will return an error response. When a PIO read or * - * write request targets an external Crosstalk widget, then not only * - * must the bit for the requestor's region be set in the ILAPR, but * - * also the target widget's bit in the IOWA register must be set in * - * order for the II to perform the requested operation; otherwise, * - * the II will return an error response. Hence, the protection * - * provided by the IOWA register supplements the protection provided * - * by the ILAPR for requests that target external Crosstalk widgets. * - * This register itself can be accessed only by the nodes whose * - * region ID bits are enabled in this same register. It can also be * - * accessed through the IAlias space by the local processors. * - * The reset value of this register allows access by all nodes. * - * * - ************************************************************************/ - - - - -typedef union ii_ilapr_u { - bdrkreg_t ii_ilapr_regval; - struct { - bdrkreg_t i_region : 64; - } ii_ilapr_fld_s; -} ii_ilapr_u_t; - - - - -/************************************************************************ - * * - * Description: A write to this register of the 64-bit value * - * "SGIrules" in ASCII, will cause the bit in the ILAPR register * - * corresponding to the region of the requestor to be set (allow * - * access). A write of any other value will be ignored. Access * - * protection for this register is "SGIrules". * - * This register can also be accessed through the IAlias space. * - * However, this access will not change the access permissions in the * - * ILAPR. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilapo_u { - bdrkreg_t ii_ilapo_regval; - struct { - bdrkreg_t i_io_ovrride : 9; - bdrkreg_t i_rsvd : 55; - } ii_ilapo_fld_s; -} ii_ilapo_u_t; - -#else - -typedef union ii_ilapo_u { - bdrkreg_t ii_ilapo_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_io_ovrride : 9; - } ii_ilapo_fld_s; -} ii_ilapo_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register qualifies all the PIO and Graphics writes launched * - * from the Bedrock towards a widget. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iowa_u { - bdrkreg_t ii_iowa_regval; - struct { - bdrkreg_t i_w0_oac : 1; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_wx_oac : 8; - bdrkreg_t i_rsvd : 48; - } ii_iowa_fld_s; -} ii_iowa_u_t; - -#else - -typedef union ii_iowa_u { - bdrkreg_t ii_iowa_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_wx_oac : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_w0_oac : 1; - } ii_iowa_fld_s; -} ii_iowa_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register qualifies all the requests launched * - * from a widget towards the Bedrock. This register is intended to be * - * used by software in case of misbehaving widgets. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iiwa_u { - bdrkreg_t ii_iiwa_regval; - struct { - bdrkreg_t i_w0_iac : 1; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_wx_iac : 8; - bdrkreg_t i_rsvd : 48; - } ii_iiwa_fld_s; -} ii_iiwa_u_t; - -#else - -typedef union ii_iiwa_u { - bdrkreg_t ii_iiwa_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_wx_iac : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_w0_iac : 1; - } ii_iiwa_fld_s; -} ii_iiwa_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register qualifies all the operations launched * - * from a widget towards the Bedrock. It allows individual access * - * control for up to 8 devices per widget. A device refers to * - * individual DMA master hosted by a widget. * - * The bits in each field of this register are cleared by the Bedrock * - * upon detection of an error which requires the device to be * - * disabled. These fields assume that 0=TNUM=7 (i.e., Bridge-centric * - * Crosstalk). Whether or not a device has access rights to this * - * Bedrock is determined by an AND of the device enable bit in the * - * appropriate field of this register and the corresponding bit in * - * the Wx_IAC field (for the widget which this device belongs to). * - * The bits in this field are set by writing a 1 to them. Incoming * - * replies from Crosstalk are not subject to this access control * - * mechanism. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iidem_u { - bdrkreg_t ii_iidem_regval; - struct { - bdrkreg_t i_w8_dxs : 8; - bdrkreg_t i_w9_dxs : 8; - bdrkreg_t i_wa_dxs : 8; - bdrkreg_t i_wb_dxs : 8; - bdrkreg_t i_wc_dxs : 8; - bdrkreg_t i_wd_dxs : 8; - bdrkreg_t i_we_dxs : 8; - bdrkreg_t i_wf_dxs : 8; - } ii_iidem_fld_s; -} ii_iidem_u_t; - -#else - -typedef union ii_iidem_u { - bdrkreg_t ii_iidem_regval; - struct { - bdrkreg_t i_wf_dxs : 8; - bdrkreg_t i_we_dxs : 8; - bdrkreg_t i_wd_dxs : 8; - bdrkreg_t i_wc_dxs : 8; - bdrkreg_t i_wb_dxs : 8; - bdrkreg_t i_wa_dxs : 8; - bdrkreg_t i_w9_dxs : 8; - bdrkreg_t i_w8_dxs : 8; - } ii_iidem_fld_s; -} ii_iidem_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the various programmable fields necessary * - * for controlling and observing the LLP signals. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilcsr_u { - bdrkreg_t ii_ilcsr_regval; - struct { - bdrkreg_t i_nullto : 6; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_wrmrst : 1; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_llp_en : 1; - bdrkreg_t i_bm8 : 1; - bdrkreg_t i_llp_stat : 2; - bdrkreg_t i_remote_power : 1; - bdrkreg_t i_rsvd_2 : 1; - bdrkreg_t i_maxrtry : 10; - bdrkreg_t i_d_avail_sel : 2; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_maxbrst : 10; - bdrkreg_t i_rsvd : 22; - - } ii_ilcsr_fld_s; -} ii_ilcsr_u_t; - -#else - -typedef union ii_ilcsr_u { - bdrkreg_t ii_ilcsr_regval; - struct { - bdrkreg_t i_rsvd : 22; - bdrkreg_t i_maxbrst : 10; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_d_avail_sel : 2; - bdrkreg_t i_maxrtry : 10; - bdrkreg_t i_rsvd_2 : 1; - bdrkreg_t i_remote_power : 1; - bdrkreg_t i_llp_stat : 2; - bdrkreg_t i_bm8 : 1; - bdrkreg_t i_llp_en : 1; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_wrmrst : 1; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_nullto : 6; - } ii_ilcsr_fld_s; -} ii_ilcsr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This is simply a status registers that monitors the LLP error * - * rate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_illr_u { - bdrkreg_t ii_illr_regval; - struct { - bdrkreg_t i_sn_cnt : 16; - bdrkreg_t i_cb_cnt : 16; - bdrkreg_t i_rsvd : 32; - } ii_illr_fld_s; -} ii_illr_u_t; - -#else - -typedef union ii_illr_u { - bdrkreg_t ii_illr_regval; - struct { - bdrkreg_t i_rsvd : 32; - bdrkreg_t i_cb_cnt : 16; - bdrkreg_t i_sn_cnt : 16; - } ii_illr_fld_s; -} ii_illr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: All II-detected non-BTE error interrupts are * - * specified via this register. * - * NOTE: The PI interrupt register address is hardcoded in the II. If * - * PI_ID==0, then the II sends an interrupt request (Duplonet PWRI * - * packet) to address offset 0x0180_0090 within the local register * - * address space of PI0 on the node specified by the NODE field. If * - * PI_ID==1, then the II sends the interrupt request to address * - * offset 0x01A0_0090 within the local register address space of PI1 * - * on the node specified by the NODE field. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iidsr_u { - bdrkreg_t ii_iidsr_regval; - struct { - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node : 8; - bdrkreg_t i_rsvd_3 : 7; - bdrkreg_t i_enable : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_int_sent : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_rsvd : 30; - } ii_iidsr_fld_s; -} ii_iidsr_u_t; - -#else - -typedef union ii_iidsr_u { - bdrkreg_t ii_iidsr_regval; - struct { - bdrkreg_t i_rsvd : 30; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_int_sent : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_enable : 1; - bdrkreg_t i_rsvd_3 : 7; - bdrkreg_t i_node : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_level : 7; - } ii_iidsr_fld_s; -} ii_iidsr_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_igfx0_u { - bdrkreg_t ii_igfx0_regval; - struct { - bdrkreg_t i_w_num : 4; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd : 47; - } ii_igfx0_fld_s; -} ii_igfx0_u_t; - -#else - -typedef union ii_igfx0_u { - bdrkreg_t ii_igfx0_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_w_num : 4; - } ii_igfx0_fld_s; -} ii_igfx0_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this register. This register is used * - * for matching up the incoming responses from the graphics widget to * - * the processor that initiated the graphics operation. The * - * write-responses are converted to graphics credits and returned to * - * the processor so that the processor interface can manage the flow * - * control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_igfx1_u { - bdrkreg_t ii_igfx1_regval; - struct { - bdrkreg_t i_w_num : 4; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd : 47; - } ii_igfx1_fld_s; -} ii_igfx1_u_t; - -#else - -typedef union ii_igfx1_u { - bdrkreg_t ii_igfx1_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_p_num : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_n_num : 8; - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_w_num : 4; - } ii_igfx1_fld_s; -} ii_igfx1_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - - - - -typedef union ii_iscr0_u { - bdrkreg_t ii_iscr0_regval; - struct { - bdrkreg_t i_scratch : 64; - } ii_iscr0_fld_s; -} ii_iscr0_u_t; - - - - -/************************************************************************ - * * - * There are two instances of this registers. These registers are * - * used as scratch registers for software use. * - * * - ************************************************************************/ - - - - -typedef union ii_iscr1_u { - bdrkreg_t ii_iscr1_regval; - struct { - bdrkreg_t i_scratch : 64; - } ii_iscr1_fld_s; -} ii_iscr1_u_t; - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte1_u { - bdrkreg_t ii_itte1_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte1_fld_s; -} ii_itte1_u_t; - -#else - -typedef union ii_itte1_u { - bdrkreg_t ii_itte1_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte1_fld_s; -} ii_itte1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte2_u { - bdrkreg_t ii_itte2_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte2_fld_s; -} ii_itte2_u_t; - -#else -typedef union ii_itte2_u { - bdrkreg_t ii_itte2_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte2_fld_s; -} ii_itte2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte3_u { - bdrkreg_t ii_itte3_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte3_fld_s; -} ii_itte3_u_t; - -#else - -typedef union ii_itte3_u { - bdrkreg_t ii_itte3_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte3_fld_s; -} ii_itte3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte4_u { - bdrkreg_t ii_itte4_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte4_fld_s; -} ii_itte4_u_t; - -#else - -typedef union ii_itte4_u { - bdrkreg_t ii_itte4_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte4_fld_s; -} ii_itte4_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte5_u { - bdrkreg_t ii_itte5_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte5_fld_s; -} ii_itte5_u_t; - -#else - -typedef union ii_itte5_u { - bdrkreg_t ii_itte5_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte5_fld_s; -} ii_itte5_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte6_u { - bdrkreg_t ii_itte6_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte6_fld_s; -} ii_itte6_u_t; - -#else - -typedef union ii_itte6_u { - bdrkreg_t ii_itte6_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte6_fld_s; -} ii_itte6_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are seven instances of translation table entry * - * registers. Each register maps a Bedrock Big Window to a 48-bit * - * address on Crosstalk. * - * For M-mode (128 nodes, 8 GBytes/node), SysAD[31:29] (Big Window * - * number) are used to select one of these 7 registers. The Widget * - * number field is then derived from the W_NUM field for synthesizing * - * a Crosstalk packet. The 5 bits of OFFSET are concatenated with * - * SysAD[28:0] to form Crosstalk[33:0]. The upper Crosstalk[47:34] * - * are padded with zeros. Although the maximum Crosstalk space * - * addressable by the Bedrock is thus the lower 16 GBytes per widget * - * (M-mode), however only 7/32nds of this * - * space can be accessed. * - * For the N-mode (256 nodes, 4 GBytes/node), SysAD[30:28] (Big * - * Window number) are used to select one of these 7 registers. The * - * Widget number field is then derived from the W_NUM field for * - * synthesizing a Crosstalk packet. The 5 bits of OFFSET are * - * concatenated with SysAD[27:0] to form Crosstalk[33:0]. The IOSP * - * field is used as Crosstalk[47], and remainder of the Crosstalk * - * address bits (Crosstalk[46:34]) are always zero. While the maximum * - * Crosstalk space addressable by the Bedrock is thus the lower * - * 8-GBytes per widget (N-mode), only 7/32nds * - * of this space can be accessed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_itte7_u { - bdrkreg_t ii_itte7_regval; - struct { - bdrkreg_t i_offset : 5; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_rsvd : 51; - } ii_itte7_fld_s; -} ii_itte7_u_t; - -#else - -typedef union ii_itte7_u { - bdrkreg_t ii_itte7_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_iosp : 1; - bdrkreg_t i_w_num : 4; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_offset : 5; - } ii_itte7_fld_s; -} ii_itte7_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb0_u { - bdrkreg_t ii_iprb0_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb0_fld_s; -} ii_iprb0_u_t; - -#else - -typedef union ii_iprb0_u { - bdrkreg_t ii_iprb0_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb0_fld_s; -} ii_iprb0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb8_u { - bdrkreg_t ii_iprb8_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb8_fld_s; -} ii_iprb8_u_t; - -#else - - -typedef union ii_iprb8_u { - bdrkreg_t ii_iprb8_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb8_fld_s; -} ii_iprb8_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprb9_u { - bdrkreg_t ii_iprb9_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprb9_fld_s; -} ii_iprb9_u_t; - -#else - -typedef union ii_iprb9_u { - bdrkreg_t ii_iprb9_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprb9_fld_s; -} ii_iprb9_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprba_u { - bdrkreg_t ii_iprba_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprba_fld_s; -} ii_iprba_u_t; - -#else - -typedef union ii_iprba_u { - bdrkreg_t ii_iprba_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprba_fld_s; -} ii_iprba_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbb_u { - bdrkreg_t ii_iprbb_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbb_fld_s; -} ii_iprbb_u_t; - -#else - -typedef union ii_iprbb_u { - bdrkreg_t ii_iprbb_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbb_fld_s; -} ii_iprbb_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbc_u { - bdrkreg_t ii_iprbc_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbc_fld_s; -} ii_iprbc_u_t; - -#else - -typedef union ii_iprbc_u { - bdrkreg_t ii_iprbc_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbc_fld_s; -} ii_iprbc_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbd_u { - bdrkreg_t ii_iprbd_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbd_fld_s; -} ii_iprbd_u_t; - -#else - -typedef union ii_iprbd_u { - bdrkreg_t ii_iprbd_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbd_fld_s; -} ii_iprbd_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbe_u { - bdrkreg_t ii_iprbe_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbe_fld_s; -} ii_iprbe_u_t; - -#else - -typedef union ii_iprbe_u { - bdrkreg_t ii_iprbe_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbe_fld_s; -} ii_iprbe_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 9 instances of this register, one per * - * actual widget in this implementation of Bedrock and Crossbow. * - * Note: Crossbow only has ports for Widgets 8 through F, widget 0 * - * refers to Crossbow's internal space. * - * This register contains the state elements per widget that are * - * necessary to manage the PIO flow control on Crosstalk and on the * - * Router Network. See the PIO Flow Control chapter for a complete * - * description of this register * - * The SPUR_WR bit requires some explanation. When this register is * - * written, the new value of the C field is captured in an internal * - * register so the hardware can remember what the programmer wrote * - * into the credit counter. The SPUR_WR bit sets whenever the C field * - * increments above this stored value, which indicates that there * - * have been more responses received than requests sent. The SPUR_WR * - * bit cannot be cleared until a value is written to the IPRBx * - * register; the write will correct the C field and capture its new * - * value in the internal register. Even if IECLR[E_PRB_x] is set, the * - * SPUR_WR bit will persist if IPRBx hasn't yet been written. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprbf_u { - bdrkreg_t ii_iprbf_regval; - struct { - bdrkreg_t i_c : 8; - bdrkreg_t i_na : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_m : 2; - bdrkreg_t i_f : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_error : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_mult_err : 1; - } ii_iprbe_fld_s; -} ii_iprbf_u_t; - -#else - -typedef union ii_iprbf_u { - bdrkreg_t ii_iprbf_regval; - struct { - bdrkreg_t i_mult_err : 1; - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_spur_rd : 1; - bdrkreg_t i_spur_wr : 1; - bdrkreg_t i_rd_to : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_of_cnt : 5; - bdrkreg_t i_f : 1; - bdrkreg_t i_m : 2; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_nb : 14; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_na : 14; - bdrkreg_t i_c : 8; - } ii_iprbf_fld_s; -} ii_iprbf_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register specifies the timeout value to use for monitoring * - * Crosstalk credits which are used outbound to Crosstalk. An * - * internal counter called the Crosstalk Credit Timeout Counter * - * increments every 128 II clocks. The counter starts counting * - * anytime the credit count drops below a threshold, and resets to * - * zero (stops counting) anytime the credit count is at or above the * - * threshold. The threshold is 1 credit in direct connect mode and 2 * - * in Crossbow connect mode. When the internal Crosstalk Credit * - * Timeout Counter reaches the value programmed in this register, a * - * Crosstalk Credit Timeout has occurred. The internal counter is not * - * readable from software, and stops counting at its maximum value, * - * so it cannot cause more than one interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixcc_u { - bdrkreg_t ii_ixcc_regval; - struct { - bdrkreg_t i_time_out : 26; - bdrkreg_t i_rsvd : 38; - } ii_ixcc_fld_s; -} ii_ixcc_u_t; - -#else - -typedef union ii_ixcc_u { - bdrkreg_t ii_ixcc_regval; - struct { - bdrkreg_t i_rsvd : 38; - bdrkreg_t i_time_out : 26; - } ii_ixcc_fld_s; -} ii_ixcc_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: This register qualifies all the PIO and DMA * - * operations launched from widget 0 towards the Bedrock. In * - * addition, it also qualifies accesses by the BTE streams. * - * The bits in each field of this register are cleared by the Bedrock * - * upon detection of an error which requires widget 0 or the BTE * - * streams to be terminated. Whether or not widget x has access * - * rights to this Bedrock is determined by an AND of the device * - * enable bit in the appropriate field of this register and bit 0 in * - * the Wx_IAC field. The bits in this field are set by writing a 1 to * - * them. Incoming replies from Crosstalk are not subject to this * - * access control mechanism. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_imem_u { - bdrkreg_t ii_imem_regval; - struct { - bdrkreg_t i_w0_esd : 1; - bdrkreg_t i_rsvd_3 : 3; - bdrkreg_t i_b0_esd : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_b1_esd : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_clr_precise : 1; - bdrkreg_t i_rsvd : 51; - } ii_imem_fld_s; -} ii_imem_u_t; - -#else - -typedef union ii_imem_u { - bdrkreg_t ii_imem_regval; - struct { - bdrkreg_t i_rsvd : 51; - bdrkreg_t i_clr_precise : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_b1_esd : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_b0_esd : 1; - bdrkreg_t i_rsvd_3 : 3; - bdrkreg_t i_w0_esd : 1; - } ii_imem_fld_s; -} ii_imem_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register specifies the timeout value to use for * - * monitoring Crosstalk tail flits coming into the Bedrock in the * - * TAIL_TO field. An internal counter associated with this register * - * is incremented every 128 II internal clocks (7 bits). The counter * - * starts counting anytime a header micropacket is received and stops * - * counting (and resets to zero) any time a micropacket with a Tail * - * bit is received. Once the counter reaches the threshold value * - * programmed in this register, it generates an interrupt to the * - * processor that is programmed into the IIDSR. The counter saturates * - * (does not roll over) at its maximum value, so it cannot cause * - * another interrupt until after it is cleared. * - * The register also contains the Read Response Timeout values. The * - * Prescalar is 23 bits, and counts II clocks. An internal counter * - * increments on every II clock and when it reaches the value in the * - * Prescalar field, all IPRTE registers with their valid bits set * - * have their Read Response timers bumped. Whenever any of them match * - * the value in the RRSP_TO field, a Read Response Timeout has * - * occurred, and error handling occurs as described in the Error * - * Handling section of this document. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixtt_u { - bdrkreg_t ii_ixtt_regval; - struct { - bdrkreg_t i_tail_to : 26; - bdrkreg_t i_rsvd_1 : 6; - bdrkreg_t i_rrsp_ps : 23; - bdrkreg_t i_rrsp_to : 5; - bdrkreg_t i_rsvd : 4; - } ii_ixtt_fld_s; -} ii_ixtt_u_t; - -#else - -typedef union ii_ixtt_u { - bdrkreg_t ii_ixtt_regval; - struct { - bdrkreg_t i_rsvd : 4; - bdrkreg_t i_rrsp_to : 5; - bdrkreg_t i_rrsp_ps : 23; - bdrkreg_t i_rsvd_1 : 6; - bdrkreg_t i_tail_to : 26; - } ii_ixtt_fld_s; -} ii_ixtt_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing a 1 to the fields of this register clears the appropriate * - * error bits in other areas of Bedrock_II. Note that when the * - * E_PRB_x bits are used to clear error bits in PRB registers, * - * SPUR_RD and SPUR_WR may persist, because they require additional * - * action to clear them. See the IPRBx and IXSS Register * - * specifications. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ieclr_u { - bdrkreg_t ii_ieclr_regval; - struct { - bdrkreg_t i_e_prb_0 : 1; - bdrkreg_t i_rsvd : 7; - bdrkreg_t i_e_prb_8 : 1; - bdrkreg_t i_e_prb_9 : 1; - bdrkreg_t i_e_prb_a : 1; - bdrkreg_t i_e_prb_b : 1; - bdrkreg_t i_e_prb_c : 1; - bdrkreg_t i_e_prb_d : 1; - bdrkreg_t i_e_prb_e : 1; - bdrkreg_t i_e_prb_f : 1; - bdrkreg_t i_e_crazy : 1; - bdrkreg_t i_e_bte_0 : 1; - bdrkreg_t i_e_bte_1 : 1; - bdrkreg_t i_reserved_1 : 9; - bdrkreg_t i_ii_internal : 1; - bdrkreg_t i_spur_rd_hdr : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_reserved : 32; - } ii_ieclr_fld_s; -} ii_ieclr_u_t; - -#else - -typedef union ii_ieclr_u { - bdrkreg_t ii_ieclr_regval; - struct { - bdrkreg_t i_reserved : 32; - bdrkreg_t i_pi1_forward_int : 1; - bdrkreg_t i_pi0_forward_int : 1; - bdrkreg_t i_spur_rd_hdr : 1; - bdrkreg_t i_ii_internal : 1; - bdrkreg_t i_reserved_1 : 9; - bdrkreg_t i_e_bte_1 : 1; - bdrkreg_t i_e_bte_0 : 1; - bdrkreg_t i_e_crazy : 1; - bdrkreg_t i_e_prb_f : 1; - bdrkreg_t i_e_prb_e : 1; - bdrkreg_t i_e_prb_d : 1; - bdrkreg_t i_e_prb_c : 1; - bdrkreg_t i_e_prb_b : 1; - bdrkreg_t i_e_prb_a : 1; - bdrkreg_t i_e_prb_9 : 1; - bdrkreg_t i_e_prb_8 : 1; - bdrkreg_t i_rsvd : 7; - bdrkreg_t i_e_prb_0 : 1; - } ii_ieclr_fld_s; -} ii_ieclr_u_t; - -#endif - - - - - -/************************************************************************ - * * - * This register controls both BTEs. SOFT_RESET is intended for * - * recovery after an error. COUNT controls the total number of CRBs * - * that both BTEs (combined) can use, which affects total BTE * - * bandwidth. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibcr_u { - bdrkreg_t ii_ibcr_regval; - struct { - bdrkreg_t i_count : 4; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_soft_reset : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibcr_fld_s; -} ii_ibcr_u_t; - -#else - -typedef union ii_ibcr_u { - bdrkreg_t ii_ibcr_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_soft_reset : 1; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_count : 4; - } ii_ibcr_fld_s; -} ii_ibcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the header of a spurious read response * - * received from Crosstalk. A spurious read response is defined as a * - * read response received by II from a widget for which (1) the SIDN * - * has a value between 1 and 7, inclusive (II never sends requests to * - * these widgets (2) there is no valid IPRTE register which * - * corresponds to the TNUM, or (3) the widget indicated in SIDN is * - * not the same as the widget recorded in the IPRTE register * - * referenced by the TNUM. If this condition is true, and if the * - * IXSS[VALID] bit is clear, then the header of the spurious read * - * response is capture in IXSM and IXSS, and IXSS[VALID] is set. The * - * errant header is thereby captured, and no further spurious read * - * respones are captured until IXSS[VALID] is cleared by setting the * - * appropriate bit in IECLR.Everytime a spurious read response is * - * detected, the SPUR_RD bit of the PRB corresponding to the incoming * - * message's SIDN field is set. This always happens, regarless of * - * whether a header is captured. The programmer should check * - * IXSM[SIDN] to determine which widget sent the spurious response, * - * because there may be more than one SPUR_RD bit set in the PRB * - * registers. The widget indicated by IXSM[SIDN] was the first * - * spurious read response to be received since the last time * - * IXSS[VALID] was clear. The SPUR_RD bit of the corresponding PRB * - * will be set. Any SPUR_RD bits in any other PRB registers indicate * - * spurious messages from other widets which were detected after the * - * header was captured.. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixsm_u { - bdrkreg_t ii_ixsm_regval; - struct { - bdrkreg_t i_byte_en : 32; - bdrkreg_t i_reserved : 1; - bdrkreg_t i_tag : 3; - bdrkreg_t i_alt_pactyp : 4; - bdrkreg_t i_bo : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_vbpm : 1; - bdrkreg_t i_gbr : 1; - bdrkreg_t i_ds : 2; - bdrkreg_t i_ct : 1; - bdrkreg_t i_tnum : 5; - bdrkreg_t i_pactyp : 4; - bdrkreg_t i_sidn : 4; - bdrkreg_t i_didn : 4; - } ii_ixsm_fld_s; -} ii_ixsm_u_t; - -#else - -typedef union ii_ixsm_u { - bdrkreg_t ii_ixsm_regval; - struct { - bdrkreg_t i_didn : 4; - bdrkreg_t i_sidn : 4; - bdrkreg_t i_pactyp : 4; - bdrkreg_t i_tnum : 5; - bdrkreg_t i_ct : 1; - bdrkreg_t i_ds : 2; - bdrkreg_t i_gbr : 1; - bdrkreg_t i_vbpm : 1; - bdrkreg_t i_error : 1; - bdrkreg_t i_bo : 1; - bdrkreg_t i_alt_pactyp : 4; - bdrkreg_t i_tag : 3; - bdrkreg_t i_reserved : 1; - bdrkreg_t i_byte_en : 32; - } ii_ixsm_fld_s; -} ii_ixsm_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the sideband bits of a spurious read * - * response received from Crosstalk. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ixss_u { - bdrkreg_t ii_ixss_regval; - struct { - bdrkreg_t i_sideband : 8; - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_valid : 1; - } ii_ixss_fld_s; -} ii_ixss_u_t; - -#else - -typedef union ii_ixss_u { - bdrkreg_t ii_ixss_regval; - struct { - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_sideband : 8; - } ii_ixss_fld_s; -} ii_ixss_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register enables software to access the II LLP's test port. * - * Refer to the LLP 2.5 documentation for an explanation of the test * - * port. Software can write to this register to program the values * - * for the control fields (TestErrCapture, TestClear, TestFlit, * - * TestMask and TestSeed). Similarly, software can read from this * - * register to obtain the values of the test port's status outputs * - * (TestCBerr, TestValid and TestData). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ilct_u { - bdrkreg_t ii_ilct_regval; - struct { - bdrkreg_t i_test_seed : 20; - bdrkreg_t i_test_mask : 8; - bdrkreg_t i_test_data : 20; - bdrkreg_t i_test_valid : 1; - bdrkreg_t i_test_cberr : 1; - bdrkreg_t i_test_flit : 3; - bdrkreg_t i_test_clear : 1; - bdrkreg_t i_test_err_capture : 1; - bdrkreg_t i_rsvd : 9; - } ii_ilct_fld_s; -} ii_ilct_u_t; - -#else - -typedef union ii_ilct_u { - bdrkreg_t ii_ilct_regval; - struct { - bdrkreg_t i_rsvd : 9; - bdrkreg_t i_test_err_capture : 1; - bdrkreg_t i_test_clear : 1; - bdrkreg_t i_test_flit : 3; - bdrkreg_t i_test_cberr : 1; - bdrkreg_t i_test_valid : 1; - bdrkreg_t i_test_data : 20; - bdrkreg_t i_test_mask : 8; - bdrkreg_t i_test_seed : 20; - } ii_ilct_fld_s; -} ii_ilct_u_t; - -#endif - - - - -/************************************************************************ - * * - * If the II detects an illegal incoming Duplonet packet (request or * - * reply) when VALID==0 in the IIEPH1 register, then it saves the * - * contents of the packet's header flit in the IIEPH1 and IIEPH2 * - * registers, sets the VALID bit in IIEPH1, clears the OVERRUN bit, * - * and assigns a value to the ERR_TYPE field which indicates the * - * specific nature of the error. The II recognizes four different * - * types of errors: short request packets (ERR_TYPE==2), short reply * - * packets (ERR_TYPE==3), long request packets (ERR_TYPE==4) and long * - * reply packets (ERR_TYPE==5). The encodings for these types of * - * errors were chosen to be consistent with the same types of errors * - * indicated by the ERR_TYPE field in the LB_ERROR_HDR1 register (in * - * the LB unit). If the II detects an illegal incoming Duplonet * - * packet when VALID==1 in the IIEPH1 register, then it merely sets * - * the OVERRUN bit to indicate that a subsequent error has happened, * - * and does nothing further. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iieph1_u { - bdrkreg_t ii_iieph1_regval; - struct { - bdrkreg_t i_command : 7; - bdrkreg_t i_rsvd_5 : 1; - bdrkreg_t i_suppl : 11; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_source : 11; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_err_type : 4; - bdrkreg_t i_rsvd_2 : 4; - bdrkreg_t i_overrun : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd : 19; - } ii_iieph1_fld_s; -} ii_iieph1_u_t; - -#else - -typedef union ii_iieph1_u { - bdrkreg_t ii_iieph1_regval; - struct { - bdrkreg_t i_rsvd : 19; - bdrkreg_t i_valid : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_overrun : 1; - bdrkreg_t i_rsvd_2 : 4; - bdrkreg_t i_err_type : 4; - bdrkreg_t i_rsvd_3 : 1; - bdrkreg_t i_source : 11; - bdrkreg_t i_rsvd_4 : 1; - bdrkreg_t i_suppl : 11; - bdrkreg_t i_rsvd_5 : 1; - bdrkreg_t i_command : 7; - } ii_iieph1_fld_s; -} ii_iieph1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register holds the Address field from the header flit of an * - * incoming erroneous Duplonet packet, along with the tail bit which * - * accompanied this header flit. This register is essentially an * - * extension of IIEPH1. Two registers were necessary because the 64 * - * bits available in only a single register were insufficient to * - * capture the entire header flit of an erroneous packet. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iieph2_u { - bdrkreg_t ii_iieph2_regval; - struct { - bdrkreg_t i_address : 38; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_tail : 1; - bdrkreg_t i_rsvd : 23; - } ii_iieph2_fld_s; -} ii_iieph2_u_t; - -#else - -typedef union ii_iieph2_u { - bdrkreg_t ii_iieph2_regval; - struct { - bdrkreg_t i_rsvd : 23; - bdrkreg_t i_tail : 1; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_address : 38; - } ii_iieph2_fld_s; -} ii_iieph2_u_t; - -#endif - - - - -/************************************************************************ - * * - * A write to this register causes a particular field in the * - * corresponding widget's PRB entry to be adjusted up or down by 1. * - * This counter should be used when recovering from error and reset * - * conditions. Note that software would be capable of causing * - * inadvertent overflow or underflow of these counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipca_u { - bdrkreg_t ii_ipca_regval; - struct { - bdrkreg_t i_wid : 4; - bdrkreg_t i_adjust : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_field : 2; - bdrkreg_t i_rsvd : 54; - } ii_ipca_fld_s; -} ii_ipca_u_t; - -#else - -typedef union ii_ipca_u { - bdrkreg_t ii_ipca_regval; - struct { - bdrkreg_t i_rsvd : 54; - bdrkreg_t i_field : 2; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_adjust : 1; - bdrkreg_t i_wid : 4; - } ii_ipca_fld_s; -} ii_ipca_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte0_u { - bdrkreg_t ii_iprte0_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte0_fld_s; -} ii_iprte0_u_t; - -#else - -typedef union ii_iprte0_u { - bdrkreg_t ii_iprte0_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte0_fld_s; -} ii_iprte0_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte1_u { - bdrkreg_t ii_iprte1_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte1_fld_s; -} ii_iprte1_u_t; - -#else - -typedef union ii_iprte1_u { - bdrkreg_t ii_iprte1_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte1_fld_s; -} ii_iprte1_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte2_u { - bdrkreg_t ii_iprte2_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte2_fld_s; -} ii_iprte2_u_t; - -#else - -typedef union ii_iprte2_u { - bdrkreg_t ii_iprte2_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte2_fld_s; -} ii_iprte2_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte3_u { - bdrkreg_t ii_iprte3_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte3_fld_s; -} ii_iprte3_u_t; - -#else - -typedef union ii_iprte3_u { - bdrkreg_t ii_iprte3_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte3_fld_s; -} ii_iprte3_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte4_u { - bdrkreg_t ii_iprte4_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte4_fld_s; -} ii_iprte4_u_t; - -#else - -typedef union ii_iprte4_u { - bdrkreg_t ii_iprte4_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte4_fld_s; -} ii_iprte4_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte5_u { - bdrkreg_t ii_iprte5_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte5_fld_s; -} ii_iprte5_u_t; - -#else - -typedef union ii_iprte5_u { - bdrkreg_t ii_iprte5_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte5_fld_s; -} ii_iprte5_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte6_u { - bdrkreg_t ii_iprte6_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte6_fld_s; -} ii_iprte6_u_t; - -#else - -typedef union ii_iprte6_u { - bdrkreg_t ii_iprte6_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte6_fld_s; -} ii_iprte6_u_t; - -#endif - - - - -/************************************************************************ - * * - * There are 8 instances of this register. This register contains * - * the information that the II has to remember once it has launched a * - * PIO Read operation. The contents are used to form the correct * - * Router Network packet and direct the Crosstalk reply to the * - * appropriate processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iprte7_u { - bdrkreg_t ii_iprte7_regval; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } ii_iprte7_fld_s; -} ii_iprte7_u_t; - -#else - -typedef union ii_iprte7_u { - bdrkreg_t ii_iprte7_regval; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } ii_iprte7_fld_s; -} ii_iprte7_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Bedrock_II contains a feature which did not exist in * - * the Hub which automatically cleans up after a Read Response * - * timeout, including deallocation of the IPRTE and recovery of IBuf * - * space. The inclusion of this register in Bedrock is for backward * - * compatibility * - * A write to this register causes an entry from the table of * - * outstanding PIO Read Requests to be freed and returned to the * - * stack of free entries. This register is used in handling the * - * timeout errors that result in a PIO Reply never returning from * - * Crosstalk. * - * Note that this register does not affect the contents of the IPRTE * - * registers. The Valid bits in those registers have to be * - * specifically turned off by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipdr_u { - bdrkreg_t ii_ipdr_regval; - struct { - bdrkreg_t i_te : 3; - bdrkreg_t i_rsvd_1 : 1; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_init_rpcnt : 1; - bdrkreg_t i_rsvd : 58; - } ii_ipdr_fld_s; -} ii_ipdr_u_t; - -#else - -typedef union ii_ipdr_u { - bdrkreg_t ii_ipdr_regval; - struct { - bdrkreg_t i_rsvd : 58; - bdrkreg_t i_init_rpcnt : 1; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_rsvd_1 : 1; - bdrkreg_t i_te : 3; - } ii_ipdr_fld_s; -} ii_ipdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * A write to this register causes a CRB entry to be returned to the * - * queue of free CRBs. The entry should have previously been cleared * - * (mark bit) via backdoor access to the pertinent CRB entry. This * - * register is used in the last step of handling the errors that are * - * captured and marked in CRB entries. Briefly: 1) first error for * - * DMA write from a particular device, and first error for a * - * particular BTE stream, lead to a marked CRB entry, and processor * - * interrupt, 2) software reads the error information captured in the * - * CRB entry, and presumably takes some corrective action, 3) * - * software clears the mark bit, and finally 4) software writes to * - * the ICDR register to return the CRB entry to the list of free CRB * - * entries. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icdr_u { - bdrkreg_t ii_icdr_regval; - struct { - bdrkreg_t i_crb_num : 4; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_rsvd : 59; - } ii_icdr_fld_s; -} ii_icdr_u_t; - -#else - -typedef union ii_icdr_u { - bdrkreg_t ii_icdr_regval; - struct { - bdrkreg_t i_rsvd : 59; - bdrkreg_t i_pnd : 1; - bdrkreg_t i_crb_num : 4; - } ii_icdr_fld_s; -} ii_icdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides debug access to two FIFOs inside of II. * - * Both IOQ_MAX* fields of this register contain the instantaneous * - * depth (in units of the number of available entries) of the * - * associated IOQ FIFO. A read of this register will return the * - * number of free entries on each FIFO at the time of the read. So * - * when a FIFO is idle, the associated field contains the maximum * - * depth of the FIFO. This register is writable for debug reasons * - * and is intended to be written with the maximum desired FIFO depth * - * while the FIFO is idle. Software must assure that II is idle when * - * this register is written. If there are any active entries in any * - * of these FIFOs when this register is written, the results are * - * undefined. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ifdr_u { - bdrkreg_t ii_ifdr_regval; - struct { - bdrkreg_t i_ioq_max_rq : 7; - bdrkreg_t i_set_ioq_rq : 1; - bdrkreg_t i_ioq_max_rp : 7; - bdrkreg_t i_set_ioq_rp : 1; - bdrkreg_t i_rsvd : 48; - } ii_ifdr_fld_s; -} ii_ifdr_u_t; - -#else - -typedef union ii_ifdr_u { - bdrkreg_t ii_ifdr_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_set_ioq_rp : 1; - bdrkreg_t i_ioq_max_rp : 7; - bdrkreg_t i_set_ioq_rq : 1; - bdrkreg_t i_ioq_max_rq : 7; - } ii_ifdr_fld_s; -} ii_ifdr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the II to become sluggish in removing * - * messages from its inbound queue (IIQ). This will cause messages to * - * back up in either virtual channel. Disabling the "molasses" mode * - * subsequently allows the II to be tested under stress. In the * - * sluggish ("Molasses") mode, the localized effects of congestion * - * can be observed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iiap_u { - bdrkreg_t ii_iiap_regval; - struct { - bdrkreg_t i_rq_mls : 6; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_rp_mls : 6; - bdrkreg_t i_rsvd : 50; - } ii_iiap_fld_s; -} ii_iiap_u_t; - -#else - -typedef union ii_iiap_u { - bdrkreg_t ii_iiap_regval; - struct { - bdrkreg_t i_rsvd : 50; - bdrkreg_t i_rp_mls : 6; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_rq_mls : 6; - } ii_iiap_fld_s; -} ii_iiap_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows several parameters of CRB operation to be * - * set. Note that writing to this register can have catastrophic side * - * effects, if the CRB is not quiescent, i.e. if the CRB is * - * processing protocol messages when the write occurs. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icmr_u { - bdrkreg_t ii_icmr_regval; - struct { - bdrkreg_t i_sp_msg : 1; - bdrkreg_t i_rd_hdr : 1; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_c_cnt : 4; - bdrkreg_t i_rsvd_3 : 4; - bdrkreg_t i_clr_rqpd : 1; - bdrkreg_t i_clr_rppd : 1; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_fc_cnt : 4; - bdrkreg_t i_crb_vld : 15; - bdrkreg_t i_crb_mark : 15; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_precise : 1; - bdrkreg_t i_rsvd : 11; - } ii_icmr_fld_s; -} ii_icmr_u_t; - -#else - -typedef union ii_icmr_u { - bdrkreg_t ii_icmr_regval; - struct { - bdrkreg_t i_rsvd : 11; - bdrkreg_t i_precise : 1; - bdrkreg_t i_rsvd_1 : 2; - bdrkreg_t i_crb_mark : 15; - bdrkreg_t i_crb_vld : 15; - bdrkreg_t i_fc_cnt : 4; - bdrkreg_t i_rsvd_2 : 2; - bdrkreg_t i_clr_rppd : 1; - bdrkreg_t i_clr_rqpd : 1; - bdrkreg_t i_rsvd_3 : 4; - bdrkreg_t i_c_cnt : 4; - bdrkreg_t i_rsvd_4 : 2; - bdrkreg_t i_rd_hdr : 1; - bdrkreg_t i_sp_msg : 1; - } ii_icmr_fld_s; -} ii_icmr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows control of the table portion of the CRB * - * logic via software. Control operations from this register have * - * priority over all incoming Crosstalk or BTE requests. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_iccr_u { - bdrkreg_t ii_iccr_regval; - struct { - bdrkreg_t i_crb_num : 4; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_cmd : 8; - bdrkreg_t i_pending : 1; - bdrkreg_t i_rsvd : 47; - } ii_iccr_fld_s; -} ii_iccr_u_t; - -#else - -typedef union ii_iccr_u { - bdrkreg_t ii_iccr_regval; - struct { - bdrkreg_t i_rsvd : 47; - bdrkreg_t i_pending : 1; - bdrkreg_t i_cmd : 8; - bdrkreg_t i_rsvd_1 : 4; - bdrkreg_t i_crb_num : 4; - } ii_iccr_fld_s; -} ii_iccr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the maximum timeout value to be programmed. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icto_u { - bdrkreg_t ii_icto_regval; - struct { - bdrkreg_t i_timeout : 8; - bdrkreg_t i_rsvd : 56; - } ii_icto_fld_s; -} ii_icto_u_t; - -#else - -typedef union ii_icto_u { - bdrkreg_t ii_icto_regval; - struct { - bdrkreg_t i_rsvd : 56; - bdrkreg_t i_timeout : 8; - } ii_icto_fld_s; -} ii_icto_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows the timeout prescalar to be programmed. An * - * internal counter is associated with this register. When the * - * internal counter reaches the value of the PRESCALE field, the * - * timer registers in all valid CRBs are incremented (CRBx_D[TIMEOUT] * - * field). The internal counter resets to zero, and then continues * - * counting. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ictp_u { - bdrkreg_t ii_ictp_regval; - struct { - bdrkreg_t i_prescale : 24; - bdrkreg_t i_rsvd : 40; - } ii_ictp_fld_s; -} ii_ictp_u_t; - -#else - -typedef union ii_ictp_u { - bdrkreg_t ii_ictp_regval; - struct { - bdrkreg_t i_rsvd : 40; - bdrkreg_t i_prescale : 24; - } ii_ictp_fld_s; -} ii_ictp_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * The CRB Entry registers can be conceptualized as rows and columns * - * (illustrated in the table above). Each row contains the 4 * - * registers required for a single CRB Entry. The first doubleword * - * (column) for each entry is labeled A, and the second doubleword * - * (higher address) is labeled B, the third doubleword is labeled C, * - * and the fourth doubleword is labeled D. All CRB entries have their * - * addresses on a quarter cacheline aligned boundary. * - * Upon reset, only the following fields are initialized: valid * - * (VLD), priority count, timeout, timeout valid, and context valid. * - * All other bits should be cleared by software before use (after * - * recovering any potential error state from before the reset). * - * The following four tables summarize the format for the four * - * registers that are used for each ICRB# Entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_a_u { - bdrkreg_t ii_icrb0_a_regval; - struct { - bdrkreg_t ia_iow : 1; - bdrkreg_t ia_vld : 1; - bdrkreg_t ia_addr : 38; - bdrkreg_t ia_tnum : 5; - bdrkreg_t ia_sidn : 4; - bdrkreg_t ia_xt_err : 1; - bdrkreg_t ia_mark : 1; - bdrkreg_t ia_ln_uce : 1; - bdrkreg_t ia_errcode : 3; - bdrkreg_t ia_error : 1; - bdrkreg_t ia_stall__bte_1 : 1; - bdrkreg_t ia_stall__bte_0 : 1; - bdrkreg_t ia_rsvd : 6; - } ii_icrb0_a_fld_s; -} ii_icrb0_a_u_t; - -#else - -typedef union ii_icrb0_a_u { - bdrkreg_t ii_icrb0_a_regval; - struct { - bdrkreg_t ia_rsvd : 6; - bdrkreg_t ia_stall__bte_0 : 1; - bdrkreg_t ia_stall__bte_1 : 1; - bdrkreg_t ia_error : 1; - bdrkreg_t ia_errcode : 3; - bdrkreg_t ia_ln_uce : 1; - bdrkreg_t ia_mark : 1; - bdrkreg_t ia_xt_err : 1; - bdrkreg_t ia_sidn : 4; - bdrkreg_t ia_tnum : 5; - bdrkreg_t ia_addr : 38; - bdrkreg_t ia_vld : 1; - bdrkreg_t ia_iow : 1; - } ii_icrb0_a_fld_s; -} ii_icrb0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_b_u { - bdrkreg_t ii_icrb0_b_regval; - struct { - bdrkreg_t ib_stall__intr : 1; - bdrkreg_t ib_stall_ib : 1; - bdrkreg_t ib_intvn : 1; - bdrkreg_t ib_wb : 1; - bdrkreg_t ib_hold : 1; - bdrkreg_t ib_ack : 1; - bdrkreg_t ib_resp : 1; - bdrkreg_t ib_ack_cnt : 11; - bdrkreg_t ib_rsvd_1 : 7; - bdrkreg_t ib_exc : 5; - bdrkreg_t ib_init : 3; - bdrkreg_t ib_imsg : 8; - bdrkreg_t ib_imsgtype : 2; - bdrkreg_t ib_use_old : 1; - bdrkreg_t ib_source : 12; - bdrkreg_t ib_size : 2; - bdrkreg_t ib_ct : 1; - bdrkreg_t ib_bte_num : 1; - bdrkreg_t ib_rsvd : 4; - } ii_icrb0_b_fld_s; -} ii_icrb0_b_u_t; - -#else - -typedef union ii_icrb0_b_u { - bdrkreg_t ii_icrb0_b_regval; - struct { - bdrkreg_t ib_rsvd : 4; - bdrkreg_t ib_bte_num : 1; - bdrkreg_t ib_ct : 1; - bdrkreg_t ib_size : 2; - bdrkreg_t ib_source : 12; - bdrkreg_t ib_use_old : 1; - bdrkreg_t ib_imsgtype : 2; - bdrkreg_t ib_imsg : 8; - bdrkreg_t ib_init : 3; - bdrkreg_t ib_exc : 5; - bdrkreg_t ib_rsvd_1 : 7; - bdrkreg_t ib_ack_cnt : 11; - bdrkreg_t ib_resp : 1; - bdrkreg_t ib_ack : 1; - bdrkreg_t ib_hold : 1; - bdrkreg_t ib_wb : 1; - bdrkreg_t ib_intvn : 1; - bdrkreg_t ib_stall_ib : 1; - bdrkreg_t ib_stall__intr : 1; - } ii_icrb0_b_fld_s; -} ii_icrb0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_c_u { - bdrkreg_t ii_icrb0_c_regval; - struct { - bdrkreg_t ic_gbr : 1; - bdrkreg_t ic_resprqd : 1; - bdrkreg_t ic_bo : 1; - bdrkreg_t ic_suppl : 12; - bdrkreg_t ic_pa_be : 34; - bdrkreg_t ic_bte_op : 1; - bdrkreg_t ic_pr_psc : 4; - bdrkreg_t ic_pr_cnt : 4; - bdrkreg_t ic_sleep : 1; - bdrkreg_t ic_rsvd : 5; - } ii_icrb0_c_fld_s; -} ii_icrb0_c_u_t; - -#else - -typedef union ii_icrb0_c_u { - bdrkreg_t ii_icrb0_c_regval; - struct { - bdrkreg_t ic_rsvd : 5; - bdrkreg_t ic_sleep : 1; - bdrkreg_t ic_pr_cnt : 4; - bdrkreg_t ic_pr_psc : 4; - bdrkreg_t ic_bte_op : 1; - bdrkreg_t ic_pa_be : 34; - bdrkreg_t ic_suppl : 12; - bdrkreg_t ic_bo : 1; - bdrkreg_t ic_resprqd : 1; - bdrkreg_t ic_gbr : 1; - } ii_icrb0_c_fld_s; -} ii_icrb0_c_u_t; - -#endif - - - -/************************************************************************ - * * - * Description: There are 15 CRB Entries (ICRB0 to ICRBE) that are * - * used for Crosstalk operations (both cacheline and partial * - * operations) or BTE/IO. Because the CRB entries are very wide, four * - * registers (_A to _D) are required to read and write each entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icrb0_d_u { - bdrkreg_t ii_icrb0_d_regval; - struct { - bdrkreg_t id_timeout : 8; - bdrkreg_t id_context : 15; - bdrkreg_t id_rsvd_1 : 1; - bdrkreg_t id_tvld : 1; - bdrkreg_t id_cvld : 1; - bdrkreg_t id_rsvd : 38; - } ii_icrb0_d_fld_s; -} ii_icrb0_d_u_t; - -#else - -typedef union ii_icrb0_d_u { - bdrkreg_t ii_icrb0_d_regval; - struct { - bdrkreg_t id_rsvd : 38; - bdrkreg_t id_cvld : 1; - bdrkreg_t id_tvld : 1; - bdrkreg_t id_rsvd_1 : 1; - bdrkreg_t id_context : 15; - bdrkreg_t id_timeout : 8; - } ii_icrb0_d_fld_s; -} ii_icrb0_d_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the lower 64 bits of the header of the * - * spurious message captured by II. Valid when the SP_MSG bit in ICMR * - * register is set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icsml_u { - bdrkreg_t ii_icsml_regval; - struct { - bdrkreg_t i_tt_addr : 38; - bdrkreg_t i_tt_ack_cnt : 11; - bdrkreg_t i_newsuppl_ex : 11; - bdrkreg_t i_reserved : 3; - bdrkreg_t i_overflow : 1; - } ii_icsml_fld_s; -} ii_icsml_u_t; - -#else - -typedef union ii_icsml_u { - bdrkreg_t ii_icsml_regval; - struct { - bdrkreg_t i_overflow : 1; - bdrkreg_t i_reserved : 3; - bdrkreg_t i_newsuppl_ex : 11; - bdrkreg_t i_tt_ack_cnt : 11; - bdrkreg_t i_tt_addr : 38; - } ii_icsml_fld_s; -} ii_icsml_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the microscopic state, all the inputs to * - * the protocol table, captured with the spurious message. Valid when * - * the SP_MSG bit in the ICMR register is set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_icsmh_u { - bdrkreg_t ii_icsmh_regval; - struct { - bdrkreg_t i_tt_vld : 1; - bdrkreg_t i_xerr : 1; - bdrkreg_t i_ft_cwact_o : 1; - bdrkreg_t i_ft_wact_o : 1; - bdrkreg_t i_ft_active_o : 1; - bdrkreg_t i_sync : 1; - bdrkreg_t i_mnusg : 1; - bdrkreg_t i_mnusz : 1; - bdrkreg_t i_plusz : 1; - bdrkreg_t i_plusg : 1; - bdrkreg_t i_tt_exc : 5; - bdrkreg_t i_tt_wb : 1; - bdrkreg_t i_tt_hold : 1; - bdrkreg_t i_tt_ack : 1; - bdrkreg_t i_tt_resp : 1; - bdrkreg_t i_tt_intvn : 1; - bdrkreg_t i_g_stall_bte1 : 1; - bdrkreg_t i_g_stall_bte0 : 1; - bdrkreg_t i_g_stall_il : 1; - bdrkreg_t i_g_stall_ib : 1; - bdrkreg_t i_tt_imsg : 8; - bdrkreg_t i_tt_imsgtype : 2; - bdrkreg_t i_tt_use_old : 1; - bdrkreg_t i_tt_respreqd : 1; - bdrkreg_t i_tt_bte_num : 1; - bdrkreg_t i_cbn : 1; - bdrkreg_t i_match : 1; - bdrkreg_t i_rpcnt_lt_34 : 1; - bdrkreg_t i_rpcnt_ge_34 : 1; - bdrkreg_t i_rpcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_18 : 1; - bdrkreg_t i_rpcnt_lt_2 : 1; - bdrkreg_t i_rpcnt_ge_2 : 1; - bdrkreg_t i_rqcnt_lt_18 : 1; - bdrkreg_t i_rqcnt_ge_18 : 1; - bdrkreg_t i_rqcnt_lt_2 : 1; - bdrkreg_t i_rqcnt_ge_2 : 1; - bdrkreg_t i_tt_device : 7; - bdrkreg_t i_tt_init : 3; - bdrkreg_t i_reserved : 5; - } ii_icsmh_fld_s; -} ii_icsmh_u_t; - -#else - -typedef union ii_icsmh_u { - bdrkreg_t ii_icsmh_regval; - struct { - bdrkreg_t i_reserved : 5; - bdrkreg_t i_tt_init : 3; - bdrkreg_t i_tt_device : 7; - bdrkreg_t i_rqcnt_ge_2 : 1; - bdrkreg_t i_rqcnt_lt_2 : 1; - bdrkreg_t i_rqcnt_ge_18 : 1; - bdrkreg_t i_rqcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_2 : 1; - bdrkreg_t i_rpcnt_lt_2 : 1; - bdrkreg_t i_rpcnt_ge_18 : 1; - bdrkreg_t i_rpcnt_lt_18 : 1; - bdrkreg_t i_rpcnt_ge_34 : 1; - bdrkreg_t i_rpcnt_lt_34 : 1; - bdrkreg_t i_match : 1; - bdrkreg_t i_cbn : 1; - bdrkreg_t i_tt_bte_num : 1; - bdrkreg_t i_tt_respreqd : 1; - bdrkreg_t i_tt_use_old : 1; - bdrkreg_t i_tt_imsgtype : 2; - bdrkreg_t i_tt_imsg : 8; - bdrkreg_t i_g_stall_ib : 1; - bdrkreg_t i_g_stall_il : 1; - bdrkreg_t i_g_stall_bte0 : 1; - bdrkreg_t i_g_stall_bte1 : 1; - bdrkreg_t i_tt_intvn : 1; - bdrkreg_t i_tt_resp : 1; - bdrkreg_t i_tt_ack : 1; - bdrkreg_t i_tt_hold : 1; - bdrkreg_t i_tt_wb : 1; - bdrkreg_t i_tt_exc : 5; - bdrkreg_t i_plusg : 1; - bdrkreg_t i_plusz : 1; - bdrkreg_t i_mnusz : 1; - bdrkreg_t i_mnusg : 1; - bdrkreg_t i_sync : 1; - bdrkreg_t i_ft_active_o : 1; - bdrkreg_t i_ft_wact_o : 1; - bdrkreg_t i_ft_cwact_o : 1; - bdrkreg_t i_xerr : 1; - bdrkreg_t i_tt_vld : 1; - } ii_icsmh_fld_s; -} ii_icsmh_u_t; - -#endif - - -/************************************************************************ - * * - * The Bedrock DEBUG unit provides a 3-bit selection signal to the * - * II unit, thus allowing a choice of one set of debug signal outputs * - * from a menu of 8 options. Each option is limited to 32 bits in * - * size. There are more signals of interest than can be accommodated * - * in this 8*32 framework, so the IDBSS register has been defined to * - * extend the range of choices available. For each menu option * - * available to the DEBUG unit, the II provides a "submenu" of * - * several options. The value of the SUBMENU field in the IDBSS * - * register selects the desired submenu. Hence, the particular debug * - * signals provided by the II are determined by the 3-bit selection * - * signal from the DEBUG unit and the value of the SUBMENU field * - * within the IDBSS register. For a detailed description of the * - * available menus and submenus for II debug signals, refer to the * - * documentation in ii_interface.doc.. * - * * - ************************************************************************/ - - - - -#ifdef LIITLE_ENDIAN - -typedef union ii_idbss_u { - bdrkreg_t ii_idbss_regval; - struct { - bdrkreg_t i_submenu : 3; - bdrkreg_t i_rsvd : 61; - } ii_idbss_fld_s; -} ii_idbss_u_t; - -#else - -typedef union ii_idbss_u { - bdrkreg_t ii_idbss_regval; - struct { - bdrkreg_t i_rsvd : 61; - bdrkreg_t i_submenu : 3; - } ii_idbss_fld_s; -} ii_idbss_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - - - - -#ifdef LIITLE_ENDIAN - -typedef union ii_ibls0_u { - bdrkreg_t ii_ibls0_regval; - struct { - bdrkreg_t i_length : 16; - bdrkreg_t i_error : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd : 43; - } ii_ibls0_fld_s; -} ii_ibls0_u_t; - -#else - -typedef union ii_ibls0_u { - bdrkreg_t ii_ibls0_regval; - struct { - bdrkreg_t i_rsvd : 43; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_error : 1; - bdrkreg_t i_length : 16; - } ii_ibls0_fld_s; -} ii_ibls0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibsa0_u { - bdrkreg_t ii_ibsa0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibsa0_fld_s; -} ii_ibsa0_u_t; - -#else - -typedef union ii_ibsa0_u { - bdrkreg_t ii_ibsa0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibsa0_fld_s; -} ii_ibsa0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibda0_u { - bdrkreg_t ii_ibda0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibda0_fld_s; -} ii_ibda0_u_t; - -#else - -typedef union ii_ibda0_u { - bdrkreg_t ii_ibda0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibda0_fld_s; -} ii_ibda0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibct0_u { - bdrkreg_t ii_ibct0_regval; - struct { - bdrkreg_t i_zerofill : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibct0_fld_s; -} ii_ibct0_u_t; - -#else - -typedef union ii_ibct0_u { - bdrkreg_t ii_ibct0_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_zerofill : 1; - } ii_ibct0_fld_s; -} ii_ibct0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibna0_u { - bdrkreg_t ii_ibna0_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibna0_fld_s; -} ii_ibna0_u_t; - -#else - -typedef union ii_ibna0_u { - bdrkreg_t ii_ibna0_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibna0_fld_s; -} ii_ibna0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibia0_u { - bdrkreg_t ii_ibia0_regval; - struct { - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd : 41; - } ii_ibia0_fld_s; -} ii_ibia0_u_t; - -#else - -typedef union ii_ibia0_u { - bdrkreg_t ii_ibia0_regval; - struct { - bdrkreg_t i_rsvd : 41; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_pi_id : 1; - } ii_ibia0_fld_s; -} ii_ibia0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register is used to set up the length for a * - * transfer and then to monitor the progress of that transfer. This * - * register needs to be initialized before a transfer is started. A * - * legitimate write to this register will set the Busy bit, clear the * - * Error bit, and initialize the length to the value desired. * - * While the transfer is in progress, hardware will decrement the * - * length field with each successful block that is copied. Once the * - * transfer completes, hardware will clear the Busy bit. The length * - * field will also contain the number of cache lines left to be * - * transferred. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibls1_u { - bdrkreg_t ii_ibls1_regval; - struct { - bdrkreg_t i_length : 16; - bdrkreg_t i_error : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd : 43; - } ii_ibls1_fld_s; -} ii_ibls1_u_t; - -#else - -typedef union ii_ibls1_u { - bdrkreg_t ii_ibls1_regval; - struct { - bdrkreg_t i_rsvd : 43; - bdrkreg_t i_busy : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_error : 1; - bdrkreg_t i_length : 16; - } ii_ibls1_fld_s; -} ii_ibls1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibsa1_u { - bdrkreg_t ii_ibsa1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibsa1_fld_s; -} ii_ibsa1_u_t; - -#else - -typedef union ii_ibsa1_u { - bdrkreg_t ii_ibsa1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibsa1_fld_s; -} ii_ibsa1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register should be loaded before a transfer is started. The * - * address to be loaded in bits 39:0 is the 40-bit TRex+ physical * - * address as described in Section 1.3, Figure2 and Figure3. Since * - * the bottom 7 bits of the address are always taken to be zero, BTE * - * transfers are always cacheline-aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibda1_u { - bdrkreg_t ii_ibda1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibda1_fld_s; -} ii_ibda1_u_t; - -#else - -typedef union ii_ibda1_u { - bdrkreg_t ii_ibda1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibda1_fld_s; -} ii_ibda1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing to this register sets up the attributes of the transfer * - * and initiates the transfer operation. Reading this register has * - * the side effect of terminating any transfer in progress. Note: * - * stopping a transfer midstream could have an adverse impact on the * - * other BTE. If a BTE stream has to be stopped (due to error * - * handling for example), both BTE streams should be stopped and * - * their transfers discarded. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibct1_u { - bdrkreg_t ii_ibct1_regval; - struct { - bdrkreg_t i_zerofill : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd : 55; - } ii_ibct1_fld_s; -} ii_ibct1_u_t; - -#else - -typedef union ii_ibct1_u { - bdrkreg_t ii_ibct1_regval; - struct { - bdrkreg_t i_rsvd : 55; - bdrkreg_t i_poison : 1; - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_notify : 1; - bdrkreg_t i_rsvd_2 : 3; - bdrkreg_t i_zerofill : 1; - } ii_ibct1_fld_s; -} ii_ibct1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the address to which the WINV is sent. * - * This address has to be cache line aligned. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibna1_u { - bdrkreg_t ii_ibna1_regval; - struct { - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd : 24; - } ii_ibna1_fld_s; -} ii_ibna1_u_t; - -#else - -typedef union ii_ibna1_u { - bdrkreg_t ii_ibna1_regval; - struct { - bdrkreg_t i_rsvd : 24; - bdrkreg_t i_addr : 33; - bdrkreg_t i_rsvd_1 : 7; - } ii_ibna1_fld_s; -} ii_ibna1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the programmable level as well as the node * - * ID and PI unit of the processor to which the interrupt will be * - * sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ibia1_u { - bdrkreg_t ii_ibia1_regval; - struct { - bdrkreg_t i_pi_id : 1; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd : 41; - } ii_ibia1_fld_s; -} ii_ibia1_u_t; - -#else - -typedef union ii_ibia1_u { - bdrkreg_t ii_ibia1_regval; - struct { - bdrkreg_t i_rsvd : 41; - bdrkreg_t i_level : 7; - bdrkreg_t i_rsvd_1 : 7; - bdrkreg_t i_node_id : 8; - bdrkreg_t i_pi_id : 1; - } ii_ibia1_fld_s; -} ii_ibia1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register defines the resources that feed information into * - * the two performance counters located in the IO Performance * - * Profiling Register. There are 17 different quantities that can be * - * measured. Given these 17 different options, the two performance * - * counters have 15 of them in common; menu selections 0 through 0xE * - * are identical for each performance counter. As for the other two * - * options, one is available from one performance counter and the * - * other is available from the other performance counter. Hence, the * - * II supports all 17*16=272 possible combinations of quantities to * - * measure. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ipcr_u { - bdrkreg_t ii_ipcr_regval; - struct { - bdrkreg_t i_ippr0_c : 4; - bdrkreg_t i_ippr1_c : 4; - bdrkreg_t i_icct : 8; - bdrkreg_t i_rsvd : 48; - } ii_ipcr_fld_s; -} ii_ipcr_u_t; - -#else - -typedef union ii_ipcr_u { - bdrkreg_t ii_ipcr_regval; - struct { - bdrkreg_t i_rsvd : 48; - bdrkreg_t i_icct : 8; - bdrkreg_t i_ippr1_c : 4; - bdrkreg_t i_ippr0_c : 4; - } ii_ipcr_fld_s; -} ii_ipcr_u_t; - -#endif - - - - -/************************************************************************ - * * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ii_ippr_u { - bdrkreg_t ii_ippr_regval; - struct { - bdrkreg_t i_ippr0 : 32; - bdrkreg_t i_ippr1 : 32; - } ii_ippr_fld_s; -} ii_ippr_u_t; - -#else - -typedef union ii_ippr_u { - bdrkreg_t ii_ippr_regval; - struct { - bdrkreg_t i_ippr1 : 32; - bdrkreg_t i_ippr0 : 32; - } ii_ippr_fld_s; -} ii_ippr_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines which were not formed into structures are * - * probably indentical to another register, and the name of the * - * register is provided against each of these registers. This * - * information needs to be checked carefully * - * * - * IIO_ICRB1_A IIO_ICRB0_A * - * IIO_ICRB1_B IIO_ICRB0_B * - * IIO_ICRB1_C IIO_ICRB0_C * - * IIO_ICRB1_D IIO_ICRB0_D * - * IIO_ICRB2_A IIO_ICRB0_A * - * IIO_ICRB2_B IIO_ICRB0_B * - * IIO_ICRB2_C IIO_ICRB0_C * - * IIO_ICRB2_D IIO_ICRB0_D * - * IIO_ICRB3_A IIO_ICRB0_A * - * IIO_ICRB3_B IIO_ICRB0_B * - * IIO_ICRB3_C IIO_ICRB0_C * - * IIO_ICRB3_D IIO_ICRB0_D * - * IIO_ICRB4_A IIO_ICRB0_A * - * IIO_ICRB4_B IIO_ICRB0_B * - * IIO_ICRB4_C IIO_ICRB0_C * - * IIO_ICRB4_D IIO_ICRB0_D * - * IIO_ICRB5_A IIO_ICRB0_A * - * IIO_ICRB5_B IIO_ICRB0_B * - * IIO_ICRB5_C IIO_ICRB0_C * - * IIO_ICRB5_D IIO_ICRB0_D * - * IIO_ICRB6_A IIO_ICRB0_A * - * IIO_ICRB6_B IIO_ICRB0_B * - * IIO_ICRB6_C IIO_ICRB0_C * - * IIO_ICRB6_D IIO_ICRB0_D * - * IIO_ICRB7_A IIO_ICRB0_A * - * IIO_ICRB7_B IIO_ICRB0_B * - * IIO_ICRB7_C IIO_ICRB0_C * - * IIO_ICRB7_D IIO_ICRB0_D * - * IIO_ICRB8_A IIO_ICRB0_A * - * IIO_ICRB8_B IIO_ICRB0_B * - * IIO_ICRB8_C IIO_ICRB0_C * - * IIO_ICRB8_D IIO_ICRB0_D * - * IIO_ICRB9_A IIO_ICRB0_A * - * IIO_ICRB9_B IIO_ICRB0_B * - * IIO_ICRB9_C IIO_ICRB0_C * - * IIO_ICRB9_D IIO_ICRB0_D * - * IIO_ICRBA_A IIO_ICRB0_A * - * IIO_ICRBA_B IIO_ICRB0_B * - * IIO_ICRBA_C IIO_ICRB0_C * - * IIO_ICRBA_D IIO_ICRB0_D * - * IIO_ICRBB_A IIO_ICRB0_A * - * IIO_ICRBB_B IIO_ICRB0_B * - * IIO_ICRBB_C IIO_ICRB0_C * - * IIO_ICRBB_D IIO_ICRB0_D * - * IIO_ICRBC_A IIO_ICRB0_A * - * IIO_ICRBC_B IIO_ICRB0_B * - * IIO_ICRBC_C IIO_ICRB0_C * - * IIO_ICRBC_D IIO_ICRB0_D * - * IIO_ICRBD_A IIO_ICRB0_A * - * IIO_ICRBD_B IIO_ICRB0_B * - * IIO_ICRBD_C IIO_ICRB0_C * - * IIO_ICRBD_D IIO_ICRB0_D * - * IIO_ICRBE_A IIO_ICRB0_A * - * IIO_ICRBE_B IIO_ICRB0_B * - * IIO_ICRBE_C IIO_ICRB0_C * - * IIO_ICRBE_D IIO_ICRB0_D * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBIO_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubio_next.h b/include/asm-ia64/sn/sn1/hubio_next.h --- a/include/asm-ia64/sn/sn1/hubio_next.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,762 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBIO_NEXT_H -#define _ASM_IA64_SN_SN1_HUBIO_NEXT_H - -/* - * Slightly friendlier names for some common registers. - */ -#define IIO_WIDGET IIO_WID /* Widget identification */ -#define IIO_WIDGET_STAT IIO_WSTAT /* Widget status register */ -#define IIO_WIDGET_CTRL IIO_WCR /* Widget control register */ -#define IIO_PROTECT IIO_ILAPR /* IO interface protection */ -#define IIO_PROTECT_OVRRD IIO_ILAPO /* IO protect override */ -#define IIO_OUTWIDGET_ACCESS IIO_IOWA /* Outbound widget access */ -#define IIO_INWIDGET_ACCESS IIO_IIWA /* Inbound widget access */ -#define IIO_INDEV_ERR_MASK IIO_IIDEM /* Inbound device error mask */ -#define IIO_LLP_CSR IIO_ILCSR /* LLP control and status */ -#define IIO_LLP_LOG IIO_ILLR /* LLP log */ -#define IIO_XTALKCC_TOUT IIO_IXCC /* Xtalk credit count timeout*/ -#define IIO_XTALKTT_TOUT IIO_IXTT /* Xtalk tail timeout */ -#define IIO_IO_ERR_CLR IIO_IECLR /* IO error clear */ -#define IIO_IGFX_0 IIO_IGFX0 -#define IIO_IGFX_1 IIO_IGFX1 -#define IIO_IBCT_0 IIO_IBCT0 -#define IIO_IBCT_1 IIO_IBCT1 -#define IIO_IBLS_0 IIO_IBLS0 -#define IIO_IBLS_1 IIO_IBLS1 -#define IIO_IBSA_0 IIO_IBSA0 -#define IIO_IBSA_1 IIO_IBSA1 -#define IIO_IBDA_0 IIO_IBDA0 -#define IIO_IBDA_1 IIO_IBDA1 -#define IIO_IBNA_0 IIO_IBNA0 -#define IIO_IBNA_1 IIO_IBNA1 -#define IIO_IBIA_0 IIO_IBIA0 -#define IIO_IBIA_1 IIO_IBIA1 -#define IIO_IOPRB_0 IIO_IPRB0 -#define IIO_PRTE_0 IIO_IPRTE0 /* PIO Read address table entry 0 */ -#define IIO_PRTE(_x) (IIO_PRTE_0 + (8 * (_x))) -#define IIO_NUM_IPRBS (9) -#define IIO_WIDPRTE(x) IIO_PRTE(((x) - 8)) /* widget ID to its PRTE num */ - -#define IIO_LLP_CSR_IS_UP 0x00002000 -#define IIO_LLP_CSR_LLP_STAT_MASK 0x00003000 -#define IIO_LLP_CSR_LLP_STAT_SHFT 12 - -#define IIO_LLP_CB_MAX 0xffff /* in ILLR CB_CNT, Max Check Bit errors */ -#define IIO_LLP_SN_MAX 0xffff /* in ILLR SN_CNT, Max Sequence Number errors */ - -/* key to IIO_PROTECT_OVRRD */ -#define IIO_PROTECT_OVRRD_KEY 0x53474972756c6573ull /* "SGIrules" */ - -/* BTE register names */ -#define IIO_BTE_STAT_0 IIO_IBLS_0 /* Also BTE length/status 0 */ -#define IIO_BTE_SRC_0 IIO_IBSA_0 /* Also BTE source address 0 */ -#define IIO_BTE_DEST_0 IIO_IBDA_0 /* Also BTE dest. address 0 */ -#define IIO_BTE_CTRL_0 IIO_IBCT_0 /* Also BTE control/terminate 0 */ -#define IIO_BTE_NOTIFY_0 IIO_IBNA_0 /* Also BTE notification 0 */ -#define IIO_BTE_INT_0 IIO_IBIA_0 /* Also BTE interrupt 0 */ -#define IIO_BTE_OFF_0 0 /* Base offset from BTE 0 regs. */ -#define IIO_BTE_OFF_1 (IIO_IBLS_1 - IIO_IBLS_0) /* Offset from base to BTE 1 */ - -/* BTE register offsets from base */ -#define BTEOFF_STAT 0 -#define BTEOFF_SRC (IIO_BTE_SRC_0 - IIO_BTE_STAT_0) -#define BTEOFF_DEST (IIO_BTE_DEST_0 - IIO_BTE_STAT_0) -#define BTEOFF_CTRL (IIO_BTE_CTRL_0 - IIO_BTE_STAT_0) -#define BTEOFF_NOTIFY (IIO_BTE_NOTIFY_0 - IIO_BTE_STAT_0) -#define BTEOFF_INT (IIO_BTE_INT_0 - IIO_BTE_STAT_0) - - -/* names used in hub_diags.c; carried over from SN0 */ -#define IIO_BASE_BTE0 IIO_IBLS_0 -#define IIO_BASE_BTE1 IIO_IBLS_1 - -/* - * Macro which takes the widget number, and returns the - * IO PRB address of that widget. - * value _x is expected to be a widget number in the range - * 0, 8 - 0xF - */ -#define IIO_IOPRB(_x) (IIO_IOPRB_0 + ( ( (_x) < HUB_WIDGET_ID_MIN ? \ - (_x) : \ - (_x) - (HUB_WIDGET_ID_MIN-1)) << 3) ) - - -/* GFX Flow Control Node/Widget Register */ -#define IIO_IGFX_W_NUM_BITS 4 /* size of widget num field */ -#define IIO_IGFX_W_NUM_MASK ((1<> IIO_WSTAT_TXRETRY_SHFT) & \ - IIO_WSTAT_TXRETRY_MASK) - -/* Number of II perf. counters we can multiplex at once */ - -#define IO_PERF_SETS 32 - -#if __KERNEL__ -#ifndef __ASSEMBLY__ -/* XXX moved over from SN/SN0/hubio.h -- each should be checked for SN1 */ -#include -#include -#include -#include - -/* Bit for the widget in inbound access register */ -#define IIO_IIWA_WIDGET(_w) ((uint64_t)(1ULL << _w)) -/* Bit for the widget in outbound access register */ -#define IIO_IOWA_WIDGET(_w) ((uint64_t)(1ULL << _w)) - -/* NOTE: The following define assumes that we are going to get - * widget numbers from 8 thru F and the device numbers within - * widget from 0 thru 7. - */ -#define IIO_IIDEM_WIDGETDEV_MASK(w, d) ((uint64_t)(1ULL << (8 * ((w) - 8) + (d)))) - -/* IO Interrupt Destination Register */ -#define IIO_IIDSR_SENT_SHIFT 28 -#define IIO_IIDSR_SENT_MASK 0x10000000 -#define IIO_IIDSR_ENB_SHIFT 24 -#define IIO_IIDSR_ENB_MASK 0x01000000 -#define IIO_IIDSR_NODE_SHIFT 8 -#define IIO_IIDSR_NODE_MASK 0x0000ff00 -#define IIO_IIDSR_PI_ID_SHIFT 8 -#define IIO_IIDSR_PI_ID_MASK 0x00000010 -#define IIO_IIDSR_LVL_SHIFT 0 -#define IIO_IIDSR_LVL_MASK 0x0000007f - -/* Xtalk timeout threshhold register (IIO_IXTT) */ -#define IXTT_RRSP_TO_SHFT 55 /* read response timeout */ -#define IXTT_RRSP_TO_MASK (0x1FULL << IXTT_RRSP_TO_SHFT) -#define IXTT_RRSP_PS_SHFT 32 /* read responsed TO prescalar */ -#define IXTT_RRSP_PS_MASK (0x7FFFFFULL << IXTT_RRSP_PS_SHFT) -#define IXTT_TAIL_TO_SHFT 0 /* tail timeout counter threshold */ -#define IXTT_TAIL_TO_MASK (0x3FFFFFFULL << IXTT_TAIL_TO_SHFT) - -/* - * The IO LLP control status register and widget control register - */ - -#ifdef LITTLE_ENDIAN - -typedef union hubii_wcr_u { - uint64_t wcr_reg_value; - struct { - uint64_t wcr_widget_id: 4, /* LLP crossbar credit */ - wcr_tag_mode: 1, /* Tag mode */ - wcr_rsvd1: 8, /* Reserved */ - wcr_xbar_crd: 3, /* LLP crossbar credit */ - wcr_f_bad_pkt: 1, /* Force bad llp pkt enable */ - wcr_dir_con: 1, /* widget direct connect */ - wcr_e_thresh: 5, /* elasticity threshold */ - wcr_rsvd: 41; /* unused */ - } wcr_fields_s; -} hubii_wcr_t; - -#else - -typedef union hubii_wcr_u { - uint64_t wcr_reg_value; - struct { - uint64_t wcr_rsvd: 41, /* unused */ - wcr_e_thresh: 5, /* elasticity threshold */ - wcr_dir_con: 1, /* widget direct connect */ - wcr_f_bad_pkt: 1, /* Force bad llp pkt enable */ - wcr_xbar_crd: 3, /* LLP crossbar credit */ - wcr_rsvd1: 8, /* Reserved */ - wcr_tag_mode: 1, /* Tag mode */ - wcr_widget_id: 4; /* LLP crossbar credit */ - } wcr_fields_s; -} hubii_wcr_t; - -#endif - -#define iwcr_dir_con wcr_fields_s.wcr_dir_con - -/* The structures below are defined to extract and modify the ii -performance registers */ - -/* io_perf_sel allows the caller to specify what tests will be - performed */ -#ifdef LITTLE_ENDIAN - -typedef union io_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_ippr0 : 4, - perf_ippr1 : 4, - perf_icct : 8, - perf_rsvd : 48; - } perf_sel_bits; -} io_perf_sel_t; - -#else - -typedef union io_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_rsvd : 48, - perf_icct : 8, - perf_ippr1 : 4, - perf_ippr0 : 4; - } perf_sel_bits; -} io_perf_sel_t; - -#endif - -/* io_perf_cnt is to extract the count from the hub registers. Due to - hardware problems there is only one counter, not two. */ - -#ifdef LITTLE_ENDIAN - -typedef union io_perf_cnt { - uint64_t perf_cnt; - struct { - uint64_t perf_cnt : 20, - perf_rsvd2 : 12, - perf_rsvd1 : 32; - } perf_cnt_bits; - -} io_perf_cnt_t; - -#else - -typedef union io_perf_cnt { - uint64_t perf_cnt; - struct { - uint64_t perf_rsvd1 : 32, - perf_rsvd2 : 12, - perf_cnt : 20; - } perf_cnt_bits; - -} io_perf_cnt_t; - -#endif - -#ifdef LITTLE_ENDIAN - -typedef union iprte_a { - bdrkreg_t entry; - struct { - bdrkreg_t i_rsvd_1 : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_init : 3; - bdrkreg_t i_source : 8; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_widget : 4; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_vld : 1; - } iprte_fields; -} iprte_a_t; - -#else - -typedef union iprte_a { - bdrkreg_t entry; - struct { - bdrkreg_t i_vld : 1; - bdrkreg_t i_to_cnt : 5; - bdrkreg_t i_widget : 4; - bdrkreg_t i_rsvd : 2; - bdrkreg_t i_source : 8; - bdrkreg_t i_init : 3; - bdrkreg_t i_addr : 38; - bdrkreg_t i_rsvd_1 : 3; - } iprte_fields; -} iprte_a_t; - -#endif - -/* PIO MANAGEMENT */ -typedef struct hub_piomap_s *hub_piomap_t; - -extern hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags); /* defined in sys/pio.h */ - -extern void hub_piomap_free(hub_piomap_t hub_piomap); - -extern caddr_t -hub_piomap_addr(hub_piomap_t hub_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk addr */ - size_t byte_count); /* map this many bytes */ - -extern void -hub_piomap_done(hub_piomap_t hub_piomap); - -extern caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags); /* (currently unused) */ - -/* DMA MANAGEMENT */ -typedef struct hub_dmamap_s *hub_dmamap_t; - -extern hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for dev */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags); /* defined in dma.h */ - -extern void -hub_dmamap_free(hub_dmamap_t dmamap); - -extern iopaddr_t -hub_dmamap_addr( hub_dmamap_t dmamap, /* use mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count); /* map this many bytes */ - -extern alenlist_t -hub_dmamap_list( hub_dmamap_t dmamap, /* use mapping resources */ - alenlist_t alenlist, /* map this Addr/Length List */ - unsigned flags); - -extern void -hub_dmamap_done( hub_dmamap_t dmamap); /* done w/ mapping resources */ - -extern iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags); /* defined in dma.h */ - -extern alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - alenlist_t palenlist, /* system addr/length list */ - unsigned flags); /* defined in dma.h */ - -extern void -hub_dmamap_drain( hub_dmamap_t map); - -extern void -hub_dmaaddr_drain( devfs_handle_t vhdl, - paddr_t addr, - size_t bytes); - -extern void -hub_dmalist_drain( devfs_handle_t vhdl, - alenlist_t list); - - -/* INTERRUPT MANAGEMENT */ -typedef struct hub_intr_s *hub_intr_t; - -extern hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ - -extern hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ - device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ - -extern void -hub_intr_free(hub_intr_t intr_hdl); - -extern int -hub_intr_connect( hub_intr_t intr_hdl, /* xtalk intr resource hndl */ - xtalk_intr_setfunc_t setfunc, - /* func to set intr hw */ - void *setfunc_arg); /* arg to setfunc */ - -extern void -hub_intr_disconnect(hub_intr_t intr_hdl); - -extern devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl); - -/* CONFIGURATION MANAGEMENT */ - -extern void -hub_provider_startup(devfs_handle_t hub); - -extern void -hub_provider_shutdown(devfs_handle_t hub); - -#define HUB_PIO_CONVEYOR 0x1 /* PIO in conveyor belt mode */ -#define HUB_PIO_FIRE_N_FORGET 0x2 /* PIO in fire-and-forget mode */ - -/* Flags that make sense to hub_widget_flags_set */ -#define HUB_WIDGET_FLAGS ( \ - HUB_PIO_CONVEYOR | \ - HUB_PIO_FIRE_N_FORGET \ - ) - - -typedef int hub_widget_flags_t; - -/* Set the PIO mode for a widget. These two functions perform the - * same operation, but hub_device_flags_set() takes a hardware graph - * vertex while hub_widget_flags_set() takes a nasid and widget - * number. In most cases, hub_device_flags_set() should be used. - */ -extern int hub_widget_flags_set(nasid_t nasid, - xwidgetnum_t widget_num, - hub_widget_flags_t flags); - -/* Depending on the flags set take the appropriate actions */ -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); - - -/* Error Handling. */ -extern int hub_ioerror_handler(devfs_handle_t, int, int, struct io_error_s *); -extern int kl_ioerror_handler(cnodeid_t, cnodeid_t, cpuid_t, - int, paddr_t, caddr_t, ioerror_mode_t); -extern void hub_widget_reset(devfs_handle_t, xwidgetnum_t); -extern int hub_error_devenable(devfs_handle_t, int, int); -extern void hub_widgetdev_enable(devfs_handle_t, int); -extern void hub_widgetdev_shutdown(devfs_handle_t, int); -extern int hub_dma_enabled(devfs_handle_t); - -#endif /* __ASSEMBLY__ */ -#endif /* _KERNEL */ -#endif /* _ASM_IA64_SN_SN1_HUBIO_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hublb.h b/include/asm-ia64/sn/sn1/hublb.h --- a/include/asm-ia64/sn/sn1/hublb.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1607 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#ifndef _ASM_IA64_SN_SN1_HUBLB_H -#define _ASM_IA64_SN_SN1_HUBLB_H - - -#define LB_REV_ID 0x00600000 /* - * Bedrock Revision - * and ID - */ - - - -#define LB_CPU_PERMISSION 0x00604000 /* - * CPU PIO access - * permission bits - */ - - - -#define LB_CPU_PERM_OVRRD 0x00604008 /* - * CPU PIO access - * permission bit - * override - */ - - - -#define LB_IO_PERMISSION 0x00604010 /* - * IO PIO access - * permission bits - */ - - - -#define LB_SOFT_RESET 0x00604018 /* - * Soft reset the - * Bedrock chip - */ - - - -#define LB_REGION_PRESENT 0x00604020 /* - * Regions Present for - * Invalidates - */ - - - -#define LB_NODES_ABSENT 0x00604028 /* - * Nodes Absent for - * Invalidates - */ - - - -#define LB_MICROLAN_CTL 0x00604030 /* - * Microlan Control - * (NIC) - */ - - - -#define LB_ERROR_BITS 0x00604040 /* - * Local Block error - * bits - */ - - - -#define LB_ERROR_MASK_CLR 0x00604048 /* - * Bit mask write to - * clear error bits - */ - - - -#define LB_ERROR_HDR1 0x00604050 /* - * Source, Suppl and - * Cmd fields - */ - - - -#define LB_ERROR_HDR2 0x00604058 /* - * Address field from - * first error - */ - - - -#define LB_ERROR_DATA 0x00604060 /* - * Data flit (if any) - * from first error - */ - - - -#define LB_DEBUG_SELECT 0x00604100 /* - * Choice of debug - * signals from chip - */ - - - -#define LB_DEBUG_PINS 0x00604108 /* - * Value on the chip's - * debug pins - */ - - - -#define LB_RT_LOCAL_CTRL 0x00604200 /* - * Local generation of - * real-time clock - */ - - - -#define LB_RT_FILTER_CTRL 0x00604208 /* - * Control of - * filtering of global - * clock - */ - - - -#define LB_SCRATCH_REG0 0x00608000 /* Scratch Register 0 */ - - - -#define LB_SCRATCH_REG1 0x00608008 /* Scratch Register 1 */ - - - -#define LB_SCRATCH_REG2 0x00608010 /* Scratch Register 2 */ - - - -#define LB_SCRATCH_REG3 0x00608018 /* Scratch Register 3 */ - - - -#define LB_SCRATCH_REG4 0x00608020 /* Scratch Register 4 */ - - - -#define LB_SCRATCH_REG0_WZ 0x00608040 /* - * Scratch Register 0 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG1_WZ 0x00608048 /* - * Scratch Register 1 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG2_WZ 0x00608050 /* - * Scratch Register 2 - * (WZ alias) - */ - - - -#define LB_SCRATCH_REG3_RZ 0x00608058 /* - * Scratch Register 3 - * (RZ alias) - */ - - - -#define LB_SCRATCH_REG4_RZ 0x00608060 /* - * Scratch Register 4 - * (RZ alias) - */ - - - -#define LB_VECTOR_PARMS 0x0060C000 /* - * Vector PIO - * parameters - */ - - - -#define LB_VECTOR_ROUTE 0x0060C008 /* - * Vector PIO Vector - * Route - */ - - - -#define LB_VECTOR_DATA 0x0060C010 /* - * Vector PIO Write - * Data - */ - - - -#define LB_VECTOR_STATUS 0x0060C020 /* - * Vector PIO Return - * Status - */ - - - -#define LB_VECTOR_RETURN 0x0060C028 /* - * Vector PIO Return - * Route - */ - - - -#define LB_VECTOR_READ_DATA 0x0060C030 /* - * Vector PIO Read - * Data - */ - - - -#define LB_VECTOR_STATUS_CLEAR 0x0060C038 /* - * Clear Vector PIO - * Return Status - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register contains information that allows * - * exploratory software to probe for chip type. This is also the * - * register that sets this node's ID and the size of each region * - * (which affects the maximum possible system size). IBM assigns the * - * values for the REVISION, PART_NUMBER and MANUFACTURER fields, in * - * accordance with the IEEE 1149.1 standard; SGI is not at liberty to * - * unilaterally change the values of these fields. * - * . * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rev_id_u { - bdrkreg_t lb_rev_id_regval; - struct { - bdrkreg_t ri_reserved_2 : 1; - bdrkreg_t ri_manufacturer : 11; - bdrkreg_t ri_part_number : 16; - bdrkreg_t ri_revision : 4; - bdrkreg_t ri_node_id : 8; - bdrkreg_t ri_reserved_1 : 6; - bdrkreg_t ri_region_size : 2; - bdrkreg_t ri_reserved : 16; - } lb_rev_id_fld_s; -} lb_rev_id_u_t; - -#else - -typedef union lb_rev_id_u { - bdrkreg_t lb_rev_id_regval; - struct { - bdrkreg_t ri_reserved : 16; - bdrkreg_t ri_region_size : 2; - bdrkreg_t ri_reserved_1 : 6; - bdrkreg_t ri_node_id : 8; - bdrkreg_t ri_revision : 4; - bdrkreg_t ri_part_number : 16; - bdrkreg_t ri_manufacturer : 11; - bdrkreg_t ri_reserved_2 : 1; - } lb_rev_id_fld_s; -} lb_rev_id_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the PI-access-rights bit-vector for the * - * LB, NI, XB and MD portions of the Bedrock local register space. If * - * a bit in the bit-vector is set, the region corresponding to that * - * bit has read/write permission on the LB, NI, XB and MD local * - * registers. If the bit is clear, that region has no write access to * - * the local registers and no read access if the read will cause any * - * state change. If a write or a read with side effects is attempted * - * by a PI in a region for which access is restricted, the LB will * - * not perform the operation and will send back a reply which * - * indicates an error. * - * * - ************************************************************************/ - - - - -typedef union lb_cpu_permission_u { - bdrkreg_t lb_cpu_permission_regval; - struct { - bdrkreg_t cp_cpu_access : 64; - } lb_cpu_permission_fld_s; -} lb_cpu_permission_u_t; - - - - -/************************************************************************ - * * - * A write to this register of the 64-bit value "SGIrules" will * - * cause the bit in the LB_CPU_PROTECT register corresponding to the * - * region of the requester to be set. * - * * - ************************************************************************/ - - - - -typedef union lb_cpu_perm_ovrrd_u { - bdrkreg_t lb_cpu_perm_ovrrd_regval; - struct { - bdrkreg_t cpo_cpu_perm_ovr : 64; - } lb_cpu_perm_ovrrd_fld_s; -} lb_cpu_perm_ovrrd_u_t; - - - - -/************************************************************************ - * * - * This register contains the II-access-rights bit-vector for the * - * LB, NI, XB and MD portions of the Bedrock local register space. If * - * a bit in the bit-vector is set, the region corresponding to that * - * bit has read/write permission on the LB, NI, XB and MD local * - * registers. If the bit is clear, then that region has no write * - * access to the local registers and no read access if the read * - * results in any state change. If a write or a read with side * - * effects is attempted by an II in a region for which access is * - * restricted, the LB will not perform the operation and will send * - * back a reply which indicates an error. * - * * - ************************************************************************/ - - - - -typedef union lb_io_permission_u { - bdrkreg_t lb_io_permission_regval; - struct { - bdrkreg_t ip_io_permission : 64; - } lb_io_permission_fld_s; -} lb_io_permission_u_t; - - - - -/************************************************************************ - * * - * A write to this bit resets the Bedrock chip with a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_soft_reset_u { - bdrkreg_t lb_soft_reset_regval; - struct { - bdrkreg_t sr_soft_reset : 1; - bdrkreg_t sr_reserved : 63; - } lb_soft_reset_fld_s; -} lb_soft_reset_u_t; - -#else - -typedef union lb_soft_reset_u { - bdrkreg_t lb_soft_reset_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_soft_reset : 1; - } lb_soft_reset_fld_s; -} lb_soft_reset_u_t; - -#endif - - - -/************************************************************************ - * * - * This register indicates which regions are present and capable of * - * receiving an invalidate (INVAL) request. The LB samples this * - * register at the start of processing each LINVAL. When an LINVAL * - * indicates that a particular PI unit might hold a shared copy of a * - * cache block but this PI is in a region which is not present (i.e., * - * its bit in LB_REGION_PRESENT is clear), then the LB sends an IVACK * - * reply packet on behalf of this PI. The REGION_SIZE field in the * - * LB_REV_ID register determines the number of nodes per region (and * - * hence, the number of PI units which share a common bit in the * - * LB_REGION_PRESENT register). * - * * - ************************************************************************/ - - - - -typedef union lb_region_present_u { - bdrkreg_t lb_region_present_regval; - struct { - bdrkreg_t rp_present_bits : 64; - } lb_region_present_fld_s; -} lb_region_present_u_t; - - - - -/************************************************************************ - * * - * Description: This register indicates which nodes are absent and * - * not capable of receiving an invalidate (INVAL) request. The LB * - * samples this register at the start of processing each LINVAL. When * - * an LINVAL indicates that a particular PI unit might hold a shared * - * copy of a cache block but this PI unit's node is not present * - * (i.e., its node ID is listed in the LB_NODES_ABSENT register), * - * then the LB sends an IVACK reply packet on behalf of this PI. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_nodes_absent_u { - bdrkreg_t lb_nodes_absent_regval; - struct { - bdrkreg_t na_node_0 : 8; - bdrkreg_t na_reserved_3 : 7; - bdrkreg_t na_node_0_valid : 1; - bdrkreg_t na_node_1 : 8; - bdrkreg_t na_reserved_2 : 7; - bdrkreg_t na_node_1_valid : 1; - bdrkreg_t na_node_2 : 8; - bdrkreg_t na_reserved_1 : 7; - bdrkreg_t na_node_2_valid : 1; - bdrkreg_t na_node_3 : 8; - bdrkreg_t na_reserved : 7; - bdrkreg_t na_node_3_valid : 1; - } lb_nodes_absent_fld_s; -} lb_nodes_absent_u_t; - -#else - -typedef union lb_nodes_absent_u { - bdrkreg_t lb_nodes_absent_regval; - struct { - bdrkreg_t na_node_3_valid : 1; - bdrkreg_t na_reserved : 7; - bdrkreg_t na_node_3 : 8; - bdrkreg_t na_node_2_valid : 1; - bdrkreg_t na_reserved_1 : 7; - bdrkreg_t na_node_2 : 8; - bdrkreg_t na_node_1_valid : 1; - bdrkreg_t na_reserved_2 : 7; - bdrkreg_t na_node_1 : 8; - bdrkreg_t na_node_0_valid : 1; - bdrkreg_t na_reserved_3 : 7; - bdrkreg_t na_node_0 : 8; - } lb_nodes_absent_fld_s; -} lb_nodes_absent_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides access to the Number-In-a-Can add-only * - * serial PROM that is used to store node board serial number and * - * configuration information. (Refer to NIC datasheet Dallas 1990A * - * that is viewable at * - * URL::http://www.dalsemi.com/DocControl/PDFs/pdfindex.html). Data * - * comes from this interface LSB first. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_microlan_ctl_u { - bdrkreg_t lb_microlan_ctl_regval; - struct { - bdrkreg_t mc_rd_data : 1; - bdrkreg_t mc_done : 1; - bdrkreg_t mc_sample : 8; - bdrkreg_t mc_pulse : 10; - bdrkreg_t mc_clkdiv_phi0 : 7; - bdrkreg_t mc_clkdiv_phi1 : 7; - bdrkreg_t mc_reserved : 30; - } lb_microlan_ctl_fld_s; -} lb_microlan_ctl_u_t; - -#else - -typedef union lb_microlan_ctl_u { - bdrkreg_t lb_microlan_ctl_regval; - struct { - bdrkreg_t mc_reserved : 30; - bdrkreg_t mc_clkdiv_phi1 : 7; - bdrkreg_t mc_clkdiv_phi0 : 7; - bdrkreg_t mc_pulse : 10; - bdrkreg_t mc_sample : 8; - bdrkreg_t mc_done : 1; - bdrkreg_t mc_rd_data : 1; - } lb_microlan_ctl_fld_s; -} lb_microlan_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains the LB error status bits. * - * Whenever a particular type of error occurs, the LB sets its bit in * - * this register so that software will be aware that such an event * - * has happened. Reads from this register are non-destructive and the * - * contents of this register remain intact across reset operations. * - * Whenever any of these bits is set, the LB will assert its * - * interrupt request output signals that go to the PI units. * - * Software can simulate the occurrence of an error by first writing * - * appropriate values into the LB_ERROR_HDR1, LB_ERROR_HDR2 and * - * LB_ERROR_DATA registers, and then writing to the LB_ERROR_BITS * - * register to set the error bits in a particular way. Setting one or * - * more error bits will cause the LB to interrupt a processor and * - * invoke error-handling software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_bits_u { - bdrkreg_t lb_error_bits_regval; - struct { - bdrkreg_t eb_rq_bad_cmd : 1; - bdrkreg_t eb_rp_bad_cmd : 1; - bdrkreg_t eb_rq_short : 1; - bdrkreg_t eb_rp_short : 1; - bdrkreg_t eb_rq_long : 1; - bdrkreg_t eb_rp_long : 1; - bdrkreg_t eb_rq_bad_data : 1; - bdrkreg_t eb_rp_bad_data : 1; - bdrkreg_t eb_rq_bad_addr : 1; - bdrkreg_t eb_rq_bad_linval : 1; - bdrkreg_t eb_gclk_drop : 1; - bdrkreg_t eb_reserved : 53; - } lb_error_bits_fld_s; -} lb_error_bits_u_t; - -#else - -typedef union lb_error_bits_u { - bdrkreg_t lb_error_bits_regval; - struct { - bdrkreg_t eb_reserved : 53; - bdrkreg_t eb_gclk_drop : 1; - bdrkreg_t eb_rq_bad_linval : 1; - bdrkreg_t eb_rq_bad_addr : 1; - bdrkreg_t eb_rp_bad_data : 1; - bdrkreg_t eb_rq_bad_data : 1; - bdrkreg_t eb_rp_long : 1; - bdrkreg_t eb_rq_long : 1; - bdrkreg_t eb_rp_short : 1; - bdrkreg_t eb_rq_short : 1; - bdrkreg_t eb_rp_bad_cmd : 1; - bdrkreg_t eb_rq_bad_cmd : 1; - } lb_error_bits_fld_s; -} lb_error_bits_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register lets software clear some of the bits in the * - * LB_ERROR_BITS register without affecting other bits. Essentially, * - * it provides bit mask functionality. When software writes to the * - * LB_ERROR_MASK_CLR register, the bits which are set in the data * - * value indicate which bits are to be cleared in LB_ERROR_BITS. If a * - * bit is clear in the data value written to the LB_ERROR_MASK_CLR * - * register, then its corresponding bit in the LB_ERROR_BITS register * - * is not affected. Hence, software can atomically clear any subset * - * of the error bits in the LB_ERROR_BITS register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_mask_clr_u { - bdrkreg_t lb_error_mask_clr_regval; - struct { - bdrkreg_t emc_clr_rq_bad_cmd : 1; - bdrkreg_t emc_clr_rp_bad_cmd : 1; - bdrkreg_t emc_clr_rq_short : 1; - bdrkreg_t emc_clr_rp_short : 1; - bdrkreg_t emc_clr_rq_long : 1; - bdrkreg_t emc_clr_rp_long : 1; - bdrkreg_t emc_clr_rq_bad_data : 1; - bdrkreg_t emc_clr_rp_bad_data : 1; - bdrkreg_t emc_clr_rq_bad_addr : 1; - bdrkreg_t emc_clr_rq_bad_linval : 1; - bdrkreg_t emc_clr_gclk_drop : 1; - bdrkreg_t emc_reserved : 53; - } lb_error_mask_clr_fld_s; -} lb_error_mask_clr_u_t; - -#else - -typedef union lb_error_mask_clr_u { - bdrkreg_t lb_error_mask_clr_regval; - struct { - bdrkreg_t emc_reserved : 53; - bdrkreg_t emc_clr_gclk_drop : 1; - bdrkreg_t emc_clr_rq_bad_linval : 1; - bdrkreg_t emc_clr_rq_bad_addr : 1; - bdrkreg_t emc_clr_rp_bad_data : 1; - bdrkreg_t emc_clr_rq_bad_data : 1; - bdrkreg_t emc_clr_rp_long : 1; - bdrkreg_t emc_clr_rq_long : 1; - bdrkreg_t emc_clr_rp_short : 1; - bdrkreg_t emc_clr_rq_short : 1; - bdrkreg_t emc_clr_rp_bad_cmd : 1; - bdrkreg_t emc_clr_rq_bad_cmd : 1; - } lb_error_mask_clr_fld_s; -} lb_error_mask_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * If the LB detects an error when VALID==0 in the LB_ERROR_HDR1 * - * register, then it saves the contents of the offending packet's * - * header flit in the LB_ERROR_HDR1 and LB_ERROR_HDR2 registers, sets * - * the VALID bit in LB_ERROR_HDR1 and clears the OVERRUN bit in * - * LB_ERROR_HDR1 (and it will also set the corresponding bit in the * - * LB_ERROR_BITS register). The ERR_TYPE field indicates specifically * - * what kind of error occurred. Its encoding corresponds to the bit * - * positions in the LB_ERROR_BITS register (e.g., ERR_TYPE==5 * - * indicates a RP_LONG error). If an error (of any type except * - * GCLK_DROP) subsequently happens while VALID==1, then the LB sets * - * the OVERRUN bit in LB_ERROR_HDR1. This register is not relevant * - * when a GCLK_DROP error occurs; the LB does not even attempt to * - * change the ERR_TYPE, VALID or OVERRUN field when a GCLK_DROP error * - * happens. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_hdr1_u { - bdrkreg_t lb_error_hdr1_regval; - struct { - bdrkreg_t eh_command : 7; - bdrkreg_t eh_reserved_5 : 1; - bdrkreg_t eh_suppl : 11; - bdrkreg_t eh_reserved_4 : 1; - bdrkreg_t eh_source : 11; - bdrkreg_t eh_reserved_3 : 1; - bdrkreg_t eh_err_type : 4; - bdrkreg_t eh_reserved_2 : 4; - bdrkreg_t eh_overrun : 1; - bdrkreg_t eh_reserved_1 : 3; - bdrkreg_t eh_valid : 1; - bdrkreg_t eh_reserved : 19; - } lb_error_hdr1_fld_s; -} lb_error_hdr1_u_t; - -#else - -typedef union lb_error_hdr1_u { - bdrkreg_t lb_error_hdr1_regval; - struct { - bdrkreg_t eh_reserved : 19; - bdrkreg_t eh_valid : 1; - bdrkreg_t eh_reserved_1 : 3; - bdrkreg_t eh_overrun : 1; - bdrkreg_t eh_reserved_2 : 4; - bdrkreg_t eh_err_type : 4; - bdrkreg_t eh_reserved_3 : 1; - bdrkreg_t eh_source : 11; - bdrkreg_t eh_reserved_4 : 1; - bdrkreg_t eh_suppl : 11; - bdrkreg_t eh_reserved_5 : 1; - bdrkreg_t eh_command : 7; - } lb_error_hdr1_fld_s; -} lb_error_hdr1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contents of the Address field from header flit of first packet * - * that causes an error. This register is not relevant when a * - * GCLK_DROP error occurs. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_error_hdr2_u { - bdrkreg_t lb_error_hdr2_regval; - struct { - bdrkreg_t eh_address : 38; - bdrkreg_t eh_reserved : 26; - } lb_error_hdr2_fld_s; -} lb_error_hdr2_u_t; - -#else - -typedef union lb_error_hdr2_u { - bdrkreg_t lb_error_hdr2_regval; - struct { - bdrkreg_t eh_reserved : 26; - bdrkreg_t eh_address : 38; - } lb_error_hdr2_fld_s; -} lb_error_hdr2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register accompanies the LB_ERROR_HDR1 and * - * LB_ERROR_HDR2 registers. The LB updates the value in this * - * register when an incoming packet with a data flit causes an error * - * while VALID==0 in the LB_ERROR_HDR1 register. This register * - * retains the contents of the data flit from the incoming packet * - * that caused the error. This register is relevant for the following * - * types of errors: * - *
    * - *
      * - *
        * - *
          * - *
            * - *
          • RQ_BAD_LINVAL for a LINVAL request. * - *
          • RQ_BAD_ADDR for a normal or vector PIO request. * - *
          • RP_BAD_DATA for a vector PIO reply. * - *
          • RQ_BAD DATA for an incoming request with data. * - *
          • RP_LONG for a vector PIO reply. * - *
          • RQ_LONG for an incoming request with expected data. * - *
            * - * In the case of RQ_BAD_LINVAL, the register retains the 64-bit data * - * value that followed the header flit. In the case of RQ_BAD_ADDR * - * or RQ_BAD_DATA, the register retains the incoming packet's 64-bit * - * data value (i.e., 2nd flit in the packet for a normal PIO write or * - * an LINVAL, 3rd flit for a vector PIO read or write). In the case * - * of RP_BAD_DATA, the register retains the 64-bit data value in the * - * 3rd flit of the packet. When a RP_LONG or RQ_LONG error occurs, * - * the LB loads the LB_ERROR_DATA register with the contents of the * - * expected data flit (i.e., the 3rd flit in the packet for a vector * - * PIO request or reply, the 2nd flit for other packets), if any. The * - * contents of the LB_ERROR_DATA register are undefined after a * - * RP_SHORT, RQ_SHORT, RP_BAD_CMD or RQ_BAD_CMD error. The contents * - * of the LB_ERROR_DATA register are also undefined after an incoming * - * normal PIO read request which encounters a RQ_LONG error. * - * * - ************************************************************************/ - - - - -typedef union lb_error_data_u { - bdrkreg_t lb_error_data_regval; - struct { - bdrkreg_t ed_data : 64; - } lb_error_data_fld_s; -} lb_error_data_u_t; - - - - -/************************************************************************ - * * - * This register enables software to control what internal Bedrock * - * signals are visible on the chip's debug pins. The LB provides the * - * 6-bit value in this register to Bedrock's DEBUG unit. The JTAG * - * unit provides a similar 6-bit selection input to the DEBUG unit, * - * along with another signal that tells the DEBUG unit whether to use * - * the selection signal from the LB or the JTAG unit. For a * - * description of the menu of choices for debug signals, refer to the * - * documentation for the DEBUG unit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_debug_select_u { - bdrkreg_t lb_debug_select_regval; - struct { - bdrkreg_t ds_debug_sel : 6; - bdrkreg_t ds_reserved : 58; - } lb_debug_select_fld_s; -} lb_debug_select_u_t; - -#else - -typedef union lb_debug_select_u { - bdrkreg_t lb_debug_select_regval; - struct { - bdrkreg_t ds_reserved : 58; - bdrkreg_t ds_debug_sel : 6; - } lb_debug_select_fld_s; -} lb_debug_select_u_t; - -#endif - - - - -/************************************************************************ - * * - * A PIO read from this register returns the 32-bit value that is * - * currently on the Bedrock chip's debug pins. This register allows * - * software to observe debug pin output values which do not change * - * frequently (i.e., they remain constant over a period of many * - * cycles). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_debug_pins_u { - bdrkreg_t lb_debug_pins_regval; - struct { - bdrkreg_t dp_debug_pins : 32; - bdrkreg_t dp_reserved : 32; - } lb_debug_pins_fld_s; -} lb_debug_pins_u_t; - -#else - -typedef union lb_debug_pins_u { - bdrkreg_t lb_debug_pins_regval; - struct { - bdrkreg_t dp_reserved : 32; - bdrkreg_t dp_debug_pins : 32; - } lb_debug_pins_fld_s; -} lb_debug_pins_u_t; - -#endif - - - - -/************************************************************************ - * * - * The LB unit provides the PI0 and PI1 units with a real-time clock * - * signal. The LB can generate this signal itself, based on the * - * Bedrock chip's system clock which the LB receives as an input. * - * Alternatively, the LB can filter a global clock signal which it * - * receives as an input and provide the filtered version to PI0 and * - * PI1. The user can program the LB_RT_LOCAL_CTRL register to choose * - * the source of the real-time clock. If the user chooses to generate * - * the real-time clock internally within the LB, then the user can * - * specify the period for the real-time clock signal. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rt_local_ctrl_u { - bdrkreg_t lb_rt_local_ctrl_regval; - struct { - bdrkreg_t rlc_gclk_enable : 1; - bdrkreg_t rlc_reserved_4 : 3; - bdrkreg_t rlc_max_count : 10; - bdrkreg_t rlc_reserved_3 : 2; - bdrkreg_t rlc_gclk_counter : 10; - bdrkreg_t rlc_reserved_2 : 2; - bdrkreg_t rlc_gclk : 1; - bdrkreg_t rlc_reserved_1 : 3; - bdrkreg_t rlc_use_internal : 1; - bdrkreg_t rlc_reserved : 31; - } lb_rt_local_ctrl_fld_s; -} lb_rt_local_ctrl_u_t; - -#else - -typedef union lb_rt_local_ctrl_u { - bdrkreg_t lb_rt_local_ctrl_regval; - struct { - bdrkreg_t rlc_reserved : 31; - bdrkreg_t rlc_use_internal : 1; - bdrkreg_t rlc_reserved_1 : 3; - bdrkreg_t rlc_gclk : 1; - bdrkreg_t rlc_reserved_2 : 2; - bdrkreg_t rlc_gclk_counter : 10; - bdrkreg_t rlc_reserved_3 : 2; - bdrkreg_t rlc_max_count : 10; - bdrkreg_t rlc_reserved_4 : 3; - bdrkreg_t rlc_gclk_enable : 1; - } lb_rt_local_ctrl_fld_s; -} lb_rt_local_ctrl_u_t; - -#endif - - - - -/************************************************************************ - * * - * When the value of the USE_INTERNAL field in the LB_RT_LOCAL_CTRL * - * register is 0, the LB filters an incoming global clock signal and * - * provides the result to PI0 and PI1 for their real-time clock * - * inputs. The LB can perform either simple filtering or complex * - * filtering, depending on the value of the MASK_ENABLE bit. For the * - * simple filtering option, the LB merely removes glitches from the * - * incoming global clock; if the global clock goes high (or low) for * - * only a single cycle, the LB considers it to be a glitch and does * - * not pass it through to PI0 and PI1. For the complex filtering * - * option, the LB expects positive edges on the incoming global clock * - * to be spaced at fairly regular intervals and it looks for them at * - * these times; the LB keeps track of unexpected or missing positive * - * edges, and it generates an edge itself whenever the incoming * - * global clock apparently misses an edge. For each filtering option, * - * the real-time clock which the LB provides to PI0 and PI1 is not * - * necessarily a square wave; when a positive edge happens, the * - * real-time clock stays high for (2*MAX_COUNT+1-OFFSET)/2 cycles of * - * the LB's system clock, and then is low until the next positive * - * edge. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_rt_filter_ctrl_u { - bdrkreg_t lb_rt_filter_ctrl_regval; - struct { - bdrkreg_t rfc_offset : 5; - bdrkreg_t rfc_reserved_4 : 3; - bdrkreg_t rfc_mask_counter : 12; - bdrkreg_t rfc_mask_enable : 1; - bdrkreg_t rfc_reserved_3 : 3; - bdrkreg_t rfc_dropout_counter : 10; - bdrkreg_t rfc_reserved_2 : 2; - bdrkreg_t rfc_dropout_thresh : 10; - bdrkreg_t rfc_reserved_1 : 2; - bdrkreg_t rfc_error_counter : 10; - bdrkreg_t rfc_reserved : 6; - } lb_rt_filter_ctrl_fld_s; -} lb_rt_filter_ctrl_u_t; - -#else - -typedef union lb_rt_filter_ctrl_u { - bdrkreg_t lb_rt_filter_ctrl_regval; - struct { - bdrkreg_t rfc_reserved : 6; - bdrkreg_t rfc_error_counter : 10; - bdrkreg_t rfc_reserved_1 : 2; - bdrkreg_t rfc_dropout_thresh : 10; - bdrkreg_t rfc_reserved_2 : 2; - bdrkreg_t rfc_dropout_counter : 10; - bdrkreg_t rfc_reserved_3 : 3; - bdrkreg_t rfc_mask_enable : 1; - bdrkreg_t rfc_mask_counter : 12; - bdrkreg_t rfc_reserved_4 : 3; - bdrkreg_t rfc_offset : 5; - } lb_rt_filter_ctrl_fld_s; -} lb_rt_filter_ctrl_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is a scratch register that is reset to 0x0. At the * - * normal address, the register is a simple storage location. At the * - * Write-If-Zero address, the register accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg0_u { - bdrkreg_t lb_scratch_reg0_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg0_fld_s; -} lb_scratch_reg0_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg1_u { - bdrkreg_t lb_scratch_reg1_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg1_fld_s; -} lb_scratch_reg1_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg2_u { - bdrkreg_t lb_scratch_reg2_regval; - struct { - bdrkreg_t sr_scratch_bits : 64; - } lb_scratch_reg2_fld_s; -} lb_scratch_reg2_u_t; - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg3_u { - bdrkreg_t lb_scratch_reg3_regval; - struct { - bdrkreg_t sr_scratch_bit : 1; - bdrkreg_t sr_reserved : 63; - } lb_scratch_reg3_fld_s; -} lb_scratch_reg3_u_t; - -#else - -typedef union lb_scratch_reg3_u { - bdrkreg_t lb_scratch_reg3_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_scratch_bit : 1; - } lb_scratch_reg3_fld_s; -} lb_scratch_reg3_u_t; - -#endif - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg4_u { - bdrkreg_t lb_scratch_reg4_regval; - struct { - bdrkreg_t sr_scratch_bit : 1; - bdrkreg_t sr_reserved : 63; - } lb_scratch_reg4_fld_s; -} lb_scratch_reg4_u_t; - -#else - -typedef union lb_scratch_reg4_u { - bdrkreg_t lb_scratch_reg4_regval; - struct { - bdrkreg_t sr_reserved : 63; - bdrkreg_t sr_scratch_bit : 1; - } lb_scratch_reg4_fld_s; -} lb_scratch_reg4_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is a scratch register that is reset to 0x0. At the * - * normal address, the register is a simple storage location. At the * - * Write-If-Zero address, the register accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg0_wz_u { - bdrkreg_t lb_scratch_reg0_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg0_wz_fld_s; -} lb_scratch_reg0_wz_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg1_wz_u { - bdrkreg_t lb_scratch_reg1_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg1_wz_fld_s; -} lb_scratch_reg1_wz_u_t; - - - - -/************************************************************************ - * * - * These registers are scratch registers that are not reset. At a * - * register's normal address, it is a simple storage location. At a * - * register's Write-If-Zero address, it accepts a new value from a * - * write operation only if the current value is zero. * - * * - ************************************************************************/ - - - - -typedef union lb_scratch_reg2_wz_u { - bdrkreg_t lb_scratch_reg2_wz_regval; - struct { - bdrkreg_t srw_scratch_bits : 64; - } lb_scratch_reg2_wz_fld_s; -} lb_scratch_reg2_wz_u_t; - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg3_rz_u { - bdrkreg_t lb_scratch_reg3_rz_regval; - struct { - bdrkreg_t srr_scratch_bit : 1; - bdrkreg_t srr_reserved : 63; - } lb_scratch_reg3_rz_fld_s; -} lb_scratch_reg3_rz_u_t; - -#else - -typedef union lb_scratch_reg3_rz_u { - bdrkreg_t lb_scratch_reg3_rz_regval; - struct { - bdrkreg_t srr_reserved : 63; - bdrkreg_t srr_scratch_bit : 1; - } lb_scratch_reg3_rz_fld_s; -} lb_scratch_reg3_rz_u_t; - -#endif - - - - -/************************************************************************ - * * - * These one-bit registers are scratch registers. At a register's * - * normal address, it is a simple storage location. At a register's * - * Read-Set-If-Zero address, it returns the original contents and * - * sets the bit if the original value is zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_scratch_reg4_rz_u { - bdrkreg_t lb_scratch_reg4_rz_regval; - struct { - bdrkreg_t srr_scratch_bit : 1; - bdrkreg_t srr_reserved : 63; - } lb_scratch_reg4_rz_fld_s; -} lb_scratch_reg4_rz_u_t; - -#else - -typedef union lb_scratch_reg4_rz_u { - bdrkreg_t lb_scratch_reg4_rz_regval; - struct { - bdrkreg_t srr_reserved : 63; - bdrkreg_t srr_scratch_bit : 1; - } lb_scratch_reg4_rz_fld_s; -} lb_scratch_reg4_rz_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains vector PIO parameters. A * - * write to this register triggers the LB to send out a vector PIO * - * request packet. Immediately after servicing a write request to the * - * LB_VECTOR_PARMS register, the LB sends back a reply (i.e., the LB * - * doesn't wait for the vector PIO operation to finish first). Three * - * LB registers provide the contents for an outgoing vector PIO * - * request packet. Software should wait until the BUSY bit in * - * LB_VECTOR_PARMS is clear and then initialize all three of these * - * registers before initiating a vector PIO operation. The three * - * vector PIO registers are: * - * LB_VECTOR_ROUTE * - * LB_VECTOR_DATA * - * LB_VECTOR_PARMS (should be written last) * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_parms_u { - bdrkreg_t lb_vector_parms_regval; - struct { - bdrkreg_t vp_type : 1; - bdrkreg_t vp_reserved_2 : 2; - bdrkreg_t vp_address : 21; - bdrkreg_t vp_reserved_1 : 8; - bdrkreg_t vp_write_id : 8; - bdrkreg_t vp_pio_id : 11; - bdrkreg_t vp_reserved : 12; - bdrkreg_t vp_busy : 1; - } lb_vector_parms_fld_s; -} lb_vector_parms_u_t; - -#else - -typedef union lb_vector_parms_u { - bdrkreg_t lb_vector_parms_regval; - struct { - bdrkreg_t vp_busy : 1; - bdrkreg_t vp_reserved : 12; - bdrkreg_t vp_pio_id : 11; - bdrkreg_t vp_write_id : 8; - bdrkreg_t vp_reserved_1 : 8; - bdrkreg_t vp_address : 21; - bdrkreg_t vp_reserved_2 : 2; - bdrkreg_t vp_type : 1; - } lb_vector_parms_fld_s; -} lb_vector_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the vector PIO route. This is one of the 3 * - * vector PIO control registers. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_route_u { - bdrkreg_t lb_vector_route_regval; - struct { - bdrkreg_t vr_vector : 64; - } lb_vector_route_fld_s; -} lb_vector_route_u_t; - - - - -/************************************************************************ - * * - * This register contains the vector PIO write data. This is one of * - * the 3 vector PIO control registers. The contents of this register * - * also provide the data value to be sent in outgoing vector PIO read * - * requests and vector PIO write replies. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_data_u { - bdrkreg_t lb_vector_data_regval; - struct { - bdrkreg_t vd_write_data : 64; - } lb_vector_data_fld_s; -} lb_vector_data_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains the vector PIO return status. * - * Software should clear this register before launching a vector PIO * - * request from the LB. The LB will not modify this register's value * - * if an incoming reply packet encounters any kind of error. If an * - * incoming reply packet does not encounter an error but the * - * STATUS_VALID bit is already set, then the LB sets the OVERRUN bit * - * and leaves the other fields unchanged. The LB updates the values * - * of the SOURCE, PIO_ID, WRITE_ID, ADDRESS and TYPE fields only if * - * an incoming vector PIO reply packet does not encounter an error * - * and the STATUS_VALID bit is clear; at the same time, the LB sets * - * the STATUS_VALID bit and will also update the LB_VECTOR_RETURN and * - * LB_VECTOR_READ_DATA registers. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_status_u { - bdrkreg_t lb_vector_status_regval; - struct { - bdrkreg_t vs_type : 3; - bdrkreg_t vs_address : 21; - bdrkreg_t vs_reserved : 8; - bdrkreg_t vs_write_id : 8; - bdrkreg_t vs_pio_id : 11; - bdrkreg_t vs_source : 11; - bdrkreg_t vs_overrun : 1; - bdrkreg_t vs_status_valid : 1; - } lb_vector_status_fld_s; -} lb_vector_status_u_t; - -#else - -typedef union lb_vector_status_u { - bdrkreg_t lb_vector_status_regval; - struct { - bdrkreg_t vs_status_valid : 1; - bdrkreg_t vs_overrun : 1; - bdrkreg_t vs_source : 11; - bdrkreg_t vs_pio_id : 11; - bdrkreg_t vs_write_id : 8; - bdrkreg_t vs_reserved : 8; - bdrkreg_t vs_address : 21; - bdrkreg_t vs_type : 3; - } lb_vector_status_fld_s; -} lb_vector_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the return vector PIO route. The LB will * - * not modify this register's value if an incoming reply packet * - * encounters any kind of error. The LB also will not modify this * - * register's value if the STATUS_VALID bit in the LB_VECTOR_STATUS * - * register is set when it receives an incoming vector PIO reply. The * - * LB stores an incoming vector PIO reply packet's vector route flit * - * in this register only if the packet does not encounter an error * - * and the STATUS_VALID bit is clear. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_return_u { - bdrkreg_t lb_vector_return_regval; - struct { - bdrkreg_t vr_return_vector : 64; - } lb_vector_return_fld_s; -} lb_vector_return_u_t; - - - - -/************************************************************************ - * * - * This register contains the vector PIO read data, if any. The LB * - * will not modify this register's value if an incoming reply packet * - * encounters any kind of error. The LB also will not modify this * - * register's value if the STATUS_VALID bit in the LB_VECTOR_STATUS * - * register is set when it receives an incoming vector PIO reply. The * - * LB stores an incoming vector PIO reply packet's data flit in this * - * register only if the packet does not encounter an error and the * - * STATUS_VALID bit is clear. * - * * - ************************************************************************/ - - - - -typedef union lb_vector_read_data_u { - bdrkreg_t lb_vector_read_data_regval; - struct { - bdrkreg_t vrd_read_data : 64; - } lb_vector_read_data_fld_s; -} lb_vector_read_data_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains the vector PIO return status. * - * Software should clear this register before launching a vector PIO * - * request from the LB. The LB will not modify this register's value * - * if an incoming reply packet encounters any kind of error. If an * - * incoming reply packet does not encounter an error but the * - * STATUS_VALID bit is already set, then the LB sets the OVERRUN bit * - * and leaves the other fields unchanged. The LB updates the values * - * of the SOURCE, PIO_ID, WRITE_ID, ADDRESS and TYPE fields only if * - * an incoming vector PIO reply packet does not encounter an error * - * and the STATUS_VALID bit is clear; at the same time, the LB sets * - * the STATUS_VALID bit and will also update the LB_VECTOR_RETURN and * - * LB_VECTOR_READ_DATA registers. * - * * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union lb_vector_status_clear_u { - bdrkreg_t lb_vector_status_clear_regval; - struct { - bdrkreg_t vsc_type : 3; - bdrkreg_t vsc_address : 21; - bdrkreg_t vsc_reserved : 8; - bdrkreg_t vsc_write_id : 8; - bdrkreg_t vsc_pio_id : 11; - bdrkreg_t vsc_source : 11; - bdrkreg_t vsc_overrun : 1; - bdrkreg_t vsc_status_valid : 1; - } lb_vector_status_clear_fld_s; -} lb_vector_status_clear_u_t; - -#else - -typedef union lb_vector_status_clear_u { - bdrkreg_t lb_vector_status_clear_regval; - struct { - bdrkreg_t vsc_status_valid : 1; - bdrkreg_t vsc_overrun : 1; - bdrkreg_t vsc_source : 11; - bdrkreg_t vsc_pio_id : 11; - bdrkreg_t vsc_write_id : 8; - bdrkreg_t vsc_reserved : 8; - bdrkreg_t vsc_address : 21; - bdrkreg_t vsc_type : 3; - } lb_vector_status_clear_fld_s; -} lb_vector_status_clear_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBLB_H */ diff -Nru a/include/asm-ia64/sn/sn1/hublb_next.h b/include/asm-ia64/sn/sn1/hublb_next.h --- a/include/asm-ia64/sn/sn1/hublb_next.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,109 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBLB_NEXT_H -#define _ASM_IA64_SN_SN1_HUBLB_NEXT_H - -/********************************************************************** - - This contains some mask and shift values for LB defined as required - for compatibility. - - **********************************************************************/ - -#define LRI_SYSTEM_SIZE_SHFT 46 -#define LRI_SYSTEM_SIZE_MASK (UINT64_CAST 0x3 << LRI_SYSTEM_SIZE_SHFT) -#define LRI_NODEID_SHFT 32 -#define LRI_NODEID_MASK (UINT64_CAST 0xff << LRI_NODEID_SHFT)/* Node ID */ -#define LRI_CHIPID_SHFT 12 -#define LRI_CHIPID_MASK (UINT64_CAST 0xffff << LRI_CHIPID_SHFT) /* should be 0x3012 */ -#define LRI_REV_SHFT 28 -#define LRI_REV_MASK (UINT64_CAST 0xf << LRI_REV_SHFT)/* Chip revision */ - -/* Values for LRI_SYSTEM_SIZE */ -#define SYSTEM_SIZE_INVALID 0x3 -#define SYSTEM_SIZE_NMODE 0x2 -#define SYSTEM_SIZE_COARSE 0x1 -#define SYSTEM_SIZE_SMALL 0x0 - -/* In fine mode, each node is a region. In coarse mode, there are - * 2 nodes per region. In N-mode, there are 4 nodes per region. */ -#define NASID_TO_FINEREG_SHFT 0 -#define NASID_TO_COARSEREG_SHFT 1 -#define NASID_TO_NMODEREG_SHFT 2 - -#define LR_LOCALRESET (UINT64_CAST 1) -/* - * LB_VECTOR_PARMS mask and shift definitions. - * TYPE may be any of the first four PIOTYPEs defined under NI_VECTOR_STATUS. - */ - -#define LVP_BUSY (UINT64_CAST 1 << 63) -#define LVP_PIOID_SHFT 40 -#define LVP_PIOID_MASK (UINT64_CAST 0x7ff << 40) -#define LVP_WRITEID_SHFT 32 -#define LVP_WRITEID_MASK (UINT64_CAST 0xff << 32) -#define LVP_ADDRESS_MASK (UINT64_CAST 0xfffff8) /* Bits 23:3 */ -#define LVP_TYPE_SHFT 0 -#define LVP_TYPE_MASK (UINT64_CAST 0x3) - -/* LB_VECTOR_STATUS mask and shift definitions */ - -#define LVS_VALID (UINT64_CAST 1 << 63) -#define LVS_OVERRUN (UINT64_CAST 1 << 62) -#define LVS_TARGET_SHFT 51 -#define LVS_TARGET_MASK (UINT64_CAST 0x7ff << 51) -#define LVS_PIOID_SHFT 40 -#define LVS_PIOID_MASK (UINT64_CAST 0x7ff << 40) -#define LVS_WRITEID_SHFT 32 -#define LVS_WRITEID_MASK (UINT64_CAST 0xff << 32) -#define LVS_ADDRESS_MASK (UINT64_CAST 0xfffff8) /* Bits 23:3 */ -#define LVS_TYPE_SHFT 0 -#define LVS_TYPE_MASK (UINT64_CAST 0x7) -#define LVS_ERROR_MASK (UINT64_CAST 0x4) /* bit set means error */ - -/* LB_RT_LOCAL_CTRL mask and shift definitions */ - -#define LRLC_USE_INT_SHFT 32 -#define LRLC_USE_INT_MASK (UINT64_CAST 1 << 32) -#define LRLC_USE_INT (UINT64_CAST 1 << 32) -#define LRLC_GCLK_SHFT 28 -#define LRLC_GCLK_MASK (UINT64_CAST 1 << 28) -#define LRLC_GCLK (UINT64_CAST 1 << 28) -#define LRLC_GCLK_COUNT_SHFT 16 -#define LRLC_GCLK_COUNT_MASK (UINT64_CAST 0x3ff << 16) -#define LRLC_MAX_COUNT_SHFT 4 -#define LRLC_MAX_COUNT_MASK (UINT64_CAST 0x3ff << 4) -#define LRLC_GCLK_EN_SHFT 0 -#define LRLC_GCLK_EN_MASK (UINT64_CAST 1) -#define LRLC_GCLK_EN (UINT64_CAST 1) - -/* LB_NODES_ABSENT mask and shift definitions */ -#define LNA_VALID_SHFT 15 -#define LNA_VALID_MASK (UINT64_CAST 1 << LNA_VALID_SHFT) -#define LNA_VALID (UINT64_CAST 1 << LNA_VALID_SHFT) -#define LNA_NODE_SHFT 0 -#define LNA_NODE_MASK (UINT64_CAST 0xff << LNA_NODE_SHFT) - -/* LB_NODES_ABSENT has 4 identical sub-registers, on 16-bit boundaries */ -#define LNA_ENTRY_SHFT 16 -#define LNA_MAX_ENTRIES 4 -#define LNA_ADD(_reg, _n) ((_reg) = (_reg) << LNA_ENTRY_SHFT | \ - LNA_VALID | (_n) << LNA_NODE_SHFT) - -#define PIOTYPE_READ 0 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_WRITE 1 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_UNDEFINED 2 /* VECTOR_PARMS and VECTOR_STATUS */ -/* XXX IP35 doesn't support vector exchange: scr. regs. do locks directly */ -#define PIOTYPE_EXCHANGE 3 /* VECTOR_PARMS and VECTOR_STATUS */ -#define PIOTYPE_ADDR_ERR 4 /* VECTOR_STATUS only */ -#define PIOTYPE_CMD_ERR 5 /* VECTOR_STATUS only */ -#define PIOTYPE_PROT_ERR 6 /* VECTOR_STATUS only */ -#define PIOTYPE_UNKNOWN 7 /* VECTOR_STATUS only */ - -#endif /* _ASM_IA64_SN_SN1_HUBLB_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubmd.h b/include/asm-ia64/sn/sn1/hubmd.h --- a/include/asm-ia64/sn/sn1/hubmd.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2476 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBMD_H -#define _ASM_IA64_SN_SN1_HUBMD_H - - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define MD_CURRENT_CELL 0x00780000 /* - * BDDIR, LREG, LBOOT, - * RREG, RBOOT - * protection and mask - * for using Local - * Access protection. - */ - - - -#define MD_MEMORY_CONFIG 0x00780008 /* - * Memory/Directory - * DIMM control - */ - - - -#define MD_ARBITRATION_CONTROL 0x00780010 /* - * Arbitration - * Parameters - */ - - - -#define MD_MIG_CONFIG 0x00780018 /* - * Page Migration - * control - */ - - - -#define MD_FANDOP_CAC_STAT0 0x00780020 /* - * Fetch-and-op cache - * 0 status - */ - - - -#define MD_FANDOP_CAC_STAT1 0x00780028 /* - * Fetch-and-op cache - * 1 status - */ - - - -#define MD_MISC0_ERROR 0x00780040 /* - * Miscellaneous MD - * error - */ - - - -#define MD_MISC1_ERROR 0x00780048 /* - * Miscellaneous MD - * error - */ - - - -#define MD_MISC1_ERROR_CLR 0x00780058 /* - * Miscellaneous MD - * error clear - */ - - - -#define MD_OUTGOING_RP_QUEUE_SIZE 0x00780060 /* - * MD outgoing reply - * queues sizing - */ - - - -#define MD_PERF_SEL0 0x00790000 /* - * Selects events - * monitored by - * MD_PERF_CNT0 - */ - - - -#define MD_PERF_SEL1 0x00790008 /* - * Selects events - * monitored by - * MD_PERF_CNT1 - */ - - - -#define MD_PERF_CNT0 0x00790010 /* - * Performance counter - * 0 - */ - - - -#define MD_PERF_CNT1 0x00790018 /* - * Performance counter - * 1 - */ - - - -#define MD_REFRESH_CONTROL 0x007A0000 /* - * Memory/Directory - * refresh control - */ - - - -#define MD_JUNK_BUS_TIMING 0x007A0008 /* Junk Bus Timing */ - - - -#define MD_LED0 0x007A0010 /* Reads of 8-bit LED0 */ - - - -#define MD_LED1 0x007A0018 /* Reads of 8-bit LED1 */ - - - -#define MD_LED2 0x007A0020 /* Reads of 8-bit LED2 */ - - - -#define MD_LED3 0x007A0028 /* Reads of 8-bit LED3 */ - - - -#define MD_BIST_CTL 0x007A0030 /* - * BIST general - * control - */ - - - -#define MD_BIST_DATA 0x007A0038 /* - * BIST initial data - * pattern and - * variation control - */ - - - -#define MD_BIST_AB_ERR_ADDR 0x007A0040 /* BIST error address */ - - - -#define MD_BIST_STATUS 0x007A0048 /* BIST status */ - - - -#define MD_IB_DEBUG 0x007A0060 /* IB debug select */ - - - -#define MD_DIR_CONFIG 0x007C0000 /* - * Directory mode - * control - */ - - - -#define MD_DIR_ERROR 0x007C0010 /* - * Directory DIMM - * error - */ - - - -#define MD_DIR_ERROR_CLR 0x007C0018 /* - * Directory DIMM - * error clear - */ - - - -#define MD_PROTOCOL_ERROR 0x007C0020 /* - * Directory protocol - * error - */ - - - -#define MD_PROTOCOL_ERR_CLR 0x007C0028 /* - * Directory protocol - * error clear - */ - - - -#define MD_MIG_CANDIDATE 0x007C0030 /* - * Page migration - * candidate - */ - - - -#define MD_MIG_CANDIDATE_CLR 0x007C0038 /* - * Page migration - * candidate clear - */ - - - -#define MD_MIG_DIFF_THRESH 0x007C0040 /* - * Page migration - * count difference - * threshold - */ - - - -#define MD_MIG_VALUE_THRESH 0x007C0048 /* - * Page migration - * count absolute - * threshold - */ - - - -#define MD_OUTGOING_RQ_QUEUE_SIZE 0x007C0050 /* - * MD outgoing request - * queues sizing - */ - - - -#define MD_BIST_DB_ERR_DATA 0x007C0058 /* - * BIST directory - * error data - */ - - - -#define MD_DB_DEBUG 0x007C0060 /* DB debug select */ - - - -#define MD_MB_ECC_CONFIG 0x007E0000 /* - * Data ECC - * Configuration - */ - - - -#define MD_MEM_ERROR 0x007E0010 /* Memory DIMM error */ - - - -#define MD_MEM_ERROR_CLR 0x007E0018 /* - * Memory DIMM error - * clear - */ - - - -#define MD_BIST_MB_ERR_DATA_0 0x007E0020 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_1 0x007E0028 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_2 0x007E0030 /* - * BIST memory error - * data - */ - - - -#define MD_BIST_MB_ERR_DATA_3 0x007E0038 /* - * BIST memory error - * data - */ - - - -#define MD_MB_DEBUG 0x007E0040 /* MB debug select */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This register shows which regions are in the current * - * cell. If a region has its bit set in this register, then it uses * - * the Local Access protection in the directory instead of the * - * separate per-region protection (which would cause a small * - * performance penalty). In addition, writeback and write reply * - * commands from outside the current cell will always check the * - * directory protection before writing data to memory. Writeback and * - * write reply commands from inside the current cell will write * - * memory regardless of the protection value. * - * This register is also used as the access-rights bit-vector for * - * most of the ASIC-special (HSpec) portion of the address space. It * - * covers the BDDIR, LREG, LBOOT, RREG, and RBOOT spaces. It does not * - * cover the UALIAS and BDECC spaces, as they are covered by the * - * protection in the directory. If a bit in the bit-vector is set, * - * the region corresponding to that bit has read/write permission on * - * these spaces. If the bit is clear, then that region has read-only * - * access to these spaces (except for LREG/RREG which have no access * - * when the bit is clear). * - * The granularity of a region is set by the REGION_SIZE register in * - * the NI local register space. * - * NOTE: This means that no processor outside the current cell can * - * write into the BDDIR, LREG, LBOOT, RREG, or RBOOT spaces. * - * * - ************************************************************************/ - - - - -typedef union md_current_cell_u { - bdrkreg_t md_current_cell_regval; - struct { - bdrkreg_t cc_hspec_prot : 64; - } md_current_cell_fld_s; -} md_current_cell_u_t; - - - - -/************************************************************************ - * * - * Description: This register contains three sets of information. * - * The first set describes the size and configuration of DIMMs that * - * are plugged into a system, the second set controls which set of * - * protection checks are performed on each access and the third set * - * controls various DDR SDRAM timing parameters. * - * In order to config a DIMM bank, three fields must be initialized: * - * BANK_SIZE, DRAM_WIDTH, and BANK_ENABLE. The BANK_SIZE field sets * - * the address range that the MD unit will accept for that DIMM bank. * - * All addresses larger than the specified size will return errors on * - * access. In order to read from a DIMM bank, Bedrock must know * - * whether or not the bank contains x4 or x8/x16 DRAM. The operating * - * system must query the System Controller for this information and * - * then set the DRAM_WIDTH field accordingly. The BANK_ENABLE field * - * can be used to individually enable the two physical banks located * - * on each DIMM bank. * - * The contents of this register are preserved through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_memory_config_u { - bdrkreg_t md_memory_config_regval; - struct { - bdrkreg_t mc_dimm0_bank_enable : 2; - bdrkreg_t mc_reserved_7 : 1; - bdrkreg_t mc_dimm0_dram_width : 1; - bdrkreg_t mc_dimm0_bank_size : 4; - bdrkreg_t mc_dimm1_bank_enable : 2; - bdrkreg_t mc_reserved_6 : 1; - bdrkreg_t mc_dimm1_dram_width : 1; - bdrkreg_t mc_dimm1_bank_size : 4; - bdrkreg_t mc_dimm2_bank_enable : 2; - bdrkreg_t mc_reserved_5 : 1; - bdrkreg_t mc_dimm2_dram_width : 1; - bdrkreg_t mc_dimm2_bank_size : 4; - bdrkreg_t mc_dimm3_bank_enable : 2; - bdrkreg_t mc_reserved_4 : 1; - bdrkreg_t mc_dimm3_dram_width : 1; - bdrkreg_t mc_dimm3_bank_size : 4; - bdrkreg_t mc_dimm0_sel : 2; - bdrkreg_t mc_reserved_3 : 10; - bdrkreg_t mc_cc_enable : 1; - bdrkreg_t mc_io_prot_en : 1; - bdrkreg_t mc_io_prot_ignore : 1; - bdrkreg_t mc_cpu_prot_ignore : 1; - bdrkreg_t mc_db_neg_edge : 1; - bdrkreg_t mc_phase_delay : 1; - bdrkreg_t mc_delay_mux_sel : 2; - bdrkreg_t mc_sample_time : 2; - bdrkreg_t mc_reserved_2 : 2; - bdrkreg_t mc_mb_neg_edge : 3; - bdrkreg_t mc_reserved_1 : 1; - bdrkreg_t mc_rcd_config : 1; - bdrkreg_t mc_rp_config : 1; - bdrkreg_t mc_reserved : 2; - } md_memory_config_fld_s; -} md_memory_config_u_t; - -#else - -typedef union md_memory_config_u { - bdrkreg_t md_memory_config_regval; - struct { - bdrkreg_t mc_reserved : 2; - bdrkreg_t mc_rp_config : 1; - bdrkreg_t mc_rcd_config : 1; - bdrkreg_t mc_reserved_1 : 1; - bdrkreg_t mc_mb_neg_edge : 3; - bdrkreg_t mc_reserved_2 : 2; - bdrkreg_t mc_sample_time : 2; - bdrkreg_t mc_delay_mux_sel : 2; - bdrkreg_t mc_phase_delay : 1; - bdrkreg_t mc_db_neg_edge : 1; - bdrkreg_t mc_cpu_prot_ignore : 1; - bdrkreg_t mc_io_prot_ignore : 1; - bdrkreg_t mc_io_prot_en : 1; - bdrkreg_t mc_cc_enable : 1; - bdrkreg_t mc_reserved_3 : 10; - bdrkreg_t mc_dimm0_sel : 2; - bdrkreg_t mc_dimm3_bank_size : 4; - bdrkreg_t mc_dimm3_dram_width : 1; - bdrkreg_t mc_reserved_4 : 1; - bdrkreg_t mc_dimm3_bank_enable : 2; - bdrkreg_t mc_dimm2_bank_size : 4; - bdrkreg_t mc_dimm2_dram_width : 1; - bdrkreg_t mc_reserved_5 : 1; - bdrkreg_t mc_dimm2_bank_enable : 2; - bdrkreg_t mc_dimm1_bank_size : 4; - bdrkreg_t mc_dimm1_dram_width : 1; - bdrkreg_t mc_reserved_6 : 1; - bdrkreg_t mc_dimm1_bank_enable : 2; - bdrkreg_t mc_dimm0_bank_size : 4; - bdrkreg_t mc_dimm0_dram_width : 1; - bdrkreg_t mc_reserved_7 : 1; - bdrkreg_t mc_dimm0_bank_enable : 2; - } md_memory_config_fld_s; -} md_memory_config_u_t; - -#endif - - - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_arbitration_control_u { - bdrkreg_t md_arbitration_control_regval; - struct { - bdrkreg_t ac_reply_guar : 4; - bdrkreg_t ac_write_guar : 4; - bdrkreg_t ac_reserved : 56; - } md_arbitration_control_fld_s; -} md_arbitration_control_u_t; - -#else - -typedef union md_arbitration_control_u { - bdrkreg_t md_arbitration_control_regval; - struct { - bdrkreg_t ac_reserved : 56; - bdrkreg_t ac_write_guar : 4; - bdrkreg_t ac_reply_guar : 4; - } md_arbitration_control_fld_s; -} md_arbitration_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains page migration control fields. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_config_u { - bdrkreg_t md_mig_config_regval; - struct { - bdrkreg_t mc_mig_interval : 10; - bdrkreg_t mc_reserved_2 : 6; - bdrkreg_t mc_mig_node_mask : 8; - bdrkreg_t mc_reserved_1 : 8; - bdrkreg_t mc_mig_enable : 1; - bdrkreg_t mc_reserved : 31; - } md_mig_config_fld_s; -} md_mig_config_u_t; - -#else - -typedef union md_mig_config_u { - bdrkreg_t md_mig_config_regval; - struct { - bdrkreg_t mc_reserved : 31; - bdrkreg_t mc_mig_enable : 1; - bdrkreg_t mc_reserved_1 : 8; - bdrkreg_t mc_mig_node_mask : 8; - bdrkreg_t mc_reserved_2 : 6; - bdrkreg_t mc_mig_interval : 10; - } md_mig_config_fld_s; -} md_mig_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each register contains the valid bit and address of the entry in * - * the fetch-and-op for cache 0 (or 1). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_fandop_cac_stat0_u { - bdrkreg_t md_fandop_cac_stat0_regval; - struct { - bdrkreg_t fcs_reserved_1 : 6; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_valid : 1; - } md_fandop_cac_stat0_fld_s; -} md_fandop_cac_stat0_u_t; - -#else - -typedef union md_fandop_cac_stat0_u { - bdrkreg_t md_fandop_cac_stat0_regval; - struct { - bdrkreg_t fcs_valid : 1; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved_1 : 6; - } md_fandop_cac_stat0_fld_s; -} md_fandop_cac_stat0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each register contains the valid bit and address of the entry in * - * the fetch-and-op for cache 0 (or 1). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_fandop_cac_stat1_u { - bdrkreg_t md_fandop_cac_stat1_regval; - struct { - bdrkreg_t fcs_reserved_1 : 6; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_valid : 1; - } md_fandop_cac_stat1_fld_s; -} md_fandop_cac_stat1_u_t; - -#else - -typedef union md_fandop_cac_stat1_u { - bdrkreg_t md_fandop_cac_stat1_regval; - struct { - bdrkreg_t fcs_valid : 1; - bdrkreg_t fcs_reserved : 30; - bdrkreg_t fcs_addr : 27; - bdrkreg_t fcs_reserved_1 : 6; - } md_fandop_cac_stat1_fld_s; -} md_fandop_cac_stat1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains a number of fields to capture various * - * random memory/directory errors. For each 2-bit field, the LSB * - * indicates that additional information has been captured for the * - * error and the MSB indicates overrun, thus: * - * x1: bits 51...0 of this register contain additional information * - * for the message that caused this error * - * 1x: overrun occurred * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc0_error_u { - bdrkreg_t md_misc0_error_regval; - struct { - bdrkreg_t me_command : 7; - bdrkreg_t me_reserved_4 : 1; - bdrkreg_t me_source : 11; - bdrkreg_t me_reserved_3 : 1; - bdrkreg_t me_suppl : 11; - bdrkreg_t me_reserved_2 : 1; - bdrkreg_t me_virtual_channel : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_tail : 1; - bdrkreg_t me_reserved : 11; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_ill_revision : 2; - } md_misc0_error_fld_s; -} md_misc0_error_u_t; - -#else - -typedef union md_misc0_error_u { - bdrkreg_t md_misc0_error_regval; - struct { - bdrkreg_t me_ill_revision : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_reserved : 11; - bdrkreg_t me_tail : 1; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_virtual_channel : 2; - bdrkreg_t me_reserved_2 : 1; - bdrkreg_t me_suppl : 11; - bdrkreg_t me_reserved_3 : 1; - bdrkreg_t me_source : 11; - bdrkreg_t me_reserved_4 : 1; - bdrkreg_t me_command : 7; - } md_misc0_error_fld_s; -} md_misc0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Address for error captured in MISC0_ERROR. Error valid bits are * - * repeated in both MISC0_ERROR and MISC1_ERROR (allowing them to be * - * read sequentially without missing any errors). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc1_error_u { - bdrkreg_t md_misc1_error_regval; - struct { - bdrkreg_t me_reserved_1 : 3; - bdrkreg_t me_address : 38; - bdrkreg_t me_reserved : 7; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_ill_revision : 2; - } md_misc1_error_fld_s; -} md_misc1_error_u_t; - -#else - -typedef union md_misc1_error_u { - bdrkreg_t md_misc1_error_regval; - struct { - bdrkreg_t me_ill_revision : 2; - bdrkreg_t me_ill_msg : 2; - bdrkreg_t me_long_pack : 2; - bdrkreg_t me_short_pack : 2; - bdrkreg_t me_missing_dv : 2; - bdrkreg_t me_bad_partial_data : 2; - bdrkreg_t me_xb_error : 4; - bdrkreg_t me_reserved : 7; - bdrkreg_t me_address : 38; - bdrkreg_t me_reserved_1 : 3; - } md_misc1_error_fld_s; -} md_misc1_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Address for error captured in MISC0_ERROR. Error valid bits are * - * repeated in both MISC0_ERROR and MISC1_ERROR (allowing them to be * - * read sequentially without missing any errors). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_misc1_error_clr_u { - bdrkreg_t md_misc1_error_clr_regval; - struct { - bdrkreg_t mec_reserved_1 : 3; - bdrkreg_t mec_address : 38; - bdrkreg_t mec_reserved : 7; - bdrkreg_t mec_xb_error : 4; - bdrkreg_t mec_bad_partial_data : 2; - bdrkreg_t mec_missing_dv : 2; - bdrkreg_t mec_short_pack : 2; - bdrkreg_t mec_long_pack : 2; - bdrkreg_t mec_ill_msg : 2; - bdrkreg_t mec_ill_revision : 2; - } md_misc1_error_clr_fld_s; -} md_misc1_error_clr_u_t; - -#else - -typedef union md_misc1_error_clr_u { - bdrkreg_t md_misc1_error_clr_regval; - struct { - bdrkreg_t mec_ill_revision : 2; - bdrkreg_t mec_ill_msg : 2; - bdrkreg_t mec_long_pack : 2; - bdrkreg_t mec_short_pack : 2; - bdrkreg_t mec_missing_dv : 2; - bdrkreg_t mec_bad_partial_data : 2; - bdrkreg_t mec_xb_error : 4; - bdrkreg_t mec_reserved : 7; - bdrkreg_t mec_address : 38; - bdrkreg_t mec_reserved_1 : 3; - } md_misc1_error_clr_fld_s; -} md_misc1_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: The MD no longer allows for arbitrarily sizing the * - * reply queues, so all of the fields in this register are read-only * - * and contain the reset default value of 12 for the MOQHs (for * - * headers) and 24 for the MOQDs (for data). * - * Reading from this register returns the values currently held in * - * the MD's credit counters. Writing to the register resets the * - * counters to the default reset values specified in the table below. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_outgoing_rp_queue_size_u { - bdrkreg_t md_outgoing_rp_queue_size_regval; - struct { - bdrkreg_t orqs_reserved_6 : 8; - bdrkreg_t orqs_moqh_p0_rp_size : 4; - bdrkreg_t orqs_reserved_5 : 4; - bdrkreg_t orqs_moqh_p1_rp_size : 4; - bdrkreg_t orqs_reserved_4 : 4; - bdrkreg_t orqs_moqh_np_rp_size : 4; - bdrkreg_t orqs_reserved_3 : 4; - bdrkreg_t orqs_moqd_pi0_rp_size : 5; - bdrkreg_t orqs_reserved_2 : 3; - bdrkreg_t orqs_moqd_pi1_rp_size : 5; - bdrkreg_t orqs_reserved_1 : 3; - bdrkreg_t orqs_moqd_np_rp_size : 5; - bdrkreg_t orqs_reserved : 11; - } md_outgoing_rp_queue_size_fld_s; -} md_outgoing_rp_queue_size_u_t; - -#else - -typedef union md_outgoing_rp_queue_size_u { - bdrkreg_t md_outgoing_rp_queue_size_regval; - struct { - bdrkreg_t orqs_reserved : 11; - bdrkreg_t orqs_moqd_np_rp_size : 5; - bdrkreg_t orqs_reserved_1 : 3; - bdrkreg_t orqs_moqd_pi1_rp_size : 5; - bdrkreg_t orqs_reserved_2 : 3; - bdrkreg_t orqs_moqd_pi0_rp_size : 5; - bdrkreg_t orqs_reserved_3 : 4; - bdrkreg_t orqs_moqh_np_rp_size : 4; - bdrkreg_t orqs_reserved_4 : 4; - bdrkreg_t orqs_moqh_p1_rp_size : 4; - bdrkreg_t orqs_reserved_5 : 4; - bdrkreg_t orqs_moqh_p0_rp_size : 4; - bdrkreg_t orqs_reserved_6 : 8; - } md_outgoing_rp_queue_size_fld_s; -} md_outgoing_rp_queue_size_u_t; - -#endif - - - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel0_u { - bdrkreg_t md_perf_sel0_regval; - struct { - bdrkreg_t ps_cnt_mode : 2; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_interrupt : 1; - } md_perf_sel0_fld_s; -} md_perf_sel0_u_t; - -#else - -typedef union md_perf_sel0_u { - bdrkreg_t md_perf_sel0_regval; - struct { - bdrkreg_t ps_interrupt : 1; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_cnt_mode : 2; - } md_perf_sel0_fld_s; -} md_perf_sel0_u_t; - -#endif - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel1_u { - bdrkreg_t md_perf_sel1_regval; - struct { - bdrkreg_t ps_cnt_mode : 2; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_interrupt : 1; - } md_perf_sel1_fld_s; -} md_perf_sel1_u_t; - -#else - -typedef union md_perf_sel1_u { - bdrkreg_t md_perf_sel1_regval; - struct { - bdrkreg_t ps_interrupt : 1; - bdrkreg_t ps_reserved : 3; - bdrkreg_t ps_command : 40; - bdrkreg_t ps_channel : 4; - bdrkreg_t ps_reserved_1 : 1; - bdrkreg_t ps_source : 7; - bdrkreg_t ps_activity : 4; - bdrkreg_t ps_reserved_2 : 2; - bdrkreg_t ps_cnt_mode : 2; - } md_perf_sel1_fld_s; -} md_perf_sel1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Performance counter. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_cnt0_u { - bdrkreg_t md_perf_cnt0_regval; - struct { - bdrkreg_t pc_perf_cnt : 41; - bdrkreg_t pc_reserved : 23; - } md_perf_cnt0_fld_s; -} md_perf_cnt0_u_t; - -#else - -typedef union md_perf_cnt0_u { - bdrkreg_t md_perf_cnt0_regval; - struct { - bdrkreg_t pc_reserved : 23; - bdrkreg_t pc_perf_cnt : 41; - } md_perf_cnt0_fld_s; -} md_perf_cnt0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Performance counter. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_perf_cnt1_u { - bdrkreg_t md_perf_cnt1_regval; - struct { - bdrkreg_t pc_perf_cnt : 41; - bdrkreg_t pc_reserved : 23; - } md_perf_cnt1_fld_s; -} md_perf_cnt1_u_t; - -#else - -typedef union md_perf_cnt1_u { - bdrkreg_t md_perf_cnt1_regval; - struct { - bdrkreg_t pc_reserved : 23; - bdrkreg_t pc_perf_cnt : 41; - } md_perf_cnt1_fld_s; -} md_perf_cnt1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register contains the control for * - * memory/directory refresh. Once the MEMORY_CONFIG register contains * - * the correct DIMM information, the hardware takes care of * - * refreshing all the banks in the system. Therefore, the value in * - * the counter threshold is corresponds exactly to the refresh value * - * required by the SDRAM parts (expressed in Bedrock clock cycles). * - * The refresh will execute whenever there is a free cycle and there * - * are still banks that have not been refreshed in the current * - * window. If the window expires with banks still waiting to be * - * refreshed, all other transactions are halted until the banks are * - * refreshed. * - * The upper order bit contains an enable, which may be needed for * - * correct initialization of the DIMMs (according to the specs, the * - * first operation to the DIMMs should be a mode register write, not * - * a refresh, so this bit is cleared on reset) and is also useful for * - * diagnostic purposes. * - * For the SDRAM parts used by Bedrock, 4096 refreshes need to be * - * issued during every 64 ms window, resulting in a refresh threshold * - * of 3125 Bedrock cycles. * - * The ENABLE and CNT_THRESH fields of this register are preserved * - * through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_refresh_control_u { - bdrkreg_t md_refresh_control_regval; - struct { - bdrkreg_t rc_cnt_thresh : 12; - bdrkreg_t rc_counter : 12; - bdrkreg_t rc_reserved : 39; - bdrkreg_t rc_enable : 1; - } md_refresh_control_fld_s; -} md_refresh_control_u_t; - -#else - -typedef union md_refresh_control_u { - bdrkreg_t md_refresh_control_regval; - struct { - bdrkreg_t rc_enable : 1; - bdrkreg_t rc_reserved : 39; - bdrkreg_t rc_counter : 12; - bdrkreg_t rc_cnt_thresh : 12; - } md_refresh_control_fld_s; -} md_refresh_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls the read and write timing for Flash PROM, * - * UART and Synergy junk bus devices. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_junk_bus_timing_u { - bdrkreg_t md_junk_bus_timing_regval; - struct { - bdrkreg_t jbt_fprom_setup_hold : 8; - bdrkreg_t jbt_fprom_enable : 8; - bdrkreg_t jbt_uart_setup_hold : 8; - bdrkreg_t jbt_uart_enable : 8; - bdrkreg_t jbt_synergy_setup_hold : 8; - bdrkreg_t jbt_synergy_enable : 8; - bdrkreg_t jbt_reserved : 16; - } md_junk_bus_timing_fld_s; -} md_junk_bus_timing_u_t; - -#else - -typedef union md_junk_bus_timing_u { - bdrkreg_t md_junk_bus_timing_regval; - struct { - bdrkreg_t jbt_reserved : 16; - bdrkreg_t jbt_synergy_enable : 8; - bdrkreg_t jbt_synergy_setup_hold : 8; - bdrkreg_t jbt_uart_enable : 8; - bdrkreg_t jbt_uart_setup_hold : 8; - bdrkreg_t jbt_fprom_enable : 8; - bdrkreg_t jbt_fprom_setup_hold : 8; - } md_junk_bus_timing_fld_s; -} md_junk_bus_timing_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led0_u { - bdrkreg_t md_led0_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led0_fld_s; -} md_led0_u_t; - -#else - -typedef union md_led0_u { - bdrkreg_t md_led0_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led0_fld_s; -} md_led0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led1_u { - bdrkreg_t md_led1_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led1_fld_s; -} md_led1_u_t; - -#else - -typedef union md_led1_u { - bdrkreg_t md_led1_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led1_fld_s; -} md_led1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led2_u { - bdrkreg_t md_led2_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led2_fld_s; -} md_led2_u_t; - -#else - -typedef union md_led2_u { - bdrkreg_t md_led2_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led2_fld_s; -} md_led2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Each of these addresses allows the value on one 8-bit bank of * - * LEDs to be read. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_led3_u { - bdrkreg_t md_led3_regval; - struct { - bdrkreg_t l_data : 8; - bdrkreg_t l_reserved : 56; - } md_led3_fld_s; -} md_led3_u_t; - -#else - -typedef union md_led3_u { - bdrkreg_t md_led3_regval; - struct { - bdrkreg_t l_reserved : 56; - bdrkreg_t l_data : 8; - } md_led3_fld_s; -} md_led3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Core control for the BIST function. Start and stop BIST at any * - * time. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_ctl_u { - bdrkreg_t md_bist_ctl_regval; - struct { - bdrkreg_t bc_bist_start : 1; - bdrkreg_t bc_bist_stop : 1; - bdrkreg_t bc_bist_reset : 1; - bdrkreg_t bc_reserved_1 : 1; - bdrkreg_t bc_bank_num : 1; - bdrkreg_t bc_dimm_num : 2; - bdrkreg_t bc_reserved : 57; - } md_bist_ctl_fld_s; -} md_bist_ctl_u_t; - -#else - -typedef union md_bist_ctl_u { - bdrkreg_t md_bist_ctl_regval; - struct { - bdrkreg_t bc_reserved : 57; - bdrkreg_t bc_dimm_num : 2; - bdrkreg_t bc_bank_num : 1; - bdrkreg_t bc_reserved_1 : 1; - bdrkreg_t bc_bist_reset : 1; - bdrkreg_t bc_bist_stop : 1; - bdrkreg_t bc_bist_start : 1; - } md_bist_ctl_fld_s; -} md_bist_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contain the initial BIST data nibble and the 4-bit data control * - * field.. * - * * - ************************************************************************/ - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_data_u { - bdrkreg_t md_bist_data_regval; - struct { - bdrkreg_t bd_bist_data : 4; - bdrkreg_t bd_bist_nibble : 1; - bdrkreg_t bd_bist_byte : 1; - bdrkreg_t bd_bist_cycle : 1; - bdrkreg_t bd_bist_write : 1; - bdrkreg_t bd_reserved : 56; - } md_bist_data_fld_s; -} md_bist_data_u_t; - -#else - -typedef union md_bist_data_u { - bdrkreg_t md_bist_data_regval; - struct { - bdrkreg_t bd_reserved : 56; - bdrkreg_t bd_bist_write : 1; - bdrkreg_t bd_bist_cycle : 1; - bdrkreg_t bd_bist_byte : 1; - bdrkreg_t bd_bist_nibble : 1; - bdrkreg_t bd_bist_data : 4; - } md_bist_data_fld_s; -} md_bist_data_u_t; - -#endif - - - - -/************************************************************************ - * * - * Captures the BIST error address and indicates whether it is an MB * - * error or DB error. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_ab_err_addr_u { - bdrkreg_t md_bist_ab_err_addr_regval; - struct { - bdrkreg_t baea_be_db_cas_addr : 15; - bdrkreg_t baea_reserved_3 : 1; - bdrkreg_t baea_be_mb_cas_addr : 15; - bdrkreg_t baea_reserved_2 : 1; - bdrkreg_t baea_be_ras_addr : 15; - bdrkreg_t baea_reserved_1 : 1; - bdrkreg_t baea_bist_mb_error : 1; - bdrkreg_t baea_bist_db_error : 1; - bdrkreg_t baea_reserved : 14; - } md_bist_ab_err_addr_fld_s; -} md_bist_ab_err_addr_u_t; - -#else - -typedef union md_bist_ab_err_addr_u { - bdrkreg_t md_bist_ab_err_addr_regval; - struct { - bdrkreg_t baea_reserved : 14; - bdrkreg_t baea_bist_db_error : 1; - bdrkreg_t baea_bist_mb_error : 1; - bdrkreg_t baea_reserved_1 : 1; - bdrkreg_t baea_be_ras_addr : 15; - bdrkreg_t baea_reserved_2 : 1; - bdrkreg_t baea_be_mb_cas_addr : 15; - bdrkreg_t baea_reserved_3 : 1; - bdrkreg_t baea_be_db_cas_addr : 15; - } md_bist_ab_err_addr_fld_s; -} md_bist_ab_err_addr_u_t; - -#endif - - - -/************************************************************************ - * * - * Contains information on BIST progress and memory bank currently * - * under BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_status_u { - bdrkreg_t md_bist_status_regval; - struct { - bdrkreg_t bs_bist_passed : 1; - bdrkreg_t bs_bist_done : 1; - bdrkreg_t bs_reserved : 62; - } md_bist_status_fld_s; -} md_bist_status_u_t; - -#else - -typedef union md_bist_status_u { - bdrkreg_t md_bist_status_regval; - struct { - bdrkreg_t bs_reserved : 62; - bdrkreg_t bs_bist_done : 1; - bdrkreg_t bs_bist_passed : 1; - } md_bist_status_fld_s; -} md_bist_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains 3 bits that allow the selection of IB debug information * - * at the debug port (see design specification for available debug * - * information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_ib_debug_u { - bdrkreg_t md_ib_debug_regval; - struct { - bdrkreg_t id_ib_debug_sel : 2; - bdrkreg_t id_reserved : 62; - } md_ib_debug_fld_s; -} md_ib_debug_u_t; - -#else - -typedef union md_ib_debug_u { - bdrkreg_t md_ib_debug_regval; - struct { - bdrkreg_t id_reserved : 62; - bdrkreg_t id_ib_debug_sel : 2; - } md_ib_debug_fld_s; -} md_ib_debug_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the directory specific mode bits. The contents of this * - * register are preserved through soft-resets. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_config_u { - bdrkreg_t md_dir_config_regval; - struct { - bdrkreg_t dc_dir_flavor : 1; - bdrkreg_t dc_ignore_dir_ecc : 1; - bdrkreg_t dc_reserved : 62; - } md_dir_config_fld_s; -} md_dir_config_u_t; - -#else - -typedef union md_dir_config_u { - bdrkreg_t md_dir_config_regval; - struct { - bdrkreg_t dc_reserved : 62; - bdrkreg_t dc_ignore_dir_ecc : 1; - bdrkreg_t dc_dir_flavor : 1; - } md_dir_config_fld_s; -} md_dir_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on uncorrectable and * - * correctable directory ECC errors, along with protection ECC * - * errors. The priority of ECC errors latched is: uncorrectable * - * directory, protection error, correctable directory. Thus the valid * - * bits signal: * - * 1xxx: uncorrectable directory ECC error (UCE) * - * 01xx: access protection double bit error (AE) * - * 001x: correctable directory ECC error (CE) * - * 0001: access protection correctable error (ACE) * - * If the UCE valid bit is set, the address field contains a pointer * - * to the Hspec address of the offending directory entry, the * - * syndrome field contains the bad syndrome, and the UCE overrun bit * - * indicates whether multiple double-bit errors were received. * - * If the UCE valid bit is clear but the AE valid bit is set, the * - * address field contains a pointer to the Hspec address of the * - * offending protection entry, the Bad Protection field contains the * - * 4-bit bad protection value, the PROT_INDEX field shows which of * - * the 8 protection values in the word was bad and the AE overrun bit * - * indicates whether multiple AE errors were received. * - * If the UCE and AE valid bits are clear, but the CE valid bit is * - * set, the address field contains a pointer to the Hspec address of * - * the offending directory entry, the syndrome field contains the bad * - * syndrome, and the CE overrun bit indicates whether multiple * - * single-bit errors were received. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_error_u { - bdrkreg_t md_dir_error_regval; - struct { - bdrkreg_t de_reserved_3 : 3; - bdrkreg_t de_hspec_addr : 30; - bdrkreg_t de_reserved_2 : 7; - bdrkreg_t de_bad_syn : 7; - bdrkreg_t de_reserved_1 : 1; - bdrkreg_t de_bad_protect : 4; - bdrkreg_t de_prot_index : 3; - bdrkreg_t de_reserved : 1; - bdrkreg_t de_ace_overrun : 1; - bdrkreg_t de_ce_overrun : 1; - bdrkreg_t de_ae_overrun : 1; - bdrkreg_t de_uce_overrun : 1; - bdrkreg_t de_ace_valid : 1; - bdrkreg_t de_ce_valid : 1; - bdrkreg_t de_ae_valid : 1; - bdrkreg_t de_uce_valid : 1; - } md_dir_error_fld_s; -} md_dir_error_u_t; - -#else - -typedef union md_dir_error_u { - bdrkreg_t md_dir_error_regval; - struct { - bdrkreg_t de_uce_valid : 1; - bdrkreg_t de_ae_valid : 1; - bdrkreg_t de_ce_valid : 1; - bdrkreg_t de_ace_valid : 1; - bdrkreg_t de_uce_overrun : 1; - bdrkreg_t de_ae_overrun : 1; - bdrkreg_t de_ce_overrun : 1; - bdrkreg_t de_ace_overrun : 1; - bdrkreg_t de_reserved : 1; - bdrkreg_t de_prot_index : 3; - bdrkreg_t de_bad_protect : 4; - bdrkreg_t de_reserved_1 : 1; - bdrkreg_t de_bad_syn : 7; - bdrkreg_t de_reserved_2 : 7; - bdrkreg_t de_hspec_addr : 30; - bdrkreg_t de_reserved_3 : 3; - } md_dir_error_fld_s; -} md_dir_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on uncorrectable and * - * correctable directory ECC errors, along with protection ECC * - * errors. The priority of ECC errors latched is: uncorrectable * - * directory, protection error, correctable directory. Thus the valid * - * bits signal: * - * 1xxx: uncorrectable directory ECC error (UCE) * - * 01xx: access protection double bit error (AE) * - * 001x: correctable directory ECC error (CE) * - * 0001: access protection correctable error (ACE) * - * If the UCE valid bit is set, the address field contains a pointer * - * to the Hspec address of the offending directory entry, the * - * syndrome field contains the bad syndrome, and the UCE overrun bit * - * indicates whether multiple double-bit errors were received. * - * If the UCE valid bit is clear but the AE valid bit is set, the * - * address field contains a pointer to the Hspec address of the * - * offending protection entry, the Bad Protection field contains the * - * 4-bit bad protection value, the PROT_INDEX field shows which of * - * the 8 protection values in the word was bad and the AE overrun bit * - * indicates whether multiple AE errors were received. * - * If the UCE and AE valid bits are clear, but the CE valid bit is * - * set, the address field contains a pointer to the Hspec address of * - * the offending directory entry, the syndrome field contains the bad * - * syndrome, and the CE overrun bit indicates whether multiple * - * single-bit errors were received. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_dir_error_clr_u { - bdrkreg_t md_dir_error_clr_regval; - struct { - bdrkreg_t dec_reserved_3 : 3; - bdrkreg_t dec_hspec_addr : 30; - bdrkreg_t dec_reserved_2 : 7; - bdrkreg_t dec_bad_syn : 7; - bdrkreg_t dec_reserved_1 : 1; - bdrkreg_t dec_bad_protect : 4; - bdrkreg_t dec_prot_index : 3; - bdrkreg_t dec_reserved : 1; - bdrkreg_t dec_ace_overrun : 1; - bdrkreg_t dec_ce_overrun : 1; - bdrkreg_t dec_ae_overrun : 1; - bdrkreg_t dec_uce_overrun : 1; - bdrkreg_t dec_ace_valid : 1; - bdrkreg_t dec_ce_valid : 1; - bdrkreg_t dec_ae_valid : 1; - bdrkreg_t dec_uce_valid : 1; - } md_dir_error_clr_fld_s; -} md_dir_error_clr_u_t; - -#else - -typedef union md_dir_error_clr_u { - bdrkreg_t md_dir_error_clr_regval; - struct { - bdrkreg_t dec_uce_valid : 1; - bdrkreg_t dec_ae_valid : 1; - bdrkreg_t dec_ce_valid : 1; - bdrkreg_t dec_ace_valid : 1; - bdrkreg_t dec_uce_overrun : 1; - bdrkreg_t dec_ae_overrun : 1; - bdrkreg_t dec_ce_overrun : 1; - bdrkreg_t dec_ace_overrun : 1; - bdrkreg_t dec_reserved : 1; - bdrkreg_t dec_prot_index : 3; - bdrkreg_t dec_bad_protect : 4; - bdrkreg_t dec_reserved_1 : 1; - bdrkreg_t dec_bad_syn : 7; - bdrkreg_t dec_reserved_2 : 7; - bdrkreg_t dec_hspec_addr : 30; - bdrkreg_t dec_reserved_3 : 3; - } md_dir_error_clr_fld_s; -} md_dir_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains information on requests that encounter no valid protocol * - * table entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_protocol_error_u { - bdrkreg_t md_protocol_error_regval; - struct { - bdrkreg_t pe_overrun : 1; - bdrkreg_t pe_pointer_me : 1; - bdrkreg_t pe_reserved_1 : 1; - bdrkreg_t pe_address : 30; - bdrkreg_t pe_reserved : 1; - bdrkreg_t pe_ptr1_btmbits : 3; - bdrkreg_t pe_dir_format : 2; - bdrkreg_t pe_dir_state : 3; - bdrkreg_t pe_priority : 1; - bdrkreg_t pe_access : 1; - bdrkreg_t pe_msg_type : 8; - bdrkreg_t pe_initiator : 11; - bdrkreg_t pe_valid : 1; - } md_protocol_error_fld_s; -} md_protocol_error_u_t; - -#else - -typedef union md_protocol_error_u { - bdrkreg_t md_protocol_error_regval; - struct { - bdrkreg_t pe_valid : 1; - bdrkreg_t pe_initiator : 11; - bdrkreg_t pe_msg_type : 8; - bdrkreg_t pe_access : 1; - bdrkreg_t pe_priority : 1; - bdrkreg_t pe_dir_state : 3; - bdrkreg_t pe_dir_format : 2; - bdrkreg_t pe_ptr1_btmbits : 3; - bdrkreg_t pe_reserved : 1; - bdrkreg_t pe_address : 30; - bdrkreg_t pe_reserved_1 : 1; - bdrkreg_t pe_pointer_me : 1; - bdrkreg_t pe_overrun : 1; - } md_protocol_error_fld_s; -} md_protocol_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains information on requests that encounter no valid protocol * - * table entry. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_protocol_err_clr_u { - bdrkreg_t md_protocol_err_clr_regval; - struct { - bdrkreg_t pec_overrun : 1; - bdrkreg_t pec_pointer_me : 1; - bdrkreg_t pec_reserved_1 : 1; - bdrkreg_t pec_address : 30; - bdrkreg_t pec_reserved : 1; - bdrkreg_t pec_ptr1_btmbits : 3; - bdrkreg_t pec_dir_format : 2; - bdrkreg_t pec_dir_state : 3; - bdrkreg_t pec_priority : 1; - bdrkreg_t pec_access : 1; - bdrkreg_t pec_msg_type : 8; - bdrkreg_t pec_initiator : 11; - bdrkreg_t pec_valid : 1; - } md_protocol_err_clr_fld_s; -} md_protocol_err_clr_u_t; - -#else - -typedef union md_protocol_err_clr_u { - bdrkreg_t md_protocol_err_clr_regval; - struct { - bdrkreg_t pec_valid : 1; - bdrkreg_t pec_initiator : 11; - bdrkreg_t pec_msg_type : 8; - bdrkreg_t pec_access : 1; - bdrkreg_t pec_priority : 1; - bdrkreg_t pec_dir_state : 3; - bdrkreg_t pec_dir_format : 2; - bdrkreg_t pec_ptr1_btmbits : 3; - bdrkreg_t pec_reserved : 1; - bdrkreg_t pec_address : 30; - bdrkreg_t pec_reserved_1 : 1; - bdrkreg_t pec_pointer_me : 1; - bdrkreg_t pec_overrun : 1; - } md_protocol_err_clr_fld_s; -} md_protocol_err_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the address of the page and the requestor which caused a * - * migration threshold to be exceeded. Also contains the type of * - * threshold exceeded and an overrun bit. For Value mode type * - * interrupts, it indicates whether the local or the remote counter * - * triggered the interrupt. Unlike most registers, when the overrun * - * bit is set the register contains information on the most recent * - * (the last) migration candidate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_candidate_u { - bdrkreg_t md_mig_candidate_regval; - struct { - bdrkreg_t mc_address : 21; - bdrkreg_t mc_initiator : 11; - bdrkreg_t mc_overrun : 1; - bdrkreg_t mc_type : 1; - bdrkreg_t mc_local : 1; - bdrkreg_t mc_reserved : 28; - bdrkreg_t mc_valid : 1; - } md_mig_candidate_fld_s; -} md_mig_candidate_u_t; - -#else - -typedef union md_mig_candidate_u { - bdrkreg_t md_mig_candidate_regval; - struct { - bdrkreg_t mc_valid : 1; - bdrkreg_t mc_reserved : 28; - bdrkreg_t mc_local : 1; - bdrkreg_t mc_type : 1; - bdrkreg_t mc_overrun : 1; - bdrkreg_t mc_initiator : 11; - bdrkreg_t mc_address : 21; - } md_mig_candidate_fld_s; -} md_mig_candidate_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the address of the page and the requestor which caused a * - * migration threshold to be exceeded. Also contains the type of * - * threshold exceeded and an overrun bit. For Value mode type * - * interrupts, it indicates whether the local or the remote counter * - * triggered the interrupt. Unlike most registers, when the overrun * - * bit is set the register contains information on the most recent * - * (the last) migration candidate. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_candidate_clr_u { - bdrkreg_t md_mig_candidate_clr_regval; - struct { - bdrkreg_t mcc_address : 21; - bdrkreg_t mcc_initiator : 11; - bdrkreg_t mcc_overrun : 1; - bdrkreg_t mcc_type : 1; - bdrkreg_t mcc_local : 1; - bdrkreg_t mcc_reserved : 28; - bdrkreg_t mcc_valid : 1; - } md_mig_candidate_clr_fld_s; -} md_mig_candidate_clr_u_t; - -#else - -typedef union md_mig_candidate_clr_u { - bdrkreg_t md_mig_candidate_clr_regval; - struct { - bdrkreg_t mcc_valid : 1; - bdrkreg_t mcc_reserved : 28; - bdrkreg_t mcc_local : 1; - bdrkreg_t mcc_type : 1; - bdrkreg_t mcc_overrun : 1; - bdrkreg_t mcc_initiator : 11; - bdrkreg_t mcc_address : 21; - } md_mig_candidate_clr_fld_s; -} md_mig_candidate_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls the generation of page-migration interrupts and loading * - * of the MIGRATION_CANDIDATE register for pages which are using the * - * difference between the requestor and home counts. If the * - * difference is greater-than or equal to than the threshold * - * contained in the register, and the valid bit is set, the migration * - * candidate is loaded (and an interrupt generated if enabled by the * - * page migration mode). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_diff_thresh_u { - bdrkreg_t md_mig_diff_thresh_regval; - struct { - bdrkreg_t mdt_threshold : 15; - bdrkreg_t mdt_reserved_1 : 17; - bdrkreg_t mdt_th_action : 3; - bdrkreg_t mdt_sat_action : 3; - bdrkreg_t mdt_reserved : 25; - bdrkreg_t mdt_valid : 1; - } md_mig_diff_thresh_fld_s; -} md_mig_diff_thresh_u_t; - -#else - -typedef union md_mig_diff_thresh_u { - bdrkreg_t md_mig_diff_thresh_regval; - struct { - bdrkreg_t mdt_valid : 1; - bdrkreg_t mdt_reserved : 25; - bdrkreg_t mdt_sat_action : 3; - bdrkreg_t mdt_th_action : 3; - bdrkreg_t mdt_reserved_1 : 17; - bdrkreg_t mdt_threshold : 15; - } md_mig_diff_thresh_fld_s; -} md_mig_diff_thresh_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls the generation of page-migration interrupts and loading * - * of the MIGRATION_CANDIDATE register for pages that are using the * - * absolute value of the requestor count. If the value is * - * greater-than or equal to the threshold contained in the register, * - * and the register valid bit is set, the migration candidate is * - * loaded and an interrupt generated. For the value mode of page * - * migration, there are two variations. In the first variation, * - * interrupts are only generated when the remote counter reaches the * - * threshold, not when the local counter reaches the threshold. In * - * the second mode, both the local counter and the remote counter * - * generate interrupts if they reach the threshold. This second mode * - * is useful for performance monitoring, to track the number of local * - * and remote references to a page. LOCAL_INT determines whether we * - * will generate interrupts when the local counter reaches the * - * threshold. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mig_value_thresh_u { - bdrkreg_t md_mig_value_thresh_regval; - struct { - bdrkreg_t mvt_threshold : 15; - bdrkreg_t mvt_reserved_1 : 17; - bdrkreg_t mvt_th_action : 3; - bdrkreg_t mvt_sat_action : 3; - bdrkreg_t mvt_reserved : 24; - bdrkreg_t mvt_local_int : 1; - bdrkreg_t mvt_valid : 1; - } md_mig_value_thresh_fld_s; -} md_mig_value_thresh_u_t; - -#else - -typedef union md_mig_value_thresh_u { - bdrkreg_t md_mig_value_thresh_regval; - struct { - bdrkreg_t mvt_valid : 1; - bdrkreg_t mvt_local_int : 1; - bdrkreg_t mvt_reserved : 24; - bdrkreg_t mvt_sat_action : 3; - bdrkreg_t mvt_th_action : 3; - bdrkreg_t mvt_reserved_1 : 17; - bdrkreg_t mvt_threshold : 15; - } md_mig_value_thresh_fld_s; -} md_mig_value_thresh_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the controls for the sizing of the three MOQH request * - * queues. The maximum (and default) value is 4. Queue sizes are in * - * flits. One header equals one flit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_outgoing_rq_queue_size_u { - bdrkreg_t md_outgoing_rq_queue_size_regval; - struct { - bdrkreg_t orqs_reserved_3 : 8; - bdrkreg_t orqs_moqh_p0_rq_size : 3; - bdrkreg_t orqs_reserved_2 : 5; - bdrkreg_t orqs_moqh_p1_rq_size : 3; - bdrkreg_t orqs_reserved_1 : 5; - bdrkreg_t orqs_moqh_np_rq_size : 3; - bdrkreg_t orqs_reserved : 37; - } md_outgoing_rq_queue_size_fld_s; -} md_outgoing_rq_queue_size_u_t; - -#else - -typedef union md_outgoing_rq_queue_size_u { - bdrkreg_t md_outgoing_rq_queue_size_regval; - struct { - bdrkreg_t orqs_reserved : 37; - bdrkreg_t orqs_moqh_np_rq_size : 3; - bdrkreg_t orqs_reserved_1 : 5; - bdrkreg_t orqs_moqh_p1_rq_size : 3; - bdrkreg_t orqs_reserved_2 : 5; - bdrkreg_t orqs_moqh_p0_rq_size : 3; - bdrkreg_t orqs_reserved_3 : 8; - } md_outgoing_rq_queue_size_fld_s; -} md_outgoing_rq_queue_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the 32-bit directory word failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_db_err_data_u { - bdrkreg_t md_bist_db_err_data_regval; - struct { - bdrkreg_t bded_db_er_d : 32; - bdrkreg_t bded_reserved : 32; - } md_bist_db_err_data_fld_s; -} md_bist_db_err_data_u_t; - -#else - -typedef union md_bist_db_err_data_u { - bdrkreg_t md_bist_db_err_data_regval; - struct { - bdrkreg_t bded_reserved : 32; - bdrkreg_t bded_db_er_d : 32; - } md_bist_db_err_data_fld_s; -} md_bist_db_err_data_u_t; - -#endif - - - -/************************************************************************ - * * - * Contains 2 bits that allow the selection of DB debug information * - * at the debug port (see the design specification for descrition of * - * the available debug information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_db_debug_u { - bdrkreg_t md_db_debug_regval; - struct { - bdrkreg_t dd_db_debug_sel : 2; - bdrkreg_t dd_reserved : 62; - } md_db_debug_fld_s; -} md_db_debug_u_t; - -#else - -typedef union md_db_debug_u { - bdrkreg_t md_db_debug_regval; - struct { - bdrkreg_t dd_reserved : 62; - bdrkreg_t dd_db_debug_sel : 2; - } md_db_debug_fld_s; -} md_db_debug_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains the IgnoreECC bit. When this bit is set, all ECC errors * - * are ignored. ECC bits will still be generated on writebacks. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mb_ecc_config_u { - bdrkreg_t md_mb_ecc_config_regval; - struct { - bdrkreg_t mec_ignore_dataecc : 1; - bdrkreg_t mec_reserved : 63; - } md_mb_ecc_config_fld_s; -} md_mb_ecc_config_u_t; - -#else - -typedef union md_mb_ecc_config_u { - bdrkreg_t md_mb_ecc_config_regval; - struct { - bdrkreg_t mec_reserved : 63; - bdrkreg_t mec_ignore_dataecc : 1; - } md_mb_ecc_config_fld_s; -} md_mb_ecc_config_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on read memory errors (both * - * correctable and uncorrectable) and write memory errors (always * - * uncorrectable). The errors are prioritized as follows: * - * highest: uncorrectable read error (READ_UCE) * - * middle: write error (WRITE_UCE) * - * lowest: correctable read error (READ_CE) * - * Each type of error maintains a two-bit valid/overrun field * - * (READ_UCE, WRITE_UCE, or READ_CE). Bit 0 of each two-bit field * - * corresponds to the valid bit, and bit 1 of each two-bit field * - * corresponds to the overrun bit. * - * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occurred. * - * The rule for the overrun bit is that it gets set whenever we are * - * unable to record the address information for this particular * - * error, due to a previous error of the same or higher priority. * - * Note that the syndrome and address information always corresponds * - * to the earliest, highest priority error. * - * Finally, the UCE_DIFF_ADDR bit is set whenever there have been * - * several uncorrectable errors, to different cache line addresses. * - * If all the UCEs were to the same cache line address, then * - * UCE_DIFF_ADDR will be 0. This allows the operating system to * - * detect the case where a UCE error is read exclusively, and then * - * written back by the processor. If the bit is 0, it indicates that * - * no information has been lost about UCEs on other cache lines. In * - * particular, partial writes do a read modify write of the cache * - * line. A UCE read error will be set when the cache line is read, * - * and a UCE write error will occur when the cache line is written * - * back, but the UCE_DIFF_ADDR will not be set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mem_error_u { - bdrkreg_t md_mem_error_regval; - struct { - bdrkreg_t me_reserved_5 : 3; - bdrkreg_t me_address : 30; - bdrkreg_t me_reserved_4 : 7; - bdrkreg_t me_bad_syn : 8; - bdrkreg_t me_reserved_3 : 4; - bdrkreg_t me_read_ce : 2; - bdrkreg_t me_reserved_2 : 2; - bdrkreg_t me_write_uce : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_read_uce : 2; - bdrkreg_t me_reserved : 1; - bdrkreg_t me_uce_diff_addr : 1; - } md_mem_error_fld_s; -} md_mem_error_u_t; - -#else - -typedef union md_mem_error_u { - bdrkreg_t md_mem_error_regval; - struct { - bdrkreg_t me_uce_diff_addr : 1; - bdrkreg_t me_reserved : 1; - bdrkreg_t me_read_uce : 2; - bdrkreg_t me_reserved_1 : 2; - bdrkreg_t me_write_uce : 2; - bdrkreg_t me_reserved_2 : 2; - bdrkreg_t me_read_ce : 2; - bdrkreg_t me_reserved_3 : 4; - bdrkreg_t me_bad_syn : 8; - bdrkreg_t me_reserved_4 : 7; - bdrkreg_t me_address : 30; - bdrkreg_t me_reserved_5 : 3; - } md_mem_error_fld_s; -} md_mem_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Contains information on read memory errors (both * - * correctable and uncorrectable) and write memory errors (always * - * uncorrectable). The errors are prioritized as follows: * - * highest: uncorrectable read error (READ_UCE) * - * middle: write error (WRITE_UCE) * - * lowest: correctable read error (READ_CE) * - * Each type of error maintains a two-bit valid/overrun field * - * (READ_UCE, WRITE_UCE, or READ_CE). Bit 0 of each two-bit field * - * corresponds to the valid bit, and bit 1 of each two-bit field * - * corresponds to the overrun bit. * - * The rule for the valid bit is that it gets set whenever that error * - * occurs, regardless of whether a higher priority error has occurred. * - * The rule for the overrun bit is that it gets set whenever we are * - * unable to record the address information for this particular * - * error, due to a previous error of the same or higher priority. * - * Note that the syndrome and address information always corresponds * - * to the earliest, highest priority error. * - * Finally, the UCE_DIFF_ADDR bit is set whenever there have been * - * several uncorrectable errors, to different cache line addresses. * - * If all the UCEs were to the same cache line address, then * - * UCE_DIFF_ADDR will be 0. This allows the operating system to * - * detect the case where a UCE error is read exclusively, and then * - * written back by the processor. If the bit is 0, it indicates that * - * no information has been lost about UCEs on other cache lines. In * - * particular, partial writes do a read modify write of the cache * - * line. A UCE read error will be set when the cache line is read, * - * and a UCE write error will occur when the cache line is written * - * back, but the UCE_DIFF_ADDR will not be set. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mem_error_clr_u { - bdrkreg_t md_mem_error_clr_regval; - struct { - bdrkreg_t mec_reserved_5 : 3; - bdrkreg_t mec_address : 30; - bdrkreg_t mec_reserved_4 : 7; - bdrkreg_t mec_bad_syn : 8; - bdrkreg_t mec_reserved_3 : 4; - bdrkreg_t mec_read_ce : 2; - bdrkreg_t mec_reserved_2 : 2; - bdrkreg_t mec_write_uce : 2; - bdrkreg_t mec_reserved_1 : 2; - bdrkreg_t mec_read_uce : 2; - bdrkreg_t mec_reserved : 1; - bdrkreg_t mec_uce_diff_addr : 1; - } md_mem_error_clr_fld_s; -} md_mem_error_clr_u_t; - -#else - -typedef union md_mem_error_clr_u { - bdrkreg_t md_mem_error_clr_regval; - struct { - bdrkreg_t mec_uce_diff_addr : 1; - bdrkreg_t mec_reserved : 1; - bdrkreg_t mec_read_uce : 2; - bdrkreg_t mec_reserved_1 : 2; - bdrkreg_t mec_write_uce : 2; - bdrkreg_t mec_reserved_2 : 2; - bdrkreg_t mec_read_ce : 2; - bdrkreg_t mec_reserved_3 : 4; - bdrkreg_t mec_bad_syn : 8; - bdrkreg_t mec_reserved_4 : 7; - bdrkreg_t mec_address : 30; - bdrkreg_t mec_reserved_5 : 3; - } md_mem_error_clr_fld_s; -} md_mem_error_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_0_u { - bdrkreg_t md_bist_mb_err_data_0_regval; - struct { - bdrkreg_t bmed0_mb_er_d : 36; - bdrkreg_t bmed0_reserved : 28; - } md_bist_mb_err_data_0_fld_s; -} md_bist_mb_err_data_0_u_t; - -#else - -typedef union md_bist_mb_err_data_0_u { - bdrkreg_t md_bist_mb_err_data_0_regval; - struct { - bdrkreg_t bmed0_reserved : 28; - bdrkreg_t bmed0_mb_er_d : 36; - } md_bist_mb_err_data_0_fld_s; -} md_bist_mb_err_data_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_1_u { - bdrkreg_t md_bist_mb_err_data_1_regval; - struct { - bdrkreg_t bmed1_mb_er_d : 36; - bdrkreg_t bmed1_reserved : 28; - } md_bist_mb_err_data_1_fld_s; -} md_bist_mb_err_data_1_u_t; - -#else - -typedef union md_bist_mb_err_data_1_u { - bdrkreg_t md_bist_mb_err_data_1_regval; - struct { - bdrkreg_t bmed1_reserved : 28; - bdrkreg_t bmed1_mb_er_d : 36; - } md_bist_mb_err_data_1_fld_s; -} md_bist_mb_err_data_1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_2_u { - bdrkreg_t md_bist_mb_err_data_2_regval; - struct { - bdrkreg_t bmed2_mb_er_d : 36; - bdrkreg_t bmed2_reserved : 28; - } md_bist_mb_err_data_2_fld_s; -} md_bist_mb_err_data_2_u_t; - -#else - -typedef union md_bist_mb_err_data_2_u { - bdrkreg_t md_bist_mb_err_data_2_regval; - struct { - bdrkreg_t bmed2_reserved : 28; - bdrkreg_t bmed2_mb_er_d : 36; - } md_bist_mb_err_data_2_fld_s; -} md_bist_mb_err_data_2_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains one-quarter of the error memory line failing BIST. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_bist_mb_err_data_3_u { - bdrkreg_t md_bist_mb_err_data_3_regval; - struct { - bdrkreg_t bmed3_mb_er_d : 36; - bdrkreg_t bmed3_reserved : 28; - } md_bist_mb_err_data_3_fld_s; -} md_bist_mb_err_data_3_u_t; - -#else - -typedef union md_bist_mb_err_data_3_u { - bdrkreg_t md_bist_mb_err_data_3_regval; - struct { - bdrkreg_t bmed3_reserved : 28; - bdrkreg_t bmed3_mb_er_d : 36; - } md_bist_mb_err_data_3_fld_s; -} md_bist_mb_err_data_3_u_t; - -#endif - - - - -/************************************************************************ - * * - * Contains 1 bit that allow the selection of MB debug information * - * at the debug port (see the design specification for the available * - * debug information). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union md_mb_debug_u { - bdrkreg_t md_mb_debug_regval; - struct { - bdrkreg_t md_mb_debug_sel : 1; - bdrkreg_t md_reserved : 63; - } md_mb_debug_fld_s; -} md_mb_debug_u_t; - -#else - -typedef union md_mb_debug_u { - bdrkreg_t md_mb_debug_regval; - struct { - bdrkreg_t md_reserved : 63; - bdrkreg_t md_mb_debug_sel : 1; - } md_mb_debug_fld_s; -} md_mb_debug_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - -#endif /* _ASM_IA64_SN_SN1_HUBMD_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubmd_next.h b/include/asm-ia64/sn/sn1/hubmd_next.h --- a/include/asm-ia64/sn/sn1/hubmd_next.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,812 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBMD_NEXT_H -#define _ASM_IA64_SN_SN1_HUBMD_NEXT_H - -/* XXX moved over from SN/SN0/hubmd.h -- each should be checked for SN1 */ -/* In fact, most of this stuff is wrong. Some is correct, such as - * MD_PAGE_SIZE and MD_PAGE_NUM_SHFT. - */ - -#define MD_PERF_COUNTERS 6 -#define MD_PERF_SETS 6 - -#define MD_SIZE_EMPTY 0 -#define MD_SIZE_64MB 1 -#define MD_SIZE_128MB 2 -#define MD_SIZE_256MB 3 -#define MD_SIZE_512MB 4 -#define MD_SIZE_1GB 5 - -#define MD_SIZE_BYTES(size) ((size) == 0 ? 0 : 0x2000000L << (size)) -#define MD_SIZE_MBYTES(size) ((size) == 0 ? 0 : 0x20 << (size)) -#define MD_NUM_ENABLED(_x) ((_x & 0x1) + ((_x >> 1) & 0x1) + \ - ((_x >> 2) & 0x1) + ((_x >> 3) & 0x1)) - - -/* Hardware page size and shift */ - -#define MD_PAGE_SIZE 16384 /* Page size in bytes */ -#define MD_PAGE_NUM_SHFT 14 /* Address to page number shift */ - -#define MMC_IO_PROT (UINT64_CAST 1 << 45) - -/* Register offsets from LOCAL_HUB or REMOTE_HUB */ -#define MD_PERF_SEL 0x210000 /* Select perf monitor events */ - -/* MD_MIG_VALUE_THRESH bit definitions */ - -#define MD_MIG_VALUE_THRES_VALID_MASK (UINT64_CAST 0x1 << 63) -#define MD_MIG_VALUE_THRES_VALUE_MASK (UINT64_CAST 0xfffff) - -/* MD_MIG_CANDIDATE bit definitions */ - -#define MD_MIG_CANDIDATE_VALID_MASK (UINT64_CAST 0x1 << 63) -#define MD_MIG_CANDIDATE_VALID_SHFT 63 -#define MD_MIG_CANDIDATE_TYPE_MASK (UINT64_CAST 0x1 << 30) -#define MD_MIG_CANDIDATE_TYPE_SHFT 30 -#define MD_MIG_CANDIDATE_OVERRUN_MASK (UINT64_CAST 0x1 << 29) -#define MD_MIG_CANDIDATE_OVERRUN_SHFT 29 -#define MD_MIG_CANDIDATE_NODEID_MASK (UINT64_CAST 0x1ff << 20) -#define MD_MIG_CANDIDATE_NODEID_SHFT 20 -#define MD_MIG_CANDIDATE_ADDR_MASK (UINT64_CAST 0x3ffff) - - -/* XXX protection and migration are completely revised on SN1. On - SN0, the reference count and protection fields were accessed in the - same word, but on SN1 they reside at different addresses. The - users of these macros will need to be rewritten. Also, the MD page - size is 16K on SN1 but 4K on SN0. */ - -/* Premium SIMM protection entry shifts and masks. */ - -#define MD_PPROT_SHFT 0 /* Prot. field */ -#define MD_PPROT_MASK 0xf -#define MD_PPROT_REFCNT_SHFT 5 /* Reference count */ -#define MD_PPROT_REFCNT_WIDTH 0x7ffff -#define MD_PPROT_REFCNT_MASK (MD_PPROT_REFCNT_WIDTH << 5) - -#define MD_PPROT_IO_SHFT 8 /* I/O Prot field */ - -/* Standard SIMM protection entry shifts and masks. */ - -#define MD_SPROT_SHFT 0 /* Prot. field */ -#define MD_SPROT_MASK 0xf -#define MD_SPROT_IO_SHFT 8 -#define MD_SPROT_REFCNT_SHFT 5 /* Reference count */ -#define MD_SPROT_REFCNT_WIDTH 0x7ff -#define MD_SPROT_REFCNT_MASK (MD_SPROT_REFCNT_WIDTH << 5) - -/* Migration modes used in protection entries */ - -#define MD_PROT_MIGMD_IREL (UINT64_CAST 0x3 << 3) -#define MD_PROT_MIGMD_IABS (UINT64_CAST 0x2 << 3) -#define MD_PROT_MIGMD_PREL (UINT64_CAST 0x1 << 3) -#define MD_PROT_MIGMD_OFF (UINT64_CAST 0x0 << 3) - -/* - * Operations on Memory/Directory DIMM control register - */ - -#define DIRTYPE_PREMIUM 1 -#define DIRTYPE_STANDARD 0 - -/* - * Operations on page migration count difference and absolute threshold - * registers - */ - -#define MD_MIG_VALUE_THRESH_GET(region) ( \ - REMOTE_HUB_L((region), MD_MIG_VALUE_THRESH) & \ - MD_MIG_VALUE_THRES_VALUE_MASK) - -#define MD_MIG_VALUE_THRESH_SET(region, value) ( \ - REMOTE_HUB_S((region), MD_MIG_VALUE_THRESH, \ - MD_MIG_VALUE_THRES_VALID_MASK | (value))) - -#define MD_MIG_VALUE_THRESH_ENABLE(region) ( \ - REMOTE_HUB_S((region), MD_MIG_VALUE_THRESH, \ - REMOTE_HUB_L((region), MD_MIG_VALUE_THRESH) \ - | MD_MIG_VALUE_THRES_VALID_MASK)) - -/* - * Operations on page migration candidate register - */ - -#define MD_MIG_CANDIDATE_GET(my_region_id) ( \ - REMOTE_HUB_L((my_region_id), MD_MIG_CANDIDATE_CLR)) - -#define MD_MIG_CANDIDATE_HWPFN(value) ((value) & MD_MIG_CANDIDATE_ADDR_MASK) - -#define MD_MIG_CANDIDATE_NODEID(value) ( \ - ((value) & MD_MIG_CANDIDATE_NODEID_MASK) >> MD_MIG_CANDIDATE_NODEID_SHFT) - -#define MD_MIG_CANDIDATE_TYPE(value) ( \ - ((value) & MD_MIG_CANDIDATE_TYPE_MASK) >> MD_MIG_CANDIDATE_TYPE_SHFT) - -#define MD_MIG_CANDIDATE_VALID(value) ( \ - ((value) & MD_MIG_CANDIDATE_VALID_MASK) >> MD_MIG_CANDIDATE_VALID_SHFT) - -/* - * Macros to retrieve fields in the protection entry - */ - -/* for Premium SIMM */ -#define MD_PPROT_REFCNT_GET(value) ( \ - ((value) & MD_PPROT_REFCNT_MASK) >> MD_PPROT_REFCNT_SHFT) - -/* for Standard SIMM */ -#define MD_SPROT_REFCNT_GET(value) ( \ - ((value) & MD_SPROT_REFCNT_MASK) >> MD_SPROT_REFCNT_SHFT) - -#ifndef __ASSEMBLY__ -#ifdef LITTLE_ENDIAN - -typedef union md_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_sel : 3, - perf_en : 1, - perf_rsvd : 60; - } perf_sel_bits; -} md_perf_sel_t; - -#else - -typedef union md_perf_sel { - uint64_t perf_sel_reg; - struct { - uint64_t perf_rsvd : 60, - perf_en : 1, - perf_sel : 3; - } perf_sel_bits; -} md_perf_sel_t; - -#endif -#endif /* __ASSEMBLY__ */ - - -/* Like SN0, SN1 supports a mostly-flat address space with 8 - CPU-visible, evenly spaced, contiguous regions, or "software - banks". On SN1, software bank n begins at addresses n * 1GB, - 0 <= n < 8. - - Physically (and very unlike SN0), each SN1 node board contains 8 - dimm sockets, arranged as 4 "DIMM banks" of 2 dimms each. DIMM - size and width (x4/x8) is assigned per dimm bank. Each DIMM bank - consists of 2 "physical banks", one on the front sides of the 2 - DIMMs and the other on the back sides. Therefore a node has a - total of 8 ( = 4 * 2) physical banks. They are collectively - referred to as "locational banks", since the locational bank number - depends on the physical location of the DIMMs on the board. - - Dimm bank 0, Phys bank 0a (locational bank 0a) - Slot D0 ---------------------------------------------- - Dimm bank 0, Phys bank 1a (locational bank 1a) - - Dimm bank 1, Phys bank 0a (locational bank 2a) - Slot D1 ---------------------------------------------- - Dimm bank 1, Phys bank 1a (locational bank 3a) - - Dimm bank 2, Phys bank 0a (locational bank 4a) - Slot D2 ---------------------------------------------- - Dimm bank 2, Phys bank 1a (locational bank 5a) - - Dimm bank 3, Phys bank 0a (locational bank 6a) - Slot D3 ---------------------------------------------- - Dimm bank 3, Phys bank 1a (locational bank 7a) - - Dimm bank 0, Phys bank 0b (locational bank 0b) - Slot D4 ---------------------------------------------- - Dimm bank 0, Phys bank 1b (locational bank 1b) - - Dimm bank 1, Phys bank 0b (locational bank 2b) - Slot D5 ---------------------------------------------- - Dimm bank 1, Phys bank 1b (locational bank 3b) - - Dimm bank 2, Phys bank 0b (locational bank 4b) - Slot D6 ---------------------------------------------- - Dimm bank 2, Phys bank 1b (locational bank 5b) - - Dimm bank 3, Phys bank 0b (locational bank 6b) - Slot D7 ---------------------------------------------- - Dimm bank 3, Phys bank 1b (locational bank 7b) - - Since bank size is assigned per DIMM bank, each pair of locational - banks must have the same size. However, they may be - enabled/disabled individually. - - The locational banks map to the software banks via the dimm0_sel - field in MD_MEMORY_CONFIG. When the field is 0 (the usual case), - the mapping is direct: eg. locational bank 1 (dimm bank 0, - physical bank 1, which is the back side of the first DIMM pair) - corresponds to software bank 1, at node offset 1GB. More - generally, locational bank = software bank XOR dimm0_sel. - - All the PROM's data structures (promlog variables, klconfig, etc.) - track memory by the locational bank number. The kernel usually - tracks memory by the software bank number. - memsupport.c:slot_psize_compute() performs the mapping. - - (Note: the terms "locational bank" and "software bank" are not - offical in any way, but I've tried to make the PROM use them - consistently -- bjj.) - */ - -#define MD_MEM_BANKS 8 -#define MD_MEM_DIMM_BANKS 4 -#define MD_BANK_SHFT 30 /* log2(1 GB) */ -#define MD_BANK_MASK (UINT64_CAST 0x7 << 30) -#define MD_BANK_SIZE (UINT64_CAST 1 << MD_BANK_SHFT) /* 1 GB */ -#define MD_BANK_OFFSET(_b) (UINT64_CAST (_b) << MD_BANK_SHFT) -#define MD_BANK_GET(addr) (((addr) & MD_BANK_MASK) >> MD_BANK_SHFT) -#define MD_BANK_TO_DIMM_BANK(_b) (( (_b) >> 1) & 0x3) -#define MD_BANK_TO_PHYS_BANK(_b) (( (_b) >> 0) & 0x1) -#define MD_DIMM_BANK_GET(addr) MD_BANK_TO_DIMM_BANK(MD_BANK_GET(addr)) -#define MD_PHYS_BANK_GET(addr) MD_BANK_TO_PHYS_BANK(MD_BANK_GET(addr)) - - -/* Split an MD pointer (or message source & suppl. fields) into node, device */ - -#define MD_PTR_NODE_SHFT 3 -#define MD_PTR_DEVICE_MASK 0x7 -#define MD_PTR_SUBNODE0_MASK 0x1 -#define MD_PTR_SUBNODE1_MASK 0x4 - - -/********************************************************************** - - Backdoor protection and page counter structures - -**********************************************************************/ - -/* Protection entries and page counters are interleaved at 4 separate - addresses, 0x10 apart. Software must read/write all four. */ - -#define BD_ITLV_COUNT 4 -#define BD_ITLV_STRIDE 0x10 - -/* Protection entries */ - -/* (these macros work for standard (_rgn < 32) or premium DIMMs) */ -#define MD_PROT_SHFT(_rgn, _io) ((((_rgn) & 0x20) >> 2 | \ - ((_rgn) & 0x01) << 2 | \ - ((_io) & 0x1) << 1) * 8) -#define MD_PROT_MASK(_rgn, _io) (0xff << MD_PROT_SHFT(_rgn, _io)) -#define MD_PROT_GET(_val, _rgn, _io) \ - (((_val) & MD_PROT_MASK(_rgn, _io)) >> MD_PROT_SHFT(_rgn, _io)) - -/* Protection field values */ - -#define MD_PROT_RW (UINT64_CAST 0xff) -#define MD_PROT_RO (UINT64_CAST 0x0f) -#define MD_PROT_NO (UINT64_CAST 0x00) - - - - -/********************************************************************** - - Directory format structures - -***********************************************************************/ - -#ifndef __ASSEMBLY__ - -/* Standard Directory Entries */ - -#ifdef LITTLE_ENDIAN - -struct md_sdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t sdp_format : 2; - bdrkreg_t sdp_state : 3; - bdrkreg_t sdp_priority : 3; - bdrkreg_t sdp_pointer1 : 8; - bdrkreg_t sdp_ecc : 6; - bdrkreg_t sdp_locprot : 1; - bdrkreg_t sdp_reserved : 1; - bdrkreg_t sdp_crit_word_off : 3; - bdrkreg_t sdp_pointer2 : 5; - bdrkreg_t sdp_fill : 32; -}; - -#else - -struct md_sdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t sdp_fill : 32; - bdrkreg_t sdp_pointer2 : 5; - bdrkreg_t sdp_crit_word_off : 3; - bdrkreg_t sdp_reserved : 1; - bdrkreg_t sdp_locprot : 1; - bdrkreg_t sdp_ecc : 6; - bdrkreg_t sdp_pointer1 : 8; - bdrkreg_t sdp_priority : 3; - bdrkreg_t sdp_state : 3; - bdrkreg_t sdp_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_sdir_fine_fmt { /* shared (fine) */ - bdrkreg_t sdf_format : 2; - bdrkreg_t sdf_tag1 : 3; - bdrkreg_t sdf_tag2 : 3; - bdrkreg_t sdf_vector1 : 8; - bdrkreg_t sdf_ecc : 6; - bdrkreg_t sdf_locprot : 1; - bdrkreg_t sdf_tag2valid : 1; - bdrkreg_t sdf_vector2 : 8; - bdrkreg_t sdf_fill : 32; -}; - -#else - -struct md_sdir_fine_fmt { /* shared (fine) */ - bdrkreg_t sdf_fill : 32; - bdrkreg_t sdf_vector2 : 8; - bdrkreg_t sdf_tag2valid : 1; - bdrkreg_t sdf_locprot : 1; - bdrkreg_t sdf_ecc : 6; - bdrkreg_t sdf_vector1 : 8; - bdrkreg_t sdf_tag2 : 3; - bdrkreg_t sdf_tag1 : 3; - bdrkreg_t sdf_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_sdir_coarse_fmt { /* shared (coarse) */ - bdrkreg_t sdc_format : 2; - bdrkreg_t sdc_reserved_1 : 6; - bdrkreg_t sdc_vector_a : 8; - bdrkreg_t sdc_ecc : 6; - bdrkreg_t sdc_locprot : 1; - bdrkreg_t sdc_reserved : 1; - bdrkreg_t sdc_vector_b : 8; - bdrkreg_t sdc_fill : 32; -}; - -#else - -struct md_sdir_coarse_fmt { /* shared (coarse) */ - bdrkreg_t sdc_fill : 32; - bdrkreg_t sdc_vector_b : 8; - bdrkreg_t sdc_reserved : 1; - bdrkreg_t sdc_locprot : 1; - bdrkreg_t sdc_ecc : 6; - bdrkreg_t sdc_vector_a : 8; - bdrkreg_t sdc_reserved_1 : 6; - bdrkreg_t sdc_format : 2; -}; - -#endif - -typedef union md_sdir { - /* The 32 bits of standard directory, in bits 31:0 */ - uint64_t sd_val; - struct md_sdir_pointer_fmt sdp_fmt; - struct md_sdir_fine_fmt sdf_fmt; - struct md_sdir_coarse_fmt sdc_fmt; -} md_sdir_t; - - -/* Premium Directory Entries */ - -#ifdef LITTLE_ENDIAN - -struct md_pdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t pdp_format : 2; - bdrkreg_t pdp_state : 3; - bdrkreg_t pdp_priority : 3; - bdrkreg_t pdp_pointer1_a : 8; - bdrkreg_t pdp_reserved_4 : 6; - bdrkreg_t pdp_pointer1_b : 3; - bdrkreg_t pdp_reserved_3 : 7; - bdrkreg_t pdp_ecc_a : 6; - bdrkreg_t pdp_locprot : 1; - bdrkreg_t pdp_reserved_2 : 1; - bdrkreg_t pdp_crit_word_off : 3; - bdrkreg_t pdp_pointer2_a : 5; - bdrkreg_t pdp_ecc_b : 1; - bdrkreg_t pdp_reserved_1 : 5; - bdrkreg_t pdp_pointer2_b : 3; - bdrkreg_t pdp_reserved : 7; -}; - -#else - -struct md_pdir_pointer_fmt { /* exclusive, busy shared/excl, wait, poisoned */ - bdrkreg_t pdp_reserved : 7; - bdrkreg_t pdp_pointer2_b : 3; - bdrkreg_t pdp_reserved_1 : 5; - bdrkreg_t pdp_ecc_b : 1; - bdrkreg_t pdp_pointer2_a : 5; - bdrkreg_t pdp_crit_word_off : 3; - bdrkreg_t pdp_reserved_2 : 1; - bdrkreg_t pdp_locprot : 1; - bdrkreg_t pdp_ecc_a : 6; - bdrkreg_t pdp_reserved_3 : 7; - bdrkreg_t pdp_pointer1_b : 3; - bdrkreg_t pdp_reserved_4 : 6; - bdrkreg_t pdp_pointer1_a : 8; - bdrkreg_t pdp_priority : 3; - bdrkreg_t pdp_state : 3; - bdrkreg_t pdp_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_pdir_fine_fmt { /* shared (fine) */ - bdrkreg_t pdf_format : 2; - bdrkreg_t pdf_tag1_a : 3; - bdrkreg_t pdf_tag2_a : 3; - bdrkreg_t pdf_vector1_a : 8; - bdrkreg_t pdf_reserved_1 : 6; - bdrkreg_t pdf_tag1_b : 2; - bdrkreg_t pdf_vector1_b : 8; - bdrkreg_t pdf_ecc_a : 6; - bdrkreg_t pdf_locprot : 1; - bdrkreg_t pdf_tag2valid : 1; - bdrkreg_t pdf_vector2_a : 8; - bdrkreg_t pdf_ecc_b : 1; - bdrkreg_t pdf_reserved : 5; - bdrkreg_t pdf_tag2_b : 2; - bdrkreg_t pdf_vector2_b : 8; -}; - -#else - -struct md_pdir_fine_fmt { /* shared (fine) */ - bdrkreg_t pdf_vector2_b : 8; - bdrkreg_t pdf_tag2_b : 2; - bdrkreg_t pdf_reserved : 5; - bdrkreg_t pdf_ecc_b : 1; - bdrkreg_t pdf_vector2_a : 8; - bdrkreg_t pdf_tag2valid : 1; - bdrkreg_t pdf_locprot : 1; - bdrkreg_t pdf_ecc_a : 6; - bdrkreg_t pdf_vector1_b : 8; - bdrkreg_t pdf_tag1_b : 2; - bdrkreg_t pdf_reserved_1 : 6; - bdrkreg_t pdf_vector1_a : 8; - bdrkreg_t pdf_tag2_a : 3; - bdrkreg_t pdf_tag1_a : 3; - bdrkreg_t pdf_format : 2; -}; - -#endif - -#ifdef LITTLE_ENDIAN - -struct md_pdir_sparse_fmt { /* shared (sparse) */ - bdrkreg_t pds_format : 2; - bdrkreg_t pds_column_a : 6; - bdrkreg_t pds_row_a : 8; - bdrkreg_t pds_column_b : 16; - bdrkreg_t pds_ecc_a : 6; - bdrkreg_t pds_locprot : 1; - bdrkreg_t pds_reserved_1 : 1; - bdrkreg_t pds_row_b : 8; - bdrkreg_t pds_ecc_b : 1; - bdrkreg_t pds_column_c : 10; - bdrkreg_t pds_reserved : 5; -}; - -#else - -struct md_pdir_sparse_fmt { /* shared (sparse) */ - bdrkreg_t pds_reserved : 5; - bdrkreg_t pds_column_c : 10; - bdrkreg_t pds_ecc_b : 1; - bdrkreg_t pds_row_b : 8; - bdrkreg_t pds_reserved_1 : 1; - bdrkreg_t pds_locprot : 1; - bdrkreg_t pds_ecc_a : 6; - bdrkreg_t pds_column_b : 16; - bdrkreg_t pds_row_a : 8; - bdrkreg_t pds_column_a : 6; - bdrkreg_t pds_format : 2; -}; - -#endif - -typedef union md_pdir { - /* The 64 bits of premium directory */ - uint64_t pd_val; - struct md_pdir_pointer_fmt pdp_fmt; - struct md_pdir_fine_fmt pdf_fmt; - struct md_pdir_sparse_fmt pds_fmt; -} md_pdir_t; - -#endif /* __ASSEMBLY__ */ - - -/********************************************************************** - - The defines for backdoor directory and backdoor ECC. - -***********************************************************************/ - -/* Directory formats, for each format's "format" field */ - -#define MD_FORMAT_UNOWNED (UINT64_CAST 0x0) /* 00 */ -#define MD_FORMAT_POINTER (UINT64_CAST 0x1) /* 01 */ -#define MD_FORMAT_SHFINE (UINT64_CAST 0x2) /* 10 */ -#define MD_FORMAT_SHCOARSE (UINT64_CAST 0x3) /* 11 */ - /* Shared coarse (standard) and shared sparse (premium) both use fmt 0x3 */ - - -/* - * Cacheline state values. - * - * These are really *software* notions of the "state" of a cacheline; but the - * actual values have been carefully chosen to align with some hardware values! - * The MD_FMT_ST_TO_STATE macro is used to convert from hardware format/state - * pairs in the directory entried into one of these cacheline state values. - */ - -#define MD_DIR_EXCLUSIVE (UINT64_CAST 0x0) /* ptr format, hw-defined */ -#define MD_DIR_UNOWNED (UINT64_CAST 0x1) /* format=0 */ -#define MD_DIR_SHARED (UINT64_CAST 0x2) /* format=2,3 */ -#define MD_DIR_BUSY_SHARED (UINT64_CAST 0x4) /* ptr format, hw-defined */ -#define MD_DIR_BUSY_EXCL (UINT64_CAST 0x5) /* ptr format, hw-defined */ -#define MD_DIR_WAIT (UINT64_CAST 0x6) /* ptr format, hw-defined */ -#define MD_DIR_POISONED (UINT64_CAST 0x7) /* ptr format, hw-defined */ - -#ifndef __ASSEMBLY__ - -/* Convert format and state fields into a single "cacheline state" value, defined above */ - -#define MD_FMT_ST_TO_STATE(fmt, state) \ - ((fmt) == MD_FORMAT_POINTER ? (state) : \ - (fmt) == MD_FORMAT_UNOWNED ? MD_DIR_UNOWNED : \ - MD_DIR_SHARED) -#define MD_DIR_STATE(x) MD_FMT_ST_TO_STATE(MD_DIR_FORMAT(x), MD_DIR_STVAL(x)) - -#endif /* __ASSEMBLY__ */ - - - -/* Directory field shifts and masks */ - -/* Standard */ - -#define MD_SDIR_FORMAT_SHFT 0 /* All formats */ -#define MD_SDIR_FORMAT_MASK (0x3 << 0) -#define MD_SDIR_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_SDIR_STATE_MASK (0x7 << 2) - -/* Premium */ - -#define MD_PDIR_FORMAT_SHFT 0 /* All formats */ -#define MD_PDIR_FORMAT_MASK (0x3 << 0) -#define MD_PDIR_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_PDIR_STATE_MASK (0x7 << 2) - -/* Generic */ - -#define MD_FORMAT_SHFT 0 /* All formats */ -#define MD_FORMAT_MASK (0x3 << 0) -#define MD_STATE_SHFT 2 /* Pointer fmt. only */ -#define MD_STATE_MASK (0x7 << 2) - - -/* Special shifts to reconstruct fields from the _a and _b parts */ - -/* Standard: only shared coarse has split fields */ - -#define MD_SDC_VECTORB_SHFT 8 /* eg: sdc_vector_a is 8 bits */ - -/* Premium: pointer, shared fine, shared sparse */ - -#define MD_PDP_POINTER1A_MASK 0xFF -#define MD_PDP_POINTER1B_SHFT 8 -#define MD_PDP_POINTER2B_SHFT 5 -#define MD_PDP_ECCB_SHFT 6 - -#define MD_PDF_VECTOR1B_SHFT 8 -#define MD_PDF_VECTOR2B_SHFT 8 -#define MD_PDF_TAG1B_SHFT 3 -#define MD_PDF_TAG2B_SHFT 3 -#define MD_PDF_ECC_SHFT 6 - -#define MD_PDS_ROWB_SHFT 8 -#define MD_PDS_COLUMNB_SHFT 6 -#define MD_PDS_COLUMNC_SHFT (MD_PDS_COLUMNB_SHFT + 16) -#define MD_PDS_ECC_SHFT 6 - - - -/* - * Directory/protection/counter initialization values, premium and standard - */ - -#define MD_PDIR_INIT 0 -#define MD_PDIR_INIT_CNT 0 -#define MD_PDIR_INIT_PROT 0 - -#define MD_SDIR_INIT 0 -#define MD_SDIR_INIT_CNT 0 -#define MD_SDIR_INIT_PROT 0 - -#define MD_PDIR_MASK 0xffffffffffffffff -#define MD_SDIR_MASK 0xffffffff - -/* When premium mode is on for probing but standard directory memory - is installed, the valid directory bits depend on the phys. bank */ -#define MD_PDIR_PROBE_MASK(pb) 0xffffffffffffffff -#define MD_SDIR_PROBE_MASK(pb) (0xffff0000ffff << ((pb) ? 16 : 0)) - - -/* - * Misc. field extractions and conversions - */ - -/* Convert an MD pointer (or message source, supplemental fields) */ - -#define MD_PTR_NODE(x) ((x) >> MD_PTR_NODE_SHFT) -#define MD_PTR_DEVICE(x) ((x) & MD_PTR_DEVICE_MASK) -#define MD_PTR_SLICE(x) (((x) & MD_PTR_SUBNODE0_MASK) | \ - ((x) & MD_PTR_SUBNODE1_MASK) >> 1) -#define MD_PTR_OWNER_CPU(x) (! ((x) & 2)) -#define MD_PTR_OWNER_IO(x) ((x) & 2) - -/* Extract format and raw state from a directory entry */ - -#define MD_DIR_FORMAT(x) ((x) >> MD_SDIR_FORMAT_SHFT & \ - MD_SDIR_FORMAT_MASK >> MD_SDIR_FORMAT_SHFT) -#define MD_DIR_STVAL(x) ((x) >> MD_SDIR_STATE_SHFT & \ - MD_SDIR_STATE_MASK >> MD_SDIR_STATE_SHFT) - -/* Mask & Shift to get HSPEC_ADDR from MD DIR_ERROR register */ -#define ERROR_ADDR_SHFT 3 -#define ERROR_HSPEC_SHFT 3 -#define DIR_ERR_HSPEC_MASK 0x1fffffff8 - -/* - * DIR_ERR* and MEM_ERR* defines are used to avoid ugly - * #ifdefs for SN0 and SN1 in memerror.c code. See SN0/hubmd.h - * for corresponding SN0 definitions. - */ -#define md_dir_error_t md_dir_error_u_t -#define md_mem_error_t md_mem_error_u_t -#define derr_reg md_dir_error_regval -#define merr_reg md_mem_error_regval - -#define DIR_ERR_UCE_VALID dir_err.md_dir_error_fld_s.de_uce_valid -#define DIR_ERR_AE_VALID dir_err.md_dir_error_fld_s.de_ae_valid -#define DIR_ERR_BAD_SYN dir_err.md_dir_error_fld_s.de_bad_syn -#define DIR_ERR_CE_OVERRUN dir_err.md_dir_error_fld_s.de_ce_overrun -#define MEM_ERR_ADDRESS mem_err.md_mem_error_fld_s.me_address - /* BRINGUP Can the overrun bit be set without the valid bit? */ -#define MEM_ERR_CE_OVERRUN (mem_err.md_mem_error_fld_s.me_read_ce >> 1) -#define MEM_ERR_BAD_SYN mem_err.md_mem_error_fld_s.me_bad_syn -#define MEM_ERR_UCE_VALID (mem_err.md_mem_error_fld_s.me_read_uce & 1) - - - -/********************************************************************* - - We have the shift and masks of various fields defined below. - - *********************************************************************/ - -/* MD_REFRESH_CONTROL fields */ - -#define MRC_ENABLE_SHFT 63 -#define MRC_ENABLE_MASK (UINT64_CAST 1 << 63) -#define MRC_ENABLE (UINT64_CAST 1 << 63) -#define MRC_COUNTER_SHFT 12 -#define MRC_COUNTER_MASK (UINT64_CAST 0xfff << 12) -#define MRC_CNT_THRESH_MASK 0xfff -#define MRC_RESET_DEFAULTS (UINT64_CAST 0x800) - -/* MD_DIR_CONFIG fields */ - -#define MDC_DIR_PREMIUM (UINT64_CAST 1 << 0) -#define MDC_IGNORE_ECC_SHFT 1 -#define MDC_IGNORE_ECC_MASK (UINT64_CAST 1 << 1) - -/* MD_MEMORY_CONFIG fields */ - -#define MMC_RP_CONFIG_SHFT 61 -#define MMC_RP_CONFIG_MASK (UINT64_CAST 1 << 61) -#define MMC_RCD_CONFIG_SHFT 60 -#define MMC_RCD_CONFIG_MASK (UINT64_CAST 1 << 60) -#define MMC_MB_NEG_EDGE_SHFT 56 -#define MMC_MB_NEG_EDGE_MASK (UINT64_CAST 0x7 << 56) -#define MMC_SAMPLE_TIME_SHFT 52 -#define MMC_SAMPLE_TIME_MASK (UINT64_CAST 0x3 << 52) -#define MMC_DELAY_MUX_SEL_SHFT 50 -#define MMC_DELAY_MUX_SEL_MASK (UINT64_CAST 0x3 << 50) -#define MMC_PHASE_DELAY_SHFT 49 -#define MMC_PHASE_DELAY_MASK (UINT64_CAST 1 << 49) -#define MMC_DB_NEG_EDGE_SHFT 48 -#define MMC_DB_NEG_EDGE_MASK (UINT64_CAST 1 << 48) -#define MMC_CPU_PROT_IGNORE_SHFT 47 -#define MMC_CPU_PROT_IGNORE_MASK (UINT64_CAST 1 << 47) -#define MMC_IO_PROT_IGNORE_SHFT 46 -#define MMC_IO_PROT_IGNORE_MASK (UINT64_CAST 1 << 46) -#define MMC_IO_PROT_EN_SHFT 45 -#define MMC_IO_PROT_EN_MASK (UINT64_CAST 1 << 45) -#define MMC_CC_ENABLE_SHFT 44 -#define MMC_CC_ENABLE_MASK (UINT64_CAST 1 << 44) -#define MMC_DIMM0_SEL_SHFT 32 -#define MMC_DIMM0_SEL_MASK (UINT64_CAST 0x3 << 32) -#define MMC_DIMM_SIZE_SHFT(_dimm) ((_dimm << 3) + 4) -#define MMC_DIMM_SIZE_MASK(_dimm) (UINT64_CAST 0xf << MMC_DIMM_SIZE_SHFT(_dimm)) -#define MMC_DIMM_WIDTH_SHFT(_dimm) ((_dimm << 3) + 3) -#define MMC_DIMM_WIDTH_MASK(_dimm) (UINT64_CAST 0x1 << MMC_DIMM_WIDTH_SHFT(_dimm)) -#define MMC_DIMM_BANKS_SHFT(_dimm) (_dimm << 3) -#define MMC_DIMM_BANKS_MASK(_dimm) (UINT64_CAST 0x3 << MMC_DIMM_BANKS_SHFT(_dimm)) -#define MMC_BANK_ALL_MASK 0xffffffffLL -/* Default values for write-only bits in MD_MEMORY_CONFIG */ -#define MMC_DEFAULT_BITS (UINT64_CAST 0x7 << MMC_MB_NEG_EDGE_SHFT) - -/* MD_MB_ECC_CONFIG fields */ - -#define MEC_IGNORE_ECC (UINT64_CAST 0x1 << 0) - -/* MD_BIST_DATA fields */ - -#define MBD_BIST_WRITE (UINT64_CAST 1 << 7) -#define MBD_BIST_CYCLE (UINT64_CAST 1 << 6) -#define MBD_BIST_BYTE (UINT64_CAST 1 << 5) -#define MBD_BIST_NIBBLE (UINT64_CAST 1 << 4) -#define MBD_BIST_DATA_MASK 0xf - -/* MD_BIST_CTL fields */ - -#define MBC_DIMM_SHFT 5 -#define MBC_DIMM_MASK (UINT64_CAST 0x3 << 5) -#define MBC_BANK_SHFT 4 -#define MBC_BANK_MASK (UINT64_CAST 0x1 << 4) -#define MBC_BIST_RESET (UINT64_CAST 0x1 << 2) -#define MBC_BIST_STOP (UINT64_CAST 0x1 << 1) -#define MBC_BIST_START (UINT64_CAST 0x1 << 0) - -#define MBC_GO(dimm, bank) \ - (((dimm) << MBC_DIMM_SHFT) & MBC_DIMM_MASK | \ - ((bank) << MBC_BANK_SHFT) & MBC_BANK_MASK | \ - MBC_BIST_START) - -/* MD_BIST_STATUS fields */ - -#define MBS_BIST_DONE (UINT64_CAST 0X1 << 1) -#define MBS_BIST_PASSED (UINT64_CAST 0X1 << 0) - -/* MD_JUNK_BUS_TIMING fields */ - -#define MJT_SYNERGY_ENABLE_SHFT 40 -#define MJT_SYNERGY_ENABLE_MASK (UINT64_CAST 0Xff << MJT_SYNERGY_ENABLE_SHFT) -#define MJT_SYNERGY_SETUP_SHFT 32 -#define MJT_SYNERGY_SETUP_MASK (UINT64_CAST 0Xff << MJT_SYNERGY_SETUP_SHFT) -#define MJT_UART_ENABLE_SHFT 24 -#define MJT_UART_ENABLE_MASK (UINT64_CAST 0Xff << MJT_UART_ENABLE_SHFT) -#define MJT_UART_SETUP_SHFT 16 -#define MJT_UART_SETUP_MASK (UINT64_CAST 0Xff << MJT_UART_SETUP_SHFT) -#define MJT_FPROM_ENABLE_SHFT 8 -#define MJT_FPROM_ENABLE_MASK (UINT64_CAST 0Xff << MJT_FPROM_ENABLE_SHFT) -#define MJT_FPROM_SETUP_SHFT 0 -#define MJT_FPROM_SETUP_MASK (UINT64_CAST 0Xff << MJT_FPROM_SETUP_SHFT) - -#define MEM_ERROR_VALID_CE 1 - - -/* MD_FANDOP_CAC_STAT0, MD_FANDOP_CAC_STAT1 addr field shift */ - -#define MFC_ADDR_SHFT 6 - -#endif /* _ASM_IA64_SN_SN1_HUBMD_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubni.h b/include/asm-ia64/sn/sn1/hubni.h --- a/include/asm-ia64/sn/sn1/hubni.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1781 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBNI_H -#define _ASM_IA64_SN_SN1_HUBNI_H - - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - -#define NI_PORT_STATUS 0x00680000 /* LLP Status */ - - - -#define NI_PORT_RESET 0x00680008 /* - * Reset the Network - * Interface - */ - - - -#define NI_RESET_ENABLE 0x00680010 /* Warm Reset Enable */ - - - -#define NI_DIAG_PARMS 0x00680018 /* - * Diagnostic - * Parameters - */ - - - -#define NI_CHANNEL_CONTROL 0x00680020 /* - * Virtual channel - * control - */ - - - -#define NI_CHANNEL_TEST 0x00680028 /* LLP Test Control. */ - - - -#define NI_PORT_PARMS 0x00680030 /* LLP Parameters */ - - - -#define NI_CHANNEL_AGE 0x00680038 /* - * Network age - * injection control - */ - - - -#define NI_PORT_ERRORS 0x00680100 /* Errors */ - - - -#define NI_PORT_HEADER_A 0x00680108 /* - * Error Header first - * half - */ - - - -#define NI_PORT_HEADER_B 0x00680110 /* - * Error Header second - * half - */ - - - -#define NI_PORT_SIDEBAND 0x00680118 /* Error Sideband */ - - - -#define NI_PORT_ERROR_CLEAR 0x00680120 /* - * Clear the Error - * bits - */ - - - -#define NI_LOCAL_TABLE_0 0x00681000 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_1 0x00681008 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_2 0x00681010 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_3 0x00681018 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_4 0x00681020 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_5 0x00681028 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_6 0x00681030 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_7 0x00681038 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_8 0x00681040 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_9 0x00681048 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_10 0x00681050 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_11 0x00681058 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_12 0x00681060 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_13 0x00681068 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_14 0x00681070 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_15 0x00681078 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_16 0x00681080 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_17 0x00681088 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_18 0x00681090 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_19 0x00681098 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_20 0x006810A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_21 0x006810A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_22 0x006810B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_23 0x006810B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_24 0x006810C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_25 0x006810C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_26 0x006810D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_27 0x006810D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_28 0x006810E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_29 0x006810E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_30 0x006810F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_31 0x006810F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_32 0x00681100 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_33 0x00681108 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_34 0x00681110 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_35 0x00681118 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_36 0x00681120 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_37 0x00681128 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_38 0x00681130 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_39 0x00681138 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_40 0x00681140 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_41 0x00681148 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_42 0x00681150 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_43 0x00681158 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_44 0x00681160 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_45 0x00681168 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_46 0x00681170 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_47 0x00681178 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_48 0x00681180 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_49 0x00681188 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_50 0x00681190 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_51 0x00681198 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_52 0x006811A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_53 0x006811A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_54 0x006811B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_55 0x006811B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_56 0x006811C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_57 0x006811C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_58 0x006811D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_59 0x006811D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_60 0x006811E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_61 0x006811E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_62 0x006811F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_63 0x006811F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_64 0x00681200 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_65 0x00681208 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_66 0x00681210 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_67 0x00681218 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_68 0x00681220 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_69 0x00681228 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_70 0x00681230 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_71 0x00681238 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_72 0x00681240 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_73 0x00681248 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_74 0x00681250 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_75 0x00681258 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_76 0x00681260 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_77 0x00681268 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_78 0x00681270 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_79 0x00681278 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_80 0x00681280 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_81 0x00681288 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_82 0x00681290 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_83 0x00681298 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_84 0x006812A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_85 0x006812A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_86 0x006812B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_87 0x006812B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_88 0x006812C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_89 0x006812C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_90 0x006812D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_91 0x006812D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_92 0x006812E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_93 0x006812E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_94 0x006812F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_95 0x006812F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_96 0x00681300 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_97 0x00681308 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_98 0x00681310 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_99 0x00681318 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_100 0x00681320 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_101 0x00681328 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_102 0x00681330 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_103 0x00681338 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_104 0x00681340 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_105 0x00681348 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_106 0x00681350 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_107 0x00681358 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_108 0x00681360 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_109 0x00681368 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_110 0x00681370 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_111 0x00681378 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_112 0x00681380 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_113 0x00681388 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_114 0x00681390 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_115 0x00681398 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_116 0x006813A0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_117 0x006813A8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_118 0x006813B0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_119 0x006813B8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_120 0x006813C0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_121 0x006813C8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_122 0x006813D0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_123 0x006813D8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_124 0x006813E0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_125 0x006813E8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_126 0x006813F0 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_LOCAL_TABLE_127 0x006813F8 /* - * Base of Local - * Mapping Table 0-127 - */ - - - -#define NI_GLOBAL_TABLE 0x00682000 /* - * Base of Global - * Mapping Table - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * This register describes the LLP status. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_status_u { - bdrkreg_t ni_port_status_regval; - struct { - bdrkreg_t ps_port_status : 2; - bdrkreg_t ps_remote_power : 1; - bdrkreg_t ps_rsvd : 61; - } ni_port_status_fld_s; -} ni_port_status_u_t; - -#else - -typedef union ni_port_status_u { - bdrkreg_t ni_port_status_regval; - struct { - bdrkreg_t ps_rsvd : 61; - bdrkreg_t ps_remote_power : 1; - bdrkreg_t ps_port_status : 2; - } ni_port_status_fld_s; -} ni_port_status_u_t; - -#endif - - - - -/************************************************************************ - * * - * Writing this register issues a reset to the network interface. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_reset_u { - bdrkreg_t ni_port_reset_regval; - struct { - bdrkreg_t pr_link_reset_out : 1; - bdrkreg_t pr_port_reset : 1; - bdrkreg_t pr_local_reset : 1; - bdrkreg_t pr_rsvd : 61; - } ni_port_reset_fld_s; -} ni_port_reset_u_t; - -#else - -typedef union ni_port_reset_u { - bdrkreg_t ni_port_reset_regval; - struct { - bdrkreg_t pr_rsvd : 61; - bdrkreg_t pr_local_reset : 1; - bdrkreg_t pr_port_reset : 1; - bdrkreg_t pr_link_reset_out : 1; - } ni_port_reset_fld_s; -} ni_port_reset_u_t; - -#endif - - - -/************************************************************************ - * * - * This register contains the warm reset enable bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_reset_enable_u { - bdrkreg_t ni_reset_enable_regval; - struct { - bdrkreg_t re_reset_ok : 1; - bdrkreg_t re_rsvd : 63; - } ni_reset_enable_fld_s; -} ni_reset_enable_u_t; - -#else - -typedef union ni_reset_enable_u { - bdrkreg_t ni_reset_enable_regval; - struct { - bdrkreg_t re_rsvd : 63; - bdrkreg_t re_reset_ok : 1; - } ni_reset_enable_fld_s; -} ni_reset_enable_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains parameters for diagnostics. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_diag_parms_u { - bdrkreg_t ni_diag_parms_regval; - struct { - bdrkreg_t dp_send_data_error : 1; - bdrkreg_t dp_port_disable : 1; - bdrkreg_t dp_send_err_off : 1; - bdrkreg_t dp_rsvd : 61; - } ni_diag_parms_fld_s; -} ni_diag_parms_u_t; - -#else - -typedef union ni_diag_parms_u { - bdrkreg_t ni_diag_parms_regval; - struct { - bdrkreg_t dp_rsvd : 61; - bdrkreg_t dp_send_err_off : 1; - bdrkreg_t dp_port_disable : 1; - bdrkreg_t dp_send_data_error : 1; - } ni_diag_parms_fld_s; -} ni_diag_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the virtual channel selection control for * - * outgoing messages from the Bedrock. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_control_u { - bdrkreg_t ni_channel_control_regval; - struct { - bdrkreg_t cc_vch_one_request : 1; - bdrkreg_t cc_vch_two_request : 1; - bdrkreg_t cc_vch_nine_request : 1; - bdrkreg_t cc_vch_vector_request : 1; - bdrkreg_t cc_vch_one_reply : 1; - bdrkreg_t cc_vch_two_reply : 1; - bdrkreg_t cc_vch_nine_reply : 1; - bdrkreg_t cc_vch_vector_reply : 1; - bdrkreg_t cc_send_vch_sel : 1; - bdrkreg_t cc_rsvd : 55; - } ni_channel_control_fld_s; -} ni_channel_control_u_t; - -#else - -typedef union ni_channel_control_u { - bdrkreg_t ni_channel_control_regval; - struct { - bdrkreg_t cc_rsvd : 55; - bdrkreg_t cc_send_vch_sel : 1; - bdrkreg_t cc_vch_vector_reply : 1; - bdrkreg_t cc_vch_nine_reply : 1; - bdrkreg_t cc_vch_two_reply : 1; - bdrkreg_t cc_vch_one_reply : 1; - bdrkreg_t cc_vch_vector_request : 1; - bdrkreg_t cc_vch_nine_request : 1; - bdrkreg_t cc_vch_two_request : 1; - bdrkreg_t cc_vch_one_request : 1; - } ni_channel_control_fld_s; -} ni_channel_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register allows access to the LLP test logic. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_test_u { - bdrkreg_t ni_channel_test_regval; - struct { - bdrkreg_t ct_testseed : 20; - bdrkreg_t ct_testmask : 8; - bdrkreg_t ct_testdata : 20; - bdrkreg_t ct_testvalid : 1; - bdrkreg_t ct_testcberr : 1; - bdrkreg_t ct_testflit : 3; - bdrkreg_t ct_testclear : 1; - bdrkreg_t ct_testerrcapture : 1; - bdrkreg_t ct_rsvd : 9; - } ni_channel_test_fld_s; -} ni_channel_test_u_t; - -#else - -typedef union ni_channel_test_u { - bdrkreg_t ni_channel_test_regval; - struct { - bdrkreg_t ct_rsvd : 9; - bdrkreg_t ct_testerrcapture : 1; - bdrkreg_t ct_testclear : 1; - bdrkreg_t ct_testflit : 3; - bdrkreg_t ct_testcberr : 1; - bdrkreg_t ct_testvalid : 1; - bdrkreg_t ct_testdata : 20; - bdrkreg_t ct_testmask : 8; - bdrkreg_t ct_testseed : 20; - } ni_channel_test_fld_s; -} ni_channel_test_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains LLP port parameters and enables for the * - * capture of header data. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_parms_u { - bdrkreg_t ni_port_parms_regval; - struct { - bdrkreg_t pp_max_burst : 10; - bdrkreg_t pp_null_timeout : 6; - bdrkreg_t pp_max_retry : 10; - bdrkreg_t pp_d_avail_sel : 2; - bdrkreg_t pp_rsvd_1 : 1; - bdrkreg_t pp_first_err_enable : 1; - bdrkreg_t pp_squash_err_enable : 1; - bdrkreg_t pp_vch_err_enable : 4; - bdrkreg_t pp_rsvd : 29; - } ni_port_parms_fld_s; -} ni_port_parms_u_t; - -#else - -typedef union ni_port_parms_u { - bdrkreg_t ni_port_parms_regval; - struct { - bdrkreg_t pp_rsvd : 29; - bdrkreg_t pp_vch_err_enable : 4; - bdrkreg_t pp_squash_err_enable : 1; - bdrkreg_t pp_first_err_enable : 1; - bdrkreg_t pp_rsvd_1 : 1; - bdrkreg_t pp_d_avail_sel : 2; - bdrkreg_t pp_max_retry : 10; - bdrkreg_t pp_null_timeout : 6; - bdrkreg_t pp_max_burst : 10; - } ni_port_parms_fld_s; -} ni_port_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains the age at which request and reply packets * - * are injected into the network. This feature allows replies to be * - * given a higher fixed priority than requests, which can be * - * important in some network saturation situations. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_channel_age_u { - bdrkreg_t ni_channel_age_regval; - struct { - bdrkreg_t ca_request_inject_age : 8; - bdrkreg_t ca_reply_inject_age : 8; - bdrkreg_t ca_rsvd : 48; - } ni_channel_age_fld_s; -} ni_channel_age_u_t; - -#else - -typedef union ni_channel_age_u { - bdrkreg_t ni_channel_age_regval; - struct { - bdrkreg_t ca_rsvd : 48; - bdrkreg_t ca_reply_inject_age : 8; - bdrkreg_t ca_request_inject_age : 8; - } ni_channel_age_fld_s; -} ni_channel_age_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains latched LLP port and problematic message * - * errors. The contents are the same information as the * - * NI_PORT_ERROR_CLEAR register, but, in this register read accesses * - * are non-destructive. Bits [52:24] assert the NI interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_errors_u { - bdrkreg_t ni_port_errors_regval; - struct { - bdrkreg_t pe_sn_error_count : 8; - bdrkreg_t pe_cb_error_count : 8; - bdrkreg_t pe_retry_count : 8; - bdrkreg_t pe_tail_timeout : 4; - bdrkreg_t pe_fifo_overflow : 4; - bdrkreg_t pe_external_short : 4; - bdrkreg_t pe_external_long : 4; - bdrkreg_t pe_external_bad_header : 4; - bdrkreg_t pe_internal_short : 4; - bdrkreg_t pe_internal_long : 4; - bdrkreg_t pe_link_reset_in : 1; - bdrkreg_t pe_rsvd : 11; - } ni_port_errors_fld_s; -} ni_port_errors_u_t; - -#else - -typedef union ni_port_errors_u { - bdrkreg_t ni_port_errors_regval; - struct { - bdrkreg_t pe_rsvd : 11; - bdrkreg_t pe_link_reset_in : 1; - bdrkreg_t pe_internal_long : 4; - bdrkreg_t pe_internal_short : 4; - bdrkreg_t pe_external_bad_header : 4; - bdrkreg_t pe_external_long : 4; - bdrkreg_t pe_external_short : 4; - bdrkreg_t pe_fifo_overflow : 4; - bdrkreg_t pe_tail_timeout : 4; - bdrkreg_t pe_retry_count : 8; - bdrkreg_t pe_cb_error_count : 8; - bdrkreg_t pe_sn_error_count : 8; - } ni_port_errors_fld_s; -} ni_port_errors_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register provides the sideband data associated with the * - * NI_PORT_HEADER registers and also additional data for error * - * processing. This register is not cleared on reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_sideband_u { - bdrkreg_t ni_port_sideband_regval; - struct { - bdrkreg_t ps_sideband : 8; - bdrkreg_t ps_bad_dest : 1; - bdrkreg_t ps_bad_prexsel : 1; - bdrkreg_t ps_rcv_error : 1; - bdrkreg_t ps_bad_message : 1; - bdrkreg_t ps_squash : 1; - bdrkreg_t ps_sn_status : 1; - bdrkreg_t ps_cb_status : 1; - bdrkreg_t ps_send_error : 1; - bdrkreg_t ps_vch_active : 4; - bdrkreg_t ps_rsvd : 44; - } ni_port_sideband_fld_s; -} ni_port_sideband_u_t; - -#else - -typedef union ni_port_sideband_u { - bdrkreg_t ni_port_sideband_regval; - struct { - bdrkreg_t ps_rsvd : 44; - bdrkreg_t ps_vch_active : 4; - bdrkreg_t ps_send_error : 1; - bdrkreg_t ps_cb_status : 1; - bdrkreg_t ps_sn_status : 1; - bdrkreg_t ps_squash : 1; - bdrkreg_t ps_bad_message : 1; - bdrkreg_t ps_rcv_error : 1; - bdrkreg_t ps_bad_prexsel : 1; - bdrkreg_t ps_bad_dest : 1; - bdrkreg_t ps_sideband : 8; - } ni_port_sideband_fld_s; -} ni_port_sideband_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register contains latched LLP port and problematic message * - * errors. The contents are the same information as the * - * NI_PORT_ERROR_CLEAR register, but, in this register read accesses * - * are non-destructive. Bits [52:24] assert the NI interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_error_clear_u { - bdrkreg_t ni_port_error_clear_regval; - struct { - bdrkreg_t pec_sn_error_count : 8; - bdrkreg_t pec_cb_error_count : 8; - bdrkreg_t pec_retry_count : 8; - bdrkreg_t pec_tail_timeout : 4; - bdrkreg_t pec_fifo_overflow : 4; - bdrkreg_t pec_external_short : 4; - bdrkreg_t pec_external_long : 4; - bdrkreg_t pec_external_bad_header : 4; - bdrkreg_t pec_internal_short : 4; - bdrkreg_t pec_internal_long : 4; - bdrkreg_t pec_link_reset_in : 1; - bdrkreg_t pec_rsvd : 11; - } ni_port_error_clear_fld_s; -} ni_port_error_clear_u_t; - -#else - -typedef union ni_port_error_clear_u { - bdrkreg_t ni_port_error_clear_regval; - struct { - bdrkreg_t pec_rsvd : 11; - bdrkreg_t pec_link_reset_in : 1; - bdrkreg_t pec_internal_long : 4; - bdrkreg_t pec_internal_short : 4; - bdrkreg_t pec_external_bad_header : 4; - bdrkreg_t pec_external_long : 4; - bdrkreg_t pec_external_short : 4; - bdrkreg_t pec_fifo_overflow : 4; - bdrkreg_t pec_tail_timeout : 4; - bdrkreg_t pec_retry_count : 8; - bdrkreg_t pec_cb_error_count : 8; - bdrkreg_t pec_sn_error_count : 8; - } ni_port_error_clear_fld_s; -} ni_port_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 7-bit LocalCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_local_table_0_u { - bdrkreg_t ni_local_table_0_regval; - struct { - bdrkreg_t lt0_next_exit_port : 4; - bdrkreg_t lt0_next_vch_lsb : 1; - bdrkreg_t lt0_rsvd : 59; - } ni_local_table_0_fld_s; -} ni_local_table_0_u_t; - -#else - -typedef union ni_local_table_0_u { - bdrkreg_t ni_local_table_0_regval; - struct { - bdrkreg_t lt0_rsvd : 59; - bdrkreg_t lt0_next_vch_lsb : 1; - bdrkreg_t lt0_next_exit_port : 4; - } ni_local_table_0_fld_s; -} ni_local_table_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 7-bit LocalCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_local_table_127_u { - bdrkreg_t ni_local_table_127_regval; - struct { - bdrkreg_t lt1_next_exit_port : 4; - bdrkreg_t lt1_next_vch_lsb : 1; - bdrkreg_t lt1_rsvd : 59; - } ni_local_table_127_fld_s; -} ni_local_table_127_u_t; - -#else - -typedef union ni_local_table_127_u { - bdrkreg_t ni_local_table_127_regval; - struct { - bdrkreg_t lt1_rsvd : 59; - bdrkreg_t lt1_next_vch_lsb : 1; - bdrkreg_t lt1_next_exit_port : 4; - } ni_local_table_127_fld_s; -} ni_local_table_127_u_t; - -#endif - - - - -/************************************************************************ - * * - * Lookup table for the next hop's exit port. The table entry * - * selection is based on the 1-bit MetaCube routing destination. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union ni_global_table_u { - bdrkreg_t ni_global_table_regval; - struct { - bdrkreg_t gt_next_exit_port : 4; - bdrkreg_t gt_next_vch_lsb : 1; - bdrkreg_t gt_rsvd : 59; - } ni_global_table_fld_s; -} ni_global_table_u_t; - -#else - -typedef union ni_global_table_u { - bdrkreg_t ni_global_table_regval; - struct { - bdrkreg_t gt_rsvd : 59; - bdrkreg_t gt_next_vch_lsb : 1; - bdrkreg_t gt_next_exit_port : 4; - } ni_global_table_fld_s; -} ni_global_table_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines which were not formed into structures are * - * probably indentical to another register, and the name of the * - * register is provided against each of these registers. This * - * information needs to be checked carefully * - * * - * NI_LOCAL_TABLE_1 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_2 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_3 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_4 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_5 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_6 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_7 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_8 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_9 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_10 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_11 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_12 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_13 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_14 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_15 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_16 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_17 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_18 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_19 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_20 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_21 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_22 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_23 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_24 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_25 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_26 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_27 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_28 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_29 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_30 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_31 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_32 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_33 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_34 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_35 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_36 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_37 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_38 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_39 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_40 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_41 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_42 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_43 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_44 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_45 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_46 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_47 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_48 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_49 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_50 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_51 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_52 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_53 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_54 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_55 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_56 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_57 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_58 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_59 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_60 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_61 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_62 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_63 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_64 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_65 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_66 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_67 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_68 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_69 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_70 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_71 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_72 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_73 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_74 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_75 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_76 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_77 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_78 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_79 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_80 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_81 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_82 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_83 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_84 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_85 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_86 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_87 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_88 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_89 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_90 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_91 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_92 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_93 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_94 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_95 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_96 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_97 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_98 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_99 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_100 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_101 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_102 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_103 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_104 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_105 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_106 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_107 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_108 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_109 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_110 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_111 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_112 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_113 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_114 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_115 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_116 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_117 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_118 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_119 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_120 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_121 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_122 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_123 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_124 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_125 NI_LOCAL_TABLE_0 * - * NI_LOCAL_TABLE_126 NI_LOCAL_TABLE_0 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * The following defines were not formed into structures * - * * - * This could be because the document did not contain details of the * - * register, or because the automated script did not recognize the * - * register details in the documentation. If these register need * - * structure definition, please create them manually * - * * - * NI_PORT_HEADER_A 0x680108 * - * NI_PORT_HEADER_B 0x680110 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBNI_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubni_next.h b/include/asm-ia64/sn/sn1/hubni_next.h --- a/include/asm-ia64/sn/sn1/hubni_next.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,174 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBNI_NEXT_H -#define _ASM_IA64_SN_SN1_HUBNI_NEXT_H - -#define NI_LOCAL_ENTRIES 128 -#define NI_META_ENTRIES 1 - -#define NI_LOCAL_TABLE(_x) (NI_LOCAL_TABLE_0 + (8 * (_x))) -#define NI_META_TABLE(_x) (NI_GLOBAL_TABLE + (8 * (_x))) - -/************************************************************** - - Masks and shifts for NI registers are defined below. - -**************************************************************/ - -#define NPS_LINKUP_SHFT 1 -#define NPS_LINKUP_MASK (UINT64_CAST 0x1 << 1) - - -#define NPR_LOCALRESET (UINT64_CAST 1 << 2) /* Reset loc. bdrck */ -#define NPR_PORTRESET (UINT64_CAST 1 << 1) /* Send warm reset */ -#define NPR_LINKRESET (UINT64_CAST 1 << 0) /* Send link reset */ - -/* NI_DIAG_PARMS bit definitions */ -#define NDP_SENDERROR (UINT64_CAST 1 << 0) /* Send data error */ -#define NDP_PORTDISABLE (UINT64_CAST 1 << 1) /* Port disable */ -#define NDP_SENDERROFF (UINT64_CAST 1 << 2) /* Disable send error recovery */ - - -/* NI_PORT_ERROR mask and shift definitions (some are not present in SN0) */ - -#define NPE_LINKRESET (UINT64_CAST 1 << 52) -#define NPE_INTLONG_SHFT 48 -#define NPE_INTLONG_MASK (UINT64_CAST 0xf << NPE_INTLONG_SHFT) -#define NPE_INTSHORT_SHFT 44 -#define NPE_INTSHORT_MASK (UINT64_CAST 0xf << NPE_INTSHORT_SHFT) -#define NPE_EXTBADHEADER_SHFT 40 -#define NPE_EXTBADHEADER_MASK (UINT64_CAST 0xf << NPE_EXTBADHEADER_SHFT) -#define NPE_EXTLONG_SHFT 36 -#define NPE_EXTLONG_MASK (UINT64_CAST 0xf << NPE_EXTLONG_SHFT) -#define NPE_EXTSHORT_SHFT 32 -#define NPE_EXTSHORT_MASK (UINT64_CAST 0xf << NPE_EXTSHORT_SHFT) -#define NPE_FIFOOVFLOW_SHFT 28 -#define NPE_FIFOOVFLOW_MASK (UINT64_CAST 0xf << NPE_FIFOOVFLOW_SHFT) -#define NPE_TAILTO_SHFT 24 -#define NPE_TAILTO_MASK (UINT64_CAST 0xf << NPE_TAILTO_SHFT) -#define NPE_RETRYCOUNT_SHFT 16 -#define NPE_RETRYCOUNT_MASK (UINT64_CAST 0xff << NPE_RETRYCOUNT_SHFT) -#define NPE_CBERRCOUNT_SHFT 8 -#define NPE_CBERRCOUNT_MASK (UINT64_CAST 0xff << NPE_CBERRCOUNT_SHFT) -#define NPE_SNERRCOUNT_SHFT 0 -#define NPE_SNERRCOUNT_MASK (UINT64_CAST 0xff << NPE_SNERRCOUNT_SHFT) - -#define NPE_COUNT_MAX 0xff - -#define NPE_FATAL_ERRORS (NPE_LINKRESET | NPE_INTLONG_MASK |\ - NPE_INTSHORT_MASK | NPE_EXTBADHEADER_MASK |\ - NPE_EXTLONG_MASK | NPE_EXTSHORT_MASK |\ - NPE_FIFOOVFLOW_MASK | NPE_TAILTO_MASK) - -#ifndef __ASSEMBLY__ -/* NI_PORT_HEADER[AB] registers (not automatically generated) */ - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_header_a_u { - bdrkreg_t ni_port_header_a_regval; - struct { - bdrkreg_t pha_v : 1; - bdrkreg_t pha_age : 8; - bdrkreg_t pha_direction : 4; - bdrkreg_t pha_destination : 8; - bdrkreg_t pha_reserved_1 : 3; - bdrkreg_t pha_command : 8; - bdrkreg_t pha_prexsel : 3; - bdrkreg_t pha_address_b : 27; - bdrkreg_t pha_reserved : 2; - } ni_port_header_a_fld_s; -} ni_port_header_a_u_t; - -#else - -typedef union ni_port_header_a_u { - bdrkreg_t ni_port_header_a_regval; - struct { - bdrkreg_t pha_reserved : 2; - bdrkreg_t pha_address_b : 27; - bdrkreg_t pha_prexsel : 3; - bdrkreg_t pha_command : 8; - bdrkreg_t pha_reserved_1 : 3; - bdrkreg_t pha_destination : 8; - bdrkreg_t pha_direction : 4; - bdrkreg_t pha_age : 8; - bdrkreg_t pha_v : 1; - } ni_port_header_a_fld_s; -} ni_port_header_a_u_t; - -#endif - -#ifdef LITTLE_ENDIAN - -typedef union ni_port_header_b_u { - bdrkreg_t ni_port_header_b_regval; - struct { - bdrkreg_t phb_supplemental : 11; - bdrkreg_t phb_reserved_2 : 5; - bdrkreg_t phb_source : 11; - bdrkreg_t phb_reserved_1 : 8; - bdrkreg_t phb_address_a : 3; - bdrkreg_t phb_address_c : 8; - bdrkreg_t phb_reserved : 18; - } ni_port_header_b_fld_s; -} ni_port_header_b_u_t; - -#else - -typedef union ni_port_header_b_u { - bdrkreg_t ni_port_header_b_regval; - struct { - bdrkreg_t phb_reserved : 18; - bdrkreg_t phb_address_c : 8; - bdrkreg_t phb_address_a : 3; - bdrkreg_t phb_reserved_1 : 8; - bdrkreg_t phb_source : 11; - bdrkreg_t phb_reserved_2 : 5; - bdrkreg_t phb_supplemental : 11; - } ni_port_header_b_fld_s; -} ni_port_header_b_u_t; - -#endif -#endif - -/* NI_RESET_ENABLE mask definitions */ - -#define NRE_RESETOK (UINT64_CAST 1) /* Let LLP reset bedrock */ - -/* NI PORT_ERRORS, Max number of RETRY_COUNT, Check Bit, and Sequence */ -/* Number errors (8 bit counters that do not wrap). */ -#define NI_LLP_RETRY_MAX 0xff -#define NI_LLP_CB_MAX 0xff -#define NI_LLP_SN_MAX 0xff - -/* NI_PORT_PARMS shift and mask definitions */ - -#define NPP_VCH_ERR_EN_SHFT 31 -#define NPP_VCH_ERR_EN_MASK (0xf << NPP_VCH_ERR_EN_SHFT) -#define NPP_SQUASH_ERR_EN_SHFT 30 -#define NPP_SQUASH_ERR_EN_MASK (0x1 << NPP_SQUASH_ERR_EN_SHFT) -#define NPP_FIRST_ERR_EN_SHFT 29 -#define NPP_FIRST_ERR_EN_MASK (0x1 << NPP_FIRST_ERR_EN_SHFT) -#define NPP_D_AVAIL_SEL_SHFT 26 -#define NPP_D_AVAIL_SEL_MASK (0x3 << NPP_D_AVAIL_SEL_SHFT) -#define NPP_MAX_RETRY_SHFT 16 -#define NPP_MAX_RETRY_MASK (0x3ff << NPP_MAX_RETRY_SHFT) -#define NPP_NULL_TIMEOUT_SHFT 10 -#define NPP_NULL_TIMEOUT_MASK (0x3f << NPP_NULL_TIMEOUT_SHFT) -#define NPP_MAX_BURST_SHFT 0 -#define NPP_MAX_BURST_MASK (0x3ff << NPP_MAX_BURST_SHFT) - -#define NPP_RESET_DEFAULTS (0xf << NPP_VCH_ERR_EN_SHFT | \ - 0x1 << NPP_FIRST_ERR_EN_SHFT | \ - 0x3ff << NPP_MAX_RETRY_SHFT | \ - 0x6 << NPP_NULL_TIMEOUT_SHFT | \ - 0x3f0 << NPP_MAX_BURST_SHFT) - -#endif /* _ASM_IA64_SN_SN1_HUBNI_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubpi.h b/include/asm-ia64/sn/sn1/hubpi.h --- a/include/asm-ia64/sn/sn1/hubpi.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,4263 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBPI_H -#define _ASM_IA64_SN_SN1_HUBPI_H - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define PI_CPU_PROTECT 0x00000000 /* CPU Protection */ - - - -#define PI_PROT_OVRRD 0x00000008 /* - * Clear CPU - * Protection bit in - * CPU_PROTECT - */ - - - -#define PI_IO_PROTECT 0x00000010 /* - * Interrupt Pending - * Protection for IO - * access - */ - - - -#define PI_REGION_PRESENT 0x00000018 /* Region present */ - - - -#define PI_CPU_NUM 0x00000020 /* CPU Number ID */ - - - -#define PI_CALIAS_SIZE 0x00000028 /* Cached Alias Size */ - - - -#define PI_MAX_CRB_TIMEOUT 0x00000030 /* - * Maximum Timeout for - * CRB - */ - - - -#define PI_CRB_SFACTOR 0x00000038 /* - * Scale Factor for - * CRB Timeout - */ - - - -#define PI_CPU_PRESENT_A 0x00000040 /* - * CPU Present for - * CPU_A - */ - - - -#define PI_CPU_PRESENT_B 0x00000048 /* - * CPU Present for - * CPU_B - */ - - - -#define PI_CPU_ENABLE_A 0x00000050 /* - * CPU Enable for - * CPU_A - */ - - - -#define PI_CPU_ENABLE_B 0x00000058 /* - * CPU Enable for - * CPU_B - */ - - - -#define PI_REPLY_LEVEL 0x00010060 /* - * Reply FIFO Priority - * Control - */ - - - -#define PI_GFX_CREDIT_MODE 0x00020068 /* - * Graphics Credit - * Mode - */ - - - -#define PI_NMI_A 0x00000070 /* - * Non-maskable - * Interrupt to CPU A - */ - - - -#define PI_NMI_B 0x00000078 /* - * Non-maskable - * Interrupt to CPU B - */ - - - -#define PI_INT_PEND_MOD 0x00000090 /* - * Interrupt Pending - * Modify - */ - - - -#define PI_INT_PEND0 0x00000098 /* Interrupt Pending 0 */ - - - -#define PI_INT_PEND1 0x000000A0 /* Interrupt Pending 1 */ - - - -#define PI_INT_MASK0_A 0x000000A8 /* - * Interrupt Mask 0 - * for CPU A - */ - - - -#define PI_INT_MASK1_A 0x000000B0 /* - * Interrupt Mask 1 - * for CPU A - */ - - - -#define PI_INT_MASK0_B 0x000000B8 /* - * Interrupt Mask 0 - * for CPU B - */ - - - -#define PI_INT_MASK1_B 0x000000C0 /* - * Interrupt Mask 1 - * for CPU B - */ - - - -#define PI_CC_PEND_SET_A 0x000000C8 /* - * CC Interrupt - * Pending for CPU A - */ - - - -#define PI_CC_PEND_SET_B 0x000000D0 /* - * CC Interrupt - * Pending for CPU B - */ - - - -#define PI_CC_PEND_CLR_A 0x000000D8 /* - * CPU to CPU - * Interrupt Pending - * Clear for CPU A - */ - - - -#define PI_CC_PEND_CLR_B 0x000000E0 /* - * CPU to CPU - * Interrupt Pending - * Clear for CPU B - */ - - - -#define PI_CC_MASK 0x000000E8 /* - * Mask of both - * CC_PENDs - */ - - - -#define PI_INT_PEND1_REMAP 0x000000F0 /* - * Remap Interrupt - * Pending - */ - - - -#define PI_RT_COUNTER 0x00030100 /* Real Time Counter */ - - - -#define PI_RT_COMPARE_A 0x00000108 /* Real Time Compare A */ - - - -#define PI_RT_COMPARE_B 0x00000110 /* Real Time Compare B */ - - - -#define PI_PROFILE_COMPARE 0x00000118 /* Profiling Compare */ - - - -#define PI_RT_INT_PEND_A 0x00000120 /* - * RT interrupt - * pending - */ - - - -#define PI_RT_INT_PEND_B 0x00000128 /* - * RT interrupt - * pending - */ - - - -#define PI_PROF_INT_PEND_A 0x00000130 /* - * Profiling interrupt - * pending - */ - - - -#define PI_PROF_INT_PEND_B 0x00000138 /* - * Profiling interrupt - * pending - */ - - - -#define PI_RT_INT_EN_A 0x00000140 /* RT Interrupt Enable */ - - - -#define PI_RT_INT_EN_B 0x00000148 /* RT Interrupt Enable */ - - - -#define PI_PROF_INT_EN_A 0x00000150 /* - * Profiling Interrupt - * Enable - */ - - - -#define PI_PROF_INT_EN_B 0x00000158 /* - * Profiling Interrupt - * Enable - */ - - - -#define PI_DEBUG_SEL 0x00000160 /* PI Debug Select */ - - - -#define PI_INT_PEND_MOD_ALIAS 0x00000180 /* - * Interrupt Pending - * Modify - */ - - - -#define PI_PERF_CNTL_A 0x00040200 /* - * Performance Counter - * Control A - */ - - - -#define PI_PERF_CNTR0_A 0x00040208 /* - * Performance Counter - * 0 A - */ - - - -#define PI_PERF_CNTR1_A 0x00040210 /* - * Performance Counter - * 1 A - */ - - - -#define PI_PERF_CNTL_B 0x00050200 /* - * Performance Counter - * Control B - */ - - - -#define PI_PERF_CNTR0_B 0x00050208 /* - * Performance Counter - * 0 B - */ - - - -#define PI_PERF_CNTR1_B 0x00050210 /* - * Performance Counter - * 1 B - */ - - - -#define PI_GFX_PAGE_A 0x00000300 /* Graphics Page */ - - - -#define PI_GFX_CREDIT_CNTR_A 0x00000308 /* - * Graphics Credit - * Counter - */ - - - -#define PI_GFX_BIAS_A 0x00000310 /* TRex+ BIAS */ - - - -#define PI_GFX_INT_CNTR_A 0x00000318 /* - * Graphics Interrupt - * Counter - */ - - - -#define PI_GFX_INT_CMP_A 0x00000320 /* - * Graphics Interrupt - * Compare - */ - - - -#define PI_GFX_PAGE_B 0x00000328 /* Graphics Page */ - - - -#define PI_GFX_CREDIT_CNTR_B 0x00000330 /* - * Graphics Credit - * Counter - */ - - - -#define PI_GFX_BIAS_B 0x00000338 /* TRex+ BIAS */ - - - -#define PI_GFX_INT_CNTR_B 0x00000340 /* - * Graphics Interrupt - * Counter - */ - - - -#define PI_GFX_INT_CMP_B 0x00000348 /* - * Graphics Interrupt - * Compare - */ - - - -#define PI_ERR_INT_PEND_WR 0x000003F8 /* - * Error Interrupt - * Pending (Writable) - */ - - - -#define PI_ERR_INT_PEND 0x00000400 /* - * Error Interrupt - * Pending - */ - - - -#define PI_ERR_INT_MASK_A 0x00000408 /* - * Error Interrupt - * Mask CPU_A - */ - - - -#define PI_ERR_INT_MASK_B 0x00000410 /* - * Error Interrupt - * Mask CPU_B - */ - - - -#define PI_ERR_STACK_ADDR_A 0x00000418 /* - * Error Stack Address - * Pointer - */ - - - -#define PI_ERR_STACK_ADDR_B 0x00000420 /* - * Error Stack Address - * Pointer - */ - - - -#define PI_ERR_STACK_SIZE 0x00000428 /* Error Stack Size */ - - - -#define PI_ERR_STATUS0_A 0x00000430 /* Error Status 0 */ - - - -#define PI_ERR_STATUS0_A_CLR 0x00000438 /* Error Status 0 */ - - - -#define PI_ERR_STATUS1_A 0x00000440 /* Error Status 1 */ - - - -#define PI_ERR_STATUS1_A_CLR 0x00000448 /* Error Status 1 */ - - - -#define PI_ERR_STATUS0_B 0x00000450 /* Error Status 0 */ - - - -#define PI_ERR_STATUS0_B_CLR 0x00000458 /* Error Status 0 */ - - - -#define PI_ERR_STATUS1_B 0x00000460 /* Error Status 1 */ - - - -#define PI_ERR_STATUS1_B_CLR 0x00000468 /* Error Status 1 */ - - - -#define PI_SPOOL_CMP_A 0x00000470 /* Spool Compare */ - - - -#define PI_SPOOL_CMP_B 0x00000478 /* Spool Compare */ - - - -#define PI_CRB_TIMEOUT_A 0x00000480 /* - * CRB entries which - * have timed out but - * are still valid - */ - - - -#define PI_CRB_TIMEOUT_B 0x00000488 /* - * CRB entries which - * have timed out but - * are still valid - */ - - - -#define PI_SYSAD_ERRCHK_EN 0x00000490 /* - * enables - * sysad/cmd/state - * error checking - */ - - - -#define PI_FORCE_BAD_CHECK_BIT_A 0x00000498 /* - * force SysAD Check - * Bit error - */ - - - -#define PI_FORCE_BAD_CHECK_BIT_B 0x000004A0 /* - * force SysAD Check - * Bit error - */ - - - -#define PI_NACK_CNT_A 0x000004A8 /* - * consecutive NACK - * counter - */ - - - -#define PI_NACK_CNT_B 0x000004B0 /* - * consecutive NACK - * counter - */ - - - -#define PI_NACK_CMP 0x000004B8 /* NACK count compare */ - - - -#define PI_SPOOL_MASK 0x000004C0 /* Spool error mask */ - - - -#define PI_SPURIOUS_HDR_0 0x000004C8 /* Spurious Error 0 */ - - - -#define PI_SPURIOUS_HDR_1 0x000004D0 /* Spurious Error 1 */ - - - -#define PI_ERR_INJECT 0x000004D8 /* - * SysAD bus error - * injection - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether incoming CPU-initiated PIO Read and * - * Write to local PI registers are allowed. If access is allowed, the * - * PI's response to a partial read is a PRPLY message, and the * - * response to a partial write is a PACK message. If access is not * - * allowed, the PI's response to a partial read is a PRERR message, * - * and the response to a partial write is a PWERR message. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_cpu_protect_u { - bdrkreg_t pi_cpu_protect_regval; - struct { - bdrkreg_t cp_cpu_protect : 64; - } pi_cpu_protect_fld_s; -} pi_cpu_protect_u_t; - - - - -/************************************************************************ - * * - * A write with a special data pattern allows any CPU to set its * - * region's bit in CPU_PROTECT. This register has data pattern * - * protection. * - * * - ************************************************************************/ - - - - -typedef union pi_prot_ovrrd_u { - bdrkreg_t pi_prot_ovrrd_regval; - struct { - bdrkreg_t po_prot_ovrrd : 64; - } pi_prot_ovrrd_fld_s; -} pi_prot_ovrrd_u_t; - - - - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether incoming IO-initiated interrupts are * - * allowed to set bits in INT_PEND0 and INT_PEND1. If access is * - * allowed, the PI's response to a partial read is a PRPLY message, * - * and the response to a partial write is a PACK message. If access * - * is not allowed, the PI's response to a partial read is a PRERR * - * message, and the response to a partial write is a PWERR message. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_io_protect_u { - bdrkreg_t pi_io_protect_regval; - struct { - bdrkreg_t ip_io_protect : 64; - } pi_io_protect_fld_s; -} pi_io_protect_u_t; - - - - -/************************************************************************ - * * - * Description: This read/write register determines on a * - * bit-per-region basis whether read access from a local processor to * - * the region is permissible. For example, setting a bit to 0 * - * prevents speculative reads to that non-existent node. If a read * - * request to a non-present region occurs, an ERR response is issued * - * to the TRex+ (no PI error registers are modified). It is up to * - * software to load this register with the proper contents. * - * Region-present checking is only done for coherent read requests - * - * partial reads/writes will be issued to a non-present region. The * - * setting of these bits does not affect a node's access to its * - * CALIAS space. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -typedef union pi_region_present_u { - bdrkreg_t pi_region_present_regval; - struct { - bdrkreg_t rp_region_present : 64; - } pi_region_present_fld_s; -} pi_region_present_u_t; - - - - -/************************************************************************ - * * - * A read to the location will allow a CPU to identify itself as * - * either CPU_A or CPU_B, and will indicate whether the CPU is * - * connected to PI 0 or PI 1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_num_u { - bdrkreg_t pi_cpu_num_regval; - struct { - bdrkreg_t cn_cpu_num : 1; - bdrkreg_t cn_pi_id : 1; - bdrkreg_t cn_rsvd : 62; - } pi_cpu_num_fld_s; -} pi_cpu_num_u_t; - -#else - -typedef union pi_cpu_num_u { - bdrkreg_t pi_cpu_num_regval; - struct { - bdrkreg_t cn_rsvd : 62; - bdrkreg_t cn_pi_id : 1; - bdrkreg_t cn_cpu_num : 1; - } pi_cpu_num_fld_s; -} pi_cpu_num_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This read/write location determines the size of the * - * Calias Space. * - * This register is not reset by a soft reset. * - * NOTE: For predictable behavior, all Calias spaces in a system must * - * be set to the same size. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_calias_size_u { - bdrkreg_t pi_calias_size_regval; - struct { - bdrkreg_t cs_calias_size : 4; - bdrkreg_t cs_rsvd : 60; - } pi_calias_size_fld_s; -} pi_calias_size_u_t; - -#else - -typedef union pi_calias_size_u { - bdrkreg_t pi_calias_size_regval; - struct { - bdrkreg_t cs_rsvd : 60; - bdrkreg_t cs_calias_size : 4; - } pi_calias_size_fld_s; -} pi_calias_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines at which value (increment) * - * the CRB Timeout Counters cause a timeout error to occur. See * - * Section 3.4.2.2, "Time-outs in RRB and WRB" in the * - * Processor Interface chapter, volume 1 of this document for more * - * details. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_max_crb_timeout_u { - bdrkreg_t pi_max_crb_timeout_regval; - struct { - bdrkreg_t mct_max_timeout : 8; - bdrkreg_t mct_rsvd : 56; - } pi_max_crb_timeout_fld_s; -} pi_max_crb_timeout_u_t; - -#else - -typedef union pi_max_crb_timeout_u { - bdrkreg_t pi_max_crb_timeout_regval; - struct { - bdrkreg_t mct_rsvd : 56; - bdrkreg_t mct_max_timeout : 8; - } pi_max_crb_timeout_fld_s; -} pi_max_crb_timeout_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines how often a valid CRB's * - * Timeout Counter is incremented. See Section 3.4.2.2, * - * "Time-outs in RRB and WRB" in the Processor Interface * - * chapter, volume 1 of this document for more details. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_sfactor_u { - bdrkreg_t pi_crb_sfactor_regval; - struct { - bdrkreg_t cs_sfactor : 24; - bdrkreg_t cs_rsvd : 40; - } pi_crb_sfactor_fld_s; -} pi_crb_sfactor_u_t; - -#else - -typedef union pi_crb_sfactor_u { - bdrkreg_t pi_crb_sfactor_regval; - struct { - bdrkreg_t cs_rsvd : 40; - bdrkreg_t cs_sfactor : 24; - } pi_crb_sfactor_fld_s; -} pi_crb_sfactor_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The PI sets this * - * bit when it sees the first transaction initiated by the associated * - * CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_present_a_u { - bdrkreg_t pi_cpu_present_a_regval; - struct { - bdrkreg_t cpa_cpu_present : 1; - bdrkreg_t cpa_rsvd : 63; - } pi_cpu_present_a_fld_s; -} pi_cpu_present_a_u_t; - -#else - -typedef union pi_cpu_present_a_u { - bdrkreg_t pi_cpu_present_a_regval; - struct { - bdrkreg_t cpa_rsvd : 63; - bdrkreg_t cpa_cpu_present : 1; - } pi_cpu_present_a_fld_s; -} pi_cpu_present_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The PI sets this * - * bit when it sees the first transaction initiated by the associated * - * CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_present_b_u { - bdrkreg_t pi_cpu_present_b_regval; - struct { - bdrkreg_t cpb_cpu_present : 1; - bdrkreg_t cpb_rsvd : 63; - } pi_cpu_present_b_fld_s; -} pi_cpu_present_b_u_t; - -#else - -typedef union pi_cpu_present_b_u { - bdrkreg_t pi_cpu_present_b_regval; - struct { - bdrkreg_t cpb_rsvd : 63; - bdrkreg_t cpb_cpu_present : 1; - } pi_cpu_present_b_fld_s; -} pi_cpu_present_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * Read/Write location determines whether the associated CPU is * - * enabled to issue external requests. When this bit is zero for a * - * processor, the PI ignores SysReq_L from that processor, and so * - * never grants it the bus. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_enable_a_u { - bdrkreg_t pi_cpu_enable_a_regval; - struct { - bdrkreg_t cea_cpu_enable : 1; - bdrkreg_t cea_rsvd : 63; - } pi_cpu_enable_a_fld_s; -} pi_cpu_enable_a_u_t; - -#else - -typedef union pi_cpu_enable_a_u { - bdrkreg_t pi_cpu_enable_a_regval; - struct { - bdrkreg_t cea_rsvd : 63; - bdrkreg_t cea_cpu_enable : 1; - } pi_cpu_enable_a_fld_s; -} pi_cpu_enable_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * Read/Write location determines whether the associated CPU is * - * enabled to issue external requests. When this bit is zero for a * - * processor, the PI ignores SysReq_L from that processor, and so * - * never grants it the bus. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_cpu_enable_b_u { - bdrkreg_t pi_cpu_enable_b_regval; - struct { - bdrkreg_t ceb_cpu_enable : 1; - bdrkreg_t ceb_rsvd : 63; - } pi_cpu_enable_b_fld_s; -} pi_cpu_enable_b_u_t; - -#else - -typedef union pi_cpu_enable_b_u { - bdrkreg_t pi_cpu_enable_b_regval; - struct { - bdrkreg_t ceb_rsvd : 63; - bdrkreg_t ceb_cpu_enable : 1; - } pi_cpu_enable_b_fld_s; -} pi_cpu_enable_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A write to this * - * location will cause an NMI to be issued to the CPU. * - * * - ************************************************************************/ - - - - -typedef union pi_nmi_a_u { - bdrkreg_t pi_nmi_a_regval; - struct { - bdrkreg_t na_nmi_cpu : 64; - } pi_nmi_a_fld_s; -} pi_nmi_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A write to this * - * location will cause an NMI to be issued to the CPU. * - * * - ************************************************************************/ - - - - -typedef union pi_nmi_b_u { - bdrkreg_t pi_nmi_b_regval; - struct { - bdrkreg_t nb_nmi_cpu : 64; - } pi_nmi_b_fld_s; -} pi_nmi_b_u_t; - - - - -/************************************************************************ - * * - * A write to this register allows a single bit in the INT_PEND0 or * - * INT_PEND1 registers to be set or cleared. If 6 is clear, a bit is * - * modified in INT_PEND0, while if 6 is set, a bit is modified in * - * INT_PEND1. The value in 5:0 (ranging from 63 to 0) will determine * - * which bit in the register is effected. The value of 8 will * - * determine whether the desired bit is set (8=1) or cleared (8=0). * - * This is the only register which is accessible by IO issued PWRI * - * command and is protected through the IO_PROTECT register. If the * - * region bit in the IO_PROTECT is not set then a WERR reply is * - * issued. CPU access is controlled through CPU_PROTECT. The contents * - * of this register are masked with the contents of INT_MASK_A * - * (INT_MASK_B) to determine whether an L2 interrupt is issued to * - * CPU_A (CPU_B). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend_mod_u { - bdrkreg_t pi_int_pend_mod_regval; - struct { - bdrkreg_t ipm_bit_select : 6; - bdrkreg_t ipm_reg_select : 1; - bdrkreg_t ipm_rsvd_1 : 1; - bdrkreg_t ipm_value : 1; - bdrkreg_t ipm_rsvd : 55; - } pi_int_pend_mod_fld_s; -} pi_int_pend_mod_u_t; - -#else - -typedef union pi_int_pend_mod_u { - bdrkreg_t pi_int_pend_mod_regval; - struct { - bdrkreg_t ipm_rsvd : 55; - bdrkreg_t ipm_value : 1; - bdrkreg_t ipm_rsvd_1 : 1; - bdrkreg_t ipm_reg_select : 1; - bdrkreg_t ipm_bit_select : 6; - } pi_int_pend_mod_fld_s; -} pi_int_pend_mod_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read-only register provides information about interrupts * - * that are currently pending. The interrupts in this register map to * - * interrupt level 2 (L2). The GFX_INT_A/B bits are set by hardware * - * but must be cleared by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend0_u { - bdrkreg_t pi_int_pend0_regval; - struct { - bdrkreg_t ip_int_pend0_lo : 1; - bdrkreg_t ip_gfx_int_a : 1; - bdrkreg_t ip_gfx_int_b : 1; - bdrkreg_t ip_page_migration : 1; - bdrkreg_t ip_uart_ucntrl : 1; - bdrkreg_t ip_or_cc_pend_a : 1; - bdrkreg_t ip_or_cc_pend_b : 1; - bdrkreg_t ip_int_pend0_hi : 57; - } pi_int_pend0_fld_s; -} pi_int_pend0_u_t; - -#else - -typedef union pi_int_pend0_u { - bdrkreg_t pi_int_pend0_regval; - struct { - bdrkreg_t ip_int_pend0_hi : 57; - bdrkreg_t ip_or_cc_pend_b : 1; - bdrkreg_t ip_or_cc_pend_a : 1; - bdrkreg_t ip_uart_ucntrl : 1; - bdrkreg_t ip_page_migration : 1; - bdrkreg_t ip_gfx_int_b : 1; - bdrkreg_t ip_gfx_int_a : 1; - bdrkreg_t ip_int_pend0_lo : 1; - } pi_int_pend0_fld_s; -} pi_int_pend0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read-only register provides information about interrupts * - * that are currently pending. The interrupts in this register map to * - * interrupt level 3 (L3), unless remapped by the INT_PEND1_REMAP * - * register. The SYS_COR_ERR_A/B, RTC_DROP_OUT, and NACK_INT_A/B bits * - * are set by hardware but must be cleared by software. The * - * SYSTEM_SHUTDOWN, NI_ERROR, LB_ERROR and XB_ERROR bits just reflect * - * the value of other logic, and cannot be changed by PI register * - * writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend1_u { - bdrkreg_t pi_int_pend1_regval; - struct { - bdrkreg_t ip_int_pend1 : 54; - bdrkreg_t ip_xb_error : 1; - bdrkreg_t ip_lb_error : 1; - bdrkreg_t ip_nack_int_a : 1; - bdrkreg_t ip_nack_int_b : 1; - bdrkreg_t ip_perf_cntr_oflow : 1; - bdrkreg_t ip_sys_cor_err_b : 1; - bdrkreg_t ip_sys_cor_err_a : 1; - bdrkreg_t ip_md_corr_error : 1; - bdrkreg_t ip_ni_error : 1; - bdrkreg_t ip_system_shutdown : 1; - } pi_int_pend1_fld_s; -} pi_int_pend1_u_t; - -#else - -typedef union pi_int_pend1_u { - bdrkreg_t pi_int_pend1_regval; - struct { - bdrkreg_t ip_system_shutdown : 1; - bdrkreg_t ip_ni_error : 1; - bdrkreg_t ip_md_corr_error : 1; - bdrkreg_t ip_sys_cor_err_a : 1; - bdrkreg_t ip_sys_cor_err_b : 1; - bdrkreg_t ip_perf_cntr_oflow : 1; - bdrkreg_t ip_nack_int_b : 1; - bdrkreg_t ip_nack_int_a : 1; - bdrkreg_t ip_lb_error : 1; - bdrkreg_t ip_xb_error : 1; - bdrkreg_t ip_int_pend1 : 54; - } pi_int_pend1_fld_s; -} pi_int_pend1_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND0 to * - * determine whether an L2 interrupt (bit 10 of the processor's Cause * - * register) is sent to CPU_A if the same bit in the INT_PEND0 * - * register is also set. Only one processor in a Bedrock should * - * enable the PAGE_MIGRATION bit/interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_mask0_a_u { - bdrkreg_t pi_int_mask0_a_regval; - struct { - bdrkreg_t ima_int_mask0_lo : 1; - bdrkreg_t ima_gfx_int_a : 1; - bdrkreg_t ima_gfx_int_b : 1; - bdrkreg_t ima_page_migration : 1; - bdrkreg_t ima_uart_ucntrl : 1; - bdrkreg_t ima_or_ccp_mask_a : 1; - bdrkreg_t ima_or_ccp_mask_b : 1; - bdrkreg_t ima_int_mask0_hi : 57; - } pi_int_mask0_a_fld_s; -} pi_int_mask0_a_u_t; - -#else - -typedef union pi_int_mask0_a_u { - bdrkreg_t pi_int_mask0_a_regval; - struct { - bdrkreg_t ima_int_mask0_hi : 57; - bdrkreg_t ima_or_ccp_mask_b : 1; - bdrkreg_t ima_or_ccp_mask_a : 1; - bdrkreg_t ima_uart_ucntrl : 1; - bdrkreg_t ima_page_migration : 1; - bdrkreg_t ima_gfx_int_b : 1; - bdrkreg_t ima_gfx_int_a : 1; - bdrkreg_t ima_int_mask0_lo : 1; - } pi_int_mask0_a_fld_s; -} pi_int_mask0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND1 to * - * determine whether an interrupt should be sent. Bits 63:32 always * - * generate an L3 interrupt (bit 11 of the processor's Cause * - * register) is sent to CPU_A if the same bit in the INT_PEND1 * - * register is set. Bits 31:0 can generate either an L3 or L2 * - * interrupt, depending on the value of INT_PEND1_REMAP[3:0]. Only * - * one processor in a Bedrock should enable the NI_ERROR, LB_ERROR, * - * XB_ERROR and MD_CORR_ERROR bits. * - * * - ************************************************************************/ - - - - -typedef union pi_int_mask1_a_u { - bdrkreg_t pi_int_mask1_a_regval; - struct { - bdrkreg_t ima_int_mask1 : 64; - } pi_int_mask1_a_fld_s; -} pi_int_mask1_a_u_t; - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND0 to * - * determine whether an L2 interrupt (bit 10 of the processor's Cause * - * register) is sent to CPU_B if the same bit in the INT_PEND0 * - * register is also set. Only one processor in a Bedrock should * - * enable the PAGE_MIGRATION bit/interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_mask0_b_u { - bdrkreg_t pi_int_mask0_b_regval; - struct { - bdrkreg_t imb_int_mask0_lo : 1; - bdrkreg_t imb_gfx_int_a : 1; - bdrkreg_t imb_gfx_int_b : 1; - bdrkreg_t imb_page_migration : 1; - bdrkreg_t imb_uart_ucntrl : 1; - bdrkreg_t imb_or_ccp_mask_a : 1; - bdrkreg_t imb_or_ccp_mask_b : 1; - bdrkreg_t imb_int_mask0_hi : 57; - } pi_int_mask0_b_fld_s; -} pi_int_mask0_b_u_t; - -#else - -typedef union pi_int_mask0_b_u { - bdrkreg_t pi_int_mask0_b_regval; - struct { - bdrkreg_t imb_int_mask0_hi : 57; - bdrkreg_t imb_or_ccp_mask_b : 1; - bdrkreg_t imb_or_ccp_mask_a : 1; - bdrkreg_t imb_uart_ucntrl : 1; - bdrkreg_t imb_page_migration : 1; - bdrkreg_t imb_gfx_int_b : 1; - bdrkreg_t imb_gfx_int_a : 1; - bdrkreg_t imb_int_mask0_lo : 1; - } pi_int_mask0_b_fld_s; -} pi_int_mask0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This read/write register masks the contents of INT_PEND1 to * - * determine whether an interrupt should be sent. Bits 63:32 always * - * generate an L3 interrupt (bit 11 of the processor's Cause * - * register) is sent to CPU_B if the same bit in the INT_PEND1 * - * register is set. Bits 31:0 can generate either an L3 or L2 * - * interrupt, depending on the value of INT_PEND1_REMAP[3:0]. Only * - * one processor in a Bedrock should enable the NI_ERROR, LB_ERROR, * - * XB_ERROR and MD_CORR_ERROR bits. * - * * - ************************************************************************/ - - - - -typedef union pi_int_mask1_b_u { - bdrkreg_t pi_int_mask1_b_regval; - struct { - bdrkreg_t imb_int_mask1 : 64; - } pi_int_mask1_b_fld_s; -} pi_int_mask1_b_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. These registers do * - * not have access protection. A store to this location by a CPU will * - * cause the bit corresponding to the source's region to be set in * - * CC_PEND_A (or CC_PEND_B). The contents of CC_PEND_A (or CC_PEND_B) * - * determines on a bit-per-region basis whether a CPU-to-CPU * - * interrupt is pending CPU_A (or CPU_B). * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_set_a_u { - bdrkreg_t pi_cc_pend_set_a_regval; - struct { - bdrkreg_t cpsa_cc_pend : 64; - } pi_cc_pend_set_a_fld_s; -} pi_cc_pend_set_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. These registers do * - * not have access protection. A store to this location by a CPU will * - * cause the bit corresponding to the source's region to be set in * - * CC_PEND_A (or CC_PEND_B). The contents of CC_PEND_A (or CC_PEND_B) * - * determines on a bit-per-region basis whether a CPU-to-CPU * - * interrupt is pending CPU_A (or CPU_B). * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_set_b_u { - bdrkreg_t pi_cc_pend_set_b_regval; - struct { - bdrkreg_t cpsb_cc_pend : 64; - } pi_cc_pend_set_b_fld_s; -} pi_cc_pend_set_b_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Reading this * - * location will return the contents of CC_PEND_A (or CC_PEND_B). * - * Writing this location will clear the bits corresponding to which * - * data bits are driven high during the store; therefore, storing all * - * ones would clear all bits. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_clr_a_u { - bdrkreg_t pi_cc_pend_clr_a_regval; - struct { - bdrkreg_t cpca_cc_pend : 64; - } pi_cc_pend_clr_a_fld_s; -} pi_cc_pend_clr_a_u_t; - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Reading this * - * location will return the contents of CC_PEND_A (or CC_PEND_B). * - * Writing this location will clear the bits corresponding to which * - * data bits are driven high during the store; therefore, storing all * - * ones would clear all bits. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_pend_clr_b_u { - bdrkreg_t pi_cc_pend_clr_b_regval; - struct { - bdrkreg_t cpcb_cc_pend : 64; - } pi_cc_pend_clr_b_fld_s; -} pi_cc_pend_clr_b_u_t; - - - - -/************************************************************************ - * * - * This read/write register masks the contents of both CC_PEND_A and * - * CC_PEND_B. * - * * - ************************************************************************/ - - - - -typedef union pi_cc_mask_u { - bdrkreg_t pi_cc_mask_regval; - struct { - bdrkreg_t cm_cc_mask : 64; - } pi_cc_mask_fld_s; -} pi_cc_mask_u_t; - - - - -/************************************************************************ - * * - * This read/write register redirects INT_PEND1[31:0] from L3 to L2 * - * interrupt level.Bit 4 in this register is used to enable error * - * interrupt forwarding to the II. When this bit is set, if any of * - * the three memory interrupts (correctable error, uncorrectable * - * error, or page migration), or the NI, LB or XB error interrupts * - * are set, the PI_II_ERROR_INT wire will be asserted. When this wire * - * is asserted, the II will send an interrupt to the node specified * - * in its IIDSR (Interrupt Destination Register). This allows these * - * interrupts to be forwarded to another node. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend1_remap_u { - bdrkreg_t pi_int_pend1_remap_regval; - struct { - bdrkreg_t ipr_remap_0 : 1; - bdrkreg_t ipr_remap_1 : 1; - bdrkreg_t ipr_remap_2 : 1; - bdrkreg_t ipr_remap_3 : 1; - bdrkreg_t ipr_error_forward : 1; - bdrkreg_t ipr_reserved : 59; - } pi_int_pend1_remap_fld_s; -} pi_int_pend1_remap_u_t; - -#else - -typedef union pi_int_pend1_remap_u { - bdrkreg_t pi_int_pend1_remap_regval; - struct { - bdrkreg_t ipr_reserved : 59; - bdrkreg_t ipr_error_forward : 1; - bdrkreg_t ipr_remap_3 : 1; - bdrkreg_t ipr_remap_2 : 1; - bdrkreg_t ipr_remap_1 : 1; - bdrkreg_t ipr_remap_0 : 1; - } pi_int_pend1_remap_fld_s; -} pi_int_pend1_remap_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the real time * - * counter (RT_Counter) is equal to the value in this register, the * - * RT_INT_PEND register is set, which causes a Level-4 interrupt to * - * be sent to the processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_compare_a_u { - bdrkreg_t pi_rt_compare_a_regval; - struct { - bdrkreg_t rca_rt_compare : 55; - bdrkreg_t rca_rsvd : 9; - } pi_rt_compare_a_fld_s; -} pi_rt_compare_a_u_t; - -#else - -typedef union pi_rt_compare_a_u { - bdrkreg_t pi_rt_compare_a_regval; - struct { - bdrkreg_t rca_rsvd : 9; - bdrkreg_t rca_rt_compare : 55; - } pi_rt_compare_a_fld_s; -} pi_rt_compare_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the real time * - * counter (RT_Counter) is equal to the value in this register, the * - * RT_INT_PEND register is set, which causes a Level-4 interrupt to * - * be sent to the processor. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_compare_b_u { - bdrkreg_t pi_rt_compare_b_regval; - struct { - bdrkreg_t rcb_rt_compare : 55; - bdrkreg_t rcb_rsvd : 9; - } pi_rt_compare_b_fld_s; -} pi_rt_compare_b_u_t; - -#else - -typedef union pi_rt_compare_b_u { - bdrkreg_t pi_rt_compare_b_regval; - struct { - bdrkreg_t rcb_rsvd : 9; - bdrkreg_t rcb_rt_compare : 55; - } pi_rt_compare_b_fld_s; -} pi_rt_compare_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * When the least significant 32 bits of the real time counter * - * (RT_Counter) are equal to the value in this register, the * - * PROF_INT_PEND_A and PROF_INT_PEND_B registers are set to 0x1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_profile_compare_u { - bdrkreg_t pi_profile_compare_regval; - struct { - bdrkreg_t pc_profile_compare : 32; - bdrkreg_t pc_rsvd : 32; - } pi_profile_compare_fld_s; -} pi_profile_compare_u_t; - -#else - -typedef union pi_profile_compare_u { - bdrkreg_t pi_profile_compare_regval; - struct { - bdrkreg_t pc_rsvd : 32; - bdrkreg_t pc_profile_compare : 32; - } pi_profile_compare_fld_s; -} pi_profile_compare_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If the bit in the * - * corresponding RT_INT_EN_A/B register is set, the processor's level * - * 5 interrupt is set to the value of the RTC_INT_PEND bit in this * - * register. Storing any value to this location will clear the * - * RTC_INT_PEND bit in the register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_pend_a_u { - bdrkreg_t pi_rt_int_pend_a_regval; - struct { - bdrkreg_t ripa_rtc_int_pend : 1; - bdrkreg_t ripa_rsvd : 63; - } pi_rt_int_pend_a_fld_s; -} pi_rt_int_pend_a_u_t; - -#else - -typedef union pi_rt_int_pend_a_u { - bdrkreg_t pi_rt_int_pend_a_regval; - struct { - bdrkreg_t ripa_rsvd : 63; - bdrkreg_t ripa_rtc_int_pend : 1; - } pi_rt_int_pend_a_fld_s; -} pi_rt_int_pend_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If the bit in the * - * corresponding RT_INT_EN_A/B register is set, the processor's level * - * 5 interrupt is set to the value of the RTC_INT_PEND bit in this * - * register. Storing any value to this location will clear the * - * RTC_INT_PEND bit in the register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_pend_b_u { - bdrkreg_t pi_rt_int_pend_b_regval; - struct { - bdrkreg_t ripb_rtc_int_pend : 1; - bdrkreg_t ripb_rsvd : 63; - } pi_rt_int_pend_b_fld_s; -} pi_rt_int_pend_b_u_t; - -#else - -typedef union pi_rt_int_pend_b_u { - bdrkreg_t pi_rt_int_pend_b_regval; - struct { - bdrkreg_t ripb_rsvd : 63; - bdrkreg_t ripb_rtc_int_pend : 1; - } pi_rt_int_pend_b_fld_s; -} pi_rt_int_pend_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Both registers are * - * set when the PROFILE_COMPARE register is equal to bits [31:0] of * - * the RT_Counter. If the bit in the corresponding PROF_INT_EN_A/B * - * register is set, the processor's level 5 interrupt is set to the * - * value of the PROF_INT_PEND bit in this register. Storing any value * - * to this location will clear the PROF_INT_PEND bit in the register. * - * The reason for having A and B versions of this register is that * - * they need to be cleared independently. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_pend_a_u { - bdrkreg_t pi_prof_int_pend_a_regval; - struct { - bdrkreg_t pipa_prof_int_pend : 1; - bdrkreg_t pipa_rsvd : 63; - } pi_prof_int_pend_a_fld_s; -} pi_prof_int_pend_a_u_t; - -#else - -typedef union pi_prof_int_pend_a_u { - bdrkreg_t pi_prof_int_pend_a_regval; - struct { - bdrkreg_t pipa_rsvd : 63; - bdrkreg_t pipa_prof_int_pend : 1; - } pi_prof_int_pend_a_fld_s; -} pi_prof_int_pend_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Both registers are * - * set when the PROFILE_COMPARE register is equal to bits [31:0] of * - * the RT_Counter. If the bit in the corresponding PROF_INT_EN_A/B * - * register is set, the processor's level 5 interrupt is set to the * - * value of the PROF_INT_PEND bit in this register. Storing any value * - * to this location will clear the PROF_INT_PEND bit in the register. * - * The reason for having A and B versions of this register is that * - * they need to be cleared independently. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_pend_b_u { - bdrkreg_t pi_prof_int_pend_b_regval; - struct { - bdrkreg_t pipb_prof_int_pend : 1; - bdrkreg_t pipb_rsvd : 63; - } pi_prof_int_pend_b_fld_s; -} pi_prof_int_pend_b_u_t; - -#else - -typedef union pi_prof_int_pend_b_u { - bdrkreg_t pi_prof_int_pend_b_regval; - struct { - bdrkreg_t pipb_rsvd : 63; - bdrkreg_t pipb_prof_int_pend : 1; - } pi_prof_int_pend_b_fld_s; -} pi_prof_int_pend_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables RTC * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_en_a_u { - bdrkreg_t pi_rt_int_en_a_regval; - struct { - bdrkreg_t riea_rtc_int_en : 1; - bdrkreg_t riea_rsvd : 63; - } pi_rt_int_en_a_fld_s; -} pi_rt_int_en_a_u_t; - -#else - -typedef union pi_rt_int_en_a_u { - bdrkreg_t pi_rt_int_en_a_regval; - struct { - bdrkreg_t riea_rsvd : 63; - bdrkreg_t riea_rtc_int_en : 1; - } pi_rt_int_en_a_fld_s; -} pi_rt_int_en_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables RTC * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_int_en_b_u { - bdrkreg_t pi_rt_int_en_b_regval; - struct { - bdrkreg_t rieb_rtc_int_en : 1; - bdrkreg_t rieb_rsvd : 63; - } pi_rt_int_en_b_fld_s; -} pi_rt_int_en_b_u_t; - -#else - -typedef union pi_rt_int_en_b_u { - bdrkreg_t pi_rt_int_en_b_regval; - struct { - bdrkreg_t rieb_rsvd : 63; - bdrkreg_t rieb_rtc_int_en : 1; - } pi_rt_int_en_b_fld_s; -} pi_rt_int_en_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables profiling * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_en_a_u { - bdrkreg_t pi_prof_int_en_a_regval; - struct { - bdrkreg_t piea_prof_int_en : 1; - bdrkreg_t piea_rsvd : 63; - } pi_prof_int_en_a_fld_s; -} pi_prof_int_en_a_u_t; - -#else - -typedef union pi_prof_int_en_a_u { - bdrkreg_t pi_prof_int_en_a_regval; - struct { - bdrkreg_t piea_rsvd : 63; - bdrkreg_t piea_prof_int_en : 1; - } pi_prof_int_en_a_fld_s; -} pi_prof_int_en_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. Enables profiling * - * interrupt to the associated CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_prof_int_en_b_u { - bdrkreg_t pi_prof_int_en_b_regval; - struct { - bdrkreg_t pieb_prof_int_en : 1; - bdrkreg_t pieb_rsvd : 63; - } pi_prof_int_en_b_fld_s; -} pi_prof_int_en_b_u_t; - -#else - -typedef union pi_prof_int_en_b_u { - bdrkreg_t pi_prof_int_en_b_regval; - struct { - bdrkreg_t pieb_rsvd : 63; - bdrkreg_t pieb_prof_int_en : 1; - } pi_prof_int_en_b_fld_s; -} pi_prof_int_en_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls operation of the debug data from the PI, * - * along with Debug_Sel[2:0] from the Debug module. For some values * - * of Debug_Sel[2:0], the B_SEL bit selects whether the debug bits * - * are looking at the processor A or processor B logic. The remaining * - * bits select which signal(s) are ORed to create DebugData bits 31 * - * and 30 for all of the PI debug selections. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_debug_sel_u { - bdrkreg_t pi_debug_sel_regval; - struct { - bdrkreg_t ds_low_t5cc_a : 1; - bdrkreg_t ds_low_t5cc_b : 1; - bdrkreg_t ds_low_totcc_a : 1; - bdrkreg_t ds_low_totcc_b : 1; - bdrkreg_t ds_low_reqcc_a : 1; - bdrkreg_t ds_low_reqcc_b : 1; - bdrkreg_t ds_low_rplcc_a : 1; - bdrkreg_t ds_low_rplcc_b : 1; - bdrkreg_t ds_low_intcc : 1; - bdrkreg_t ds_low_perf_inc_a_0 : 1; - bdrkreg_t ds_low_perf_inc_a_1 : 1; - bdrkreg_t ds_low_perf_inc_b_0 : 1; - bdrkreg_t ds_low_perf_inc_b_1 : 1; - bdrkreg_t ds_high_t5cc_a : 1; - bdrkreg_t ds_high_t5cc_b : 1; - bdrkreg_t ds_high_totcc_a : 1; - bdrkreg_t ds_high_totcc_b : 1; - bdrkreg_t ds_high_reqcc_a : 1; - bdrkreg_t ds_high_reqcc_b : 1; - bdrkreg_t ds_high_rplcc_a : 1; - bdrkreg_t ds_high_rplcc_b : 1; - bdrkreg_t ds_high_intcc : 1; - bdrkreg_t ds_high_perf_inc_a_0 : 1; - bdrkreg_t ds_high_perf_inc_a_1 : 1; - bdrkreg_t ds_high_perf_inc_b_0 : 1; - bdrkreg_t ds_high_perf_inc_b_1 : 1; - bdrkreg_t ds_b_sel : 1; - bdrkreg_t ds_rsvd : 37; - } pi_debug_sel_fld_s; -} pi_debug_sel_u_t; - -#else - -typedef union pi_debug_sel_u { - bdrkreg_t pi_debug_sel_regval; - struct { - bdrkreg_t ds_rsvd : 37; - bdrkreg_t ds_b_sel : 1; - bdrkreg_t ds_high_perf_inc_b_1 : 1; - bdrkreg_t ds_high_perf_inc_b_0 : 1; - bdrkreg_t ds_high_perf_inc_a_1 : 1; - bdrkreg_t ds_high_perf_inc_a_0 : 1; - bdrkreg_t ds_high_intcc : 1; - bdrkreg_t ds_high_rplcc_b : 1; - bdrkreg_t ds_high_rplcc_a : 1; - bdrkreg_t ds_high_reqcc_b : 1; - bdrkreg_t ds_high_reqcc_a : 1; - bdrkreg_t ds_high_totcc_b : 1; - bdrkreg_t ds_high_totcc_a : 1; - bdrkreg_t ds_high_t5cc_b : 1; - bdrkreg_t ds_high_t5cc_a : 1; - bdrkreg_t ds_low_perf_inc_b_1 : 1; - bdrkreg_t ds_low_perf_inc_b_0 : 1; - bdrkreg_t ds_low_perf_inc_a_1 : 1; - bdrkreg_t ds_low_perf_inc_a_0 : 1; - bdrkreg_t ds_low_intcc : 1; - bdrkreg_t ds_low_rplcc_b : 1; - bdrkreg_t ds_low_rplcc_a : 1; - bdrkreg_t ds_low_reqcc_b : 1; - bdrkreg_t ds_low_reqcc_a : 1; - bdrkreg_t ds_low_totcc_b : 1; - bdrkreg_t ds_low_totcc_a : 1; - bdrkreg_t ds_low_t5cc_b : 1; - bdrkreg_t ds_low_t5cc_a : 1; - } pi_debug_sel_fld_s; -} pi_debug_sel_u_t; - -#endif - - -/************************************************************************ - * * - * A write to this register allows a single bit in the INT_PEND0 or * - * INT_PEND1 registers to be set or cleared. If 6 is clear, a bit is * - * modified in INT_PEND0, while if 6 is set, a bit is modified in * - * INT_PEND1. The value in 5:0 (ranging from 63 to 0) will determine * - * which bit in the register is effected. The value of 8 will * - * determine whether the desired bit is set (8=1) or cleared (8=0). * - * This is the only register which is accessible by IO issued PWRI * - * command and is protected through the IO_PROTECT register. If the * - * region bit in the IO_PROTECT is not set then a WERR reply is * - * issued. CPU access is controlled through CPU_PROTECT. The contents * - * of this register are masked with the contents of INT_MASK_A * - * (INT_MASK_B) to determine whether an L2 interrupt is issued to * - * CPU_A (CPU_B). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_int_pend_mod_alias_u { - bdrkreg_t pi_int_pend_mod_alias_regval; - struct { - bdrkreg_t ipma_bit_select : 6; - bdrkreg_t ipma_reg_select : 1; - bdrkreg_t ipma_rsvd_1 : 1; - bdrkreg_t ipma_value : 1; - bdrkreg_t ipma_rsvd : 55; - } pi_int_pend_mod_alias_fld_s; -} pi_int_pend_mod_alias_u_t; - -#else - -typedef union pi_int_pend_mod_alias_u { - bdrkreg_t pi_int_pend_mod_alias_regval; - struct { - bdrkreg_t ipma_rsvd : 55; - bdrkreg_t ipma_value : 1; - bdrkreg_t ipma_rsvd_1 : 1; - bdrkreg_t ipma_reg_select : 1; - bdrkreg_t ipma_bit_select : 6; - } pi_int_pend_mod_alias_fld_s; -} pi_int_pend_mod_alias_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * specifies the value of the Graphics Page. Uncached writes into the * - * Graphics Page (with uncached attribute of IO) are done with GFXWS * - * commands rather than the normal PWRI commands. GFXWS commands are * - * tracked with the graphics credit counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_page_a_u { - bdrkreg_t pi_gfx_page_a_regval; - struct { - bdrkreg_t gpa_rsvd_1 : 17; - bdrkreg_t gpa_gfx_page_addr : 23; - bdrkreg_t gpa_en_gfx_page : 1; - bdrkreg_t gpa_rsvd : 23; - } pi_gfx_page_a_fld_s; -} pi_gfx_page_a_u_t; - -#else - -typedef union pi_gfx_page_a_u { - bdrkreg_t pi_gfx_page_a_regval; - struct { - bdrkreg_t gpa_rsvd : 23; - bdrkreg_t gpa_en_gfx_page : 1; - bdrkreg_t gpa_gfx_page_addr : 23; - bdrkreg_t gpa_rsvd_1 : 17; - } pi_gfx_page_a_fld_s; -} pi_gfx_page_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * counts graphics credits. This counter is decremented for each * - * doubleword sent to graphics with GFXWS or GFXWL commands. It is * - * incremented for each doubleword acknowledge from graphics. When * - * this counter has a smaller value than the GFX_BIAS register, * - * SysWrRdy_L is deasserted, an interrupt is sent to the processor, * - * and SysWrRdy_L is allowed to be asserted again. This is the basic * - * mechanism for flow-controlling graphics writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_cntr_a_u { - bdrkreg_t pi_gfx_credit_cntr_a_regval; - struct { - bdrkreg_t gcca_gfx_credit_cntr : 12; - bdrkreg_t gcca_rsvd : 52; - } pi_gfx_credit_cntr_a_fld_s; -} pi_gfx_credit_cntr_a_u_t; - -#else - -typedef union pi_gfx_credit_cntr_a_u { - bdrkreg_t pi_gfx_credit_cntr_a_regval; - struct { - bdrkreg_t gcca_rsvd : 52; - bdrkreg_t gcca_gfx_credit_cntr : 12; - } pi_gfx_credit_cntr_a_fld_s; -} pi_gfx_credit_cntr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the graphics * - * credit counter is less than or equal to this value, a flow control * - * interrupt is sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_bias_a_u { - bdrkreg_t pi_gfx_bias_a_regval; - struct { - bdrkreg_t gba_gfx_bias : 12; - bdrkreg_t gba_rsvd : 52; - } pi_gfx_bias_a_fld_s; -} pi_gfx_bias_a_u_t; - -#else - -typedef union pi_gfx_bias_a_u { - bdrkreg_t pi_gfx_bias_a_regval; - struct { - bdrkreg_t gba_rsvd : 52; - bdrkreg_t gba_gfx_bias : 12; - } pi_gfx_bias_a_fld_s; -} pi_gfx_bias_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. When * - * this counter reaches the value of the GFX_INT_CMP register, an * - * interrupt is sent to the associated processor. At each clock * - * cycle, the value in this register can be changed by any one of the * - * following actions: * - * - Written by software. * - * - Loaded with the value of GFX_INT_CMP, when an interrupt, NMI, or * - * soft reset occurs, thus preventing an additional interrupt. * - * - Zeroed, when the GFX_CREDIT_CNTR rises above the bias value. * - * - Incremented (by one at each clock) for each clock that the * - * GFX_CREDIT_CNTR is less than or equal to zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cntr_a_u { - bdrkreg_t pi_gfx_int_cntr_a_regval; - struct { - bdrkreg_t gica_gfx_int_cntr : 26; - bdrkreg_t gica_rsvd : 38; - } pi_gfx_int_cntr_a_fld_s; -} pi_gfx_int_cntr_a_u_t; - -#else - -typedef union pi_gfx_int_cntr_a_u { - bdrkreg_t pi_gfx_int_cntr_a_regval; - struct { - bdrkreg_t gica_rsvd : 38; - bdrkreg_t gica_gfx_int_cntr : 26; - } pi_gfx_int_cntr_a_fld_s; -} pi_gfx_int_cntr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The value in this * - * register is loaded into the GFX_INT_CNTR register when an * - * interrupt, NMI, or soft reset is sent to the processor. The value * - * in this register is compared to the value of GFX_INT_CNTR and an * - * interrupt is sent when they become equal. * - * * - ************************************************************************/ - - - - -#ifdef LINUX - -typedef union pi_gfx_int_cmp_a_u { - bdrkreg_t pi_gfx_int_cmp_a_regval; - struct { - bdrkreg_t gica_gfx_int_cmp : 26; - bdrkreg_t gica_rsvd : 38; - } pi_gfx_int_cmp_a_fld_s; -} pi_gfx_int_cmp_a_u_t; - -#else - -typedef union pi_gfx_int_cmp_a_u { - bdrkreg_t pi_gfx_int_cmp_a_regval; - struct { - bdrkreg_t gica_rsvd : 38; - bdrkreg_t gica_gfx_int_cmp : 26; - } pi_gfx_int_cmp_a_fld_s; -} pi_gfx_int_cmp_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * specifies the value of the Graphics Page. Uncached writes into the * - * Graphics Page (with uncached attribute of IO) are done with GFXWS * - * commands rather than the normal PWRI commands. GFXWS commands are * - * tracked with the graphics credit counters. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_page_b_u { - bdrkreg_t pi_gfx_page_b_regval; - struct { - bdrkreg_t gpb_rsvd_1 : 17; - bdrkreg_t gpb_gfx_page_addr : 23; - bdrkreg_t gpb_en_gfx_page : 1; - bdrkreg_t gpb_rsvd : 23; - } pi_gfx_page_b_fld_s; -} pi_gfx_page_b_u_t; - -#else - -typedef union pi_gfx_page_b_u { - bdrkreg_t pi_gfx_page_b_regval; - struct { - bdrkreg_t gpb_rsvd : 23; - bdrkreg_t gpb_en_gfx_page : 1; - bdrkreg_t gpb_gfx_page_addr : 23; - bdrkreg_t gpb_rsvd_1 : 17; - } pi_gfx_page_b_fld_s; -} pi_gfx_page_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This register * - * counts graphics credits. This counter is decremented for each * - * doubleword sent to graphics with GFXWS or GFXWL commands. It is * - * incremented for each doubleword acknowledge from graphics. When * - * this counter has a smaller value than the GFX_BIAS register, * - * SysWrRdy_L is deasserted, an interrupt is sent to the processor, * - * and SysWrRdy_L is allowed to be asserted again. This is the basic * - * mechanism for flow-controlling graphics writes. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_cntr_b_u { - bdrkreg_t pi_gfx_credit_cntr_b_regval; - struct { - bdrkreg_t gccb_gfx_credit_cntr : 12; - bdrkreg_t gccb_rsvd : 52; - } pi_gfx_credit_cntr_b_fld_s; -} pi_gfx_credit_cntr_b_u_t; - -#else - -typedef union pi_gfx_credit_cntr_b_u { - bdrkreg_t pi_gfx_credit_cntr_b_regval; - struct { - bdrkreg_t gccb_rsvd : 52; - bdrkreg_t gccb_gfx_credit_cntr : 12; - } pi_gfx_credit_cntr_b_fld_s; -} pi_gfx_credit_cntr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When the graphics * - * credit counter is less than or equal to this value, a flow control * - * interrupt is sent. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_bias_b_u { - bdrkreg_t pi_gfx_bias_b_regval; - struct { - bdrkreg_t gbb_gfx_bias : 12; - bdrkreg_t gbb_rsvd : 52; - } pi_gfx_bias_b_fld_s; -} pi_gfx_bias_b_u_t; - -#else - -typedef union pi_gfx_bias_b_u { - bdrkreg_t pi_gfx_bias_b_regval; - struct { - bdrkreg_t gbb_rsvd : 52; - bdrkreg_t gbb_gfx_bias : 12; - } pi_gfx_bias_b_fld_s; -} pi_gfx_bias_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. When * - * this counter reaches the value of the GFX_INT_CMP register, an * - * interrupt is sent to the associated processor. At each clock * - * cycle, the value in this register can be changed by any one of the * - * following actions: * - * - Written by software. * - * - Loaded with the value of GFX_INT_CMP, when an interrupt, NMI, or * - * soft reset occurs, thus preventing an additional interrupt. * - * - Zeroed, when the GFX_CREDIT_CNTR rises above the bias value. * - * - Incremented (by one at each clock) for each clock that the * - * GFX_CREDIT_CNTR is less than or equal to zero. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cntr_b_u { - bdrkreg_t pi_gfx_int_cntr_b_regval; - struct { - bdrkreg_t gicb_gfx_int_cntr : 26; - bdrkreg_t gicb_rsvd : 38; - } pi_gfx_int_cntr_b_fld_s; -} pi_gfx_int_cntr_b_u_t; - -#else - -typedef union pi_gfx_int_cntr_b_u { - bdrkreg_t pi_gfx_int_cntr_b_regval; - struct { - bdrkreg_t gicb_rsvd : 38; - bdrkreg_t gicb_gfx_int_cntr : 26; - } pi_gfx_int_cntr_b_fld_s; -} pi_gfx_int_cntr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. The value in this * - * register is loaded into the GFX_INT_CNTR register when an * - * interrupt, NMI, or soft reset is sent to the processor. The value * - * in this register is compared to the value of GFX_INT_CNTR and an * - * interrupt is sent when they become equal. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_int_cmp_b_u { - bdrkreg_t pi_gfx_int_cmp_b_regval; - struct { - bdrkreg_t gicb_gfx_int_cmp : 26; - bdrkreg_t gicb_rsvd : 38; - } pi_gfx_int_cmp_b_fld_s; -} pi_gfx_int_cmp_b_u_t; - -#else - -typedef union pi_gfx_int_cmp_b_u { - bdrkreg_t pi_gfx_int_cmp_b_regval; - struct { - bdrkreg_t gicb_rsvd : 38; - bdrkreg_t gicb_gfx_int_cmp : 26; - } pi_gfx_int_cmp_b_fld_s; -} pi_gfx_int_cmp_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: A read of this register returns all sources of * - * Bedrock Error Interrupts. Storing to the write-with-clear location * - * clears any bit for which a one appears on the data bus. Storing to * - * the writable location does a direct write to all unreserved bits * - * (except for MEM_UNC). * - * In Synergy mode, the processor that is the source of the command * - * that got an error is independent of the A or B SysAD bus. So in * - * Synergy mode, Synergy provides the source processor number in bit * - * 52 of the SysAD bus in all commands. The PI saves this in the RRB * - * or WRB entry, and uses that value to determine which error bit (A * - * or B) to set, as well as which ERR_STATUS and spool registers to * - * use, for all error types in this register that are specified as an * - * error to CPU_A or CPU_B. * - * This register is not cleared at reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_pend_wr_u { - bdrkreg_t pi_err_int_pend_wr_regval; - struct { - bdrkreg_t eipw_spool_comp_b : 1; - bdrkreg_t eipw_spool_comp_a : 1; - bdrkreg_t eipw_spurious_b : 1; - bdrkreg_t eipw_spurious_a : 1; - bdrkreg_t eipw_wrb_terr_b : 1; - bdrkreg_t eipw_wrb_terr_a : 1; - bdrkreg_t eipw_wrb_werr_b : 1; - bdrkreg_t eipw_wrb_werr_a : 1; - bdrkreg_t eipw_sysstate_par_b : 1; - bdrkreg_t eipw_sysstate_par_a : 1; - bdrkreg_t eipw_sysad_data_ecc_b : 1; - bdrkreg_t eipw_sysad_data_ecc_a : 1; - bdrkreg_t eipw_sysad_addr_ecc_b : 1; - bdrkreg_t eipw_sysad_addr_ecc_a : 1; - bdrkreg_t eipw_syscmd_data_par_b : 1; - bdrkreg_t eipw_syscmd_data_par_a : 1; - bdrkreg_t eipw_syscmd_addr_par_b : 1; - bdrkreg_t eipw_syscmd_addr_par_a : 1; - bdrkreg_t eipw_spool_err_b : 1; - bdrkreg_t eipw_spool_err_a : 1; - bdrkreg_t eipw_ue_uncached_b : 1; - bdrkreg_t eipw_ue_uncached_a : 1; - bdrkreg_t eipw_sysstate_tag_b : 1; - bdrkreg_t eipw_sysstate_tag_a : 1; - bdrkreg_t eipw_mem_unc : 1; - bdrkreg_t eipw_sysad_bad_data_b : 1; - bdrkreg_t eipw_sysad_bad_data_a : 1; - bdrkreg_t eipw_ue_cached_b : 1; - bdrkreg_t eipw_ue_cached_a : 1; - bdrkreg_t eipw_pkt_len_err_b : 1; - bdrkreg_t eipw_pkt_len_err_a : 1; - bdrkreg_t eipw_irb_err_b : 1; - bdrkreg_t eipw_irb_err_a : 1; - bdrkreg_t eipw_irb_timeout_b : 1; - bdrkreg_t eipw_irb_timeout_a : 1; - bdrkreg_t eipw_rsvd : 29; - } pi_err_int_pend_wr_fld_s; -} pi_err_int_pend_wr_u_t; - -#else - -typedef union pi_err_int_pend_wr_u { - bdrkreg_t pi_err_int_pend_wr_regval; - struct { - bdrkreg_t eipw_rsvd : 29; - bdrkreg_t eipw_irb_timeout_a : 1; - bdrkreg_t eipw_irb_timeout_b : 1; - bdrkreg_t eipw_irb_err_a : 1; - bdrkreg_t eipw_irb_err_b : 1; - bdrkreg_t eipw_pkt_len_err_a : 1; - bdrkreg_t eipw_pkt_len_err_b : 1; - bdrkreg_t eipw_ue_cached_a : 1; - bdrkreg_t eipw_ue_cached_b : 1; - bdrkreg_t eipw_sysad_bad_data_a : 1; - bdrkreg_t eipw_sysad_bad_data_b : 1; - bdrkreg_t eipw_mem_unc : 1; - bdrkreg_t eipw_sysstate_tag_a : 1; - bdrkreg_t eipw_sysstate_tag_b : 1; - bdrkreg_t eipw_ue_uncached_a : 1; - bdrkreg_t eipw_ue_uncached_b : 1; - bdrkreg_t eipw_spool_err_a : 1; - bdrkreg_t eipw_spool_err_b : 1; - bdrkreg_t eipw_syscmd_addr_par_a : 1; - bdrkreg_t eipw_syscmd_addr_par_b : 1; - bdrkreg_t eipw_syscmd_data_par_a : 1; - bdrkreg_t eipw_syscmd_data_par_b : 1; - bdrkreg_t eipw_sysad_addr_ecc_a : 1; - bdrkreg_t eipw_sysad_addr_ecc_b : 1; - bdrkreg_t eipw_sysad_data_ecc_a : 1; - bdrkreg_t eipw_sysad_data_ecc_b : 1; - bdrkreg_t eipw_sysstate_par_a : 1; - bdrkreg_t eipw_sysstate_par_b : 1; - bdrkreg_t eipw_wrb_werr_a : 1; - bdrkreg_t eipw_wrb_werr_b : 1; - bdrkreg_t eipw_wrb_terr_a : 1; - bdrkreg_t eipw_wrb_terr_b : 1; - bdrkreg_t eipw_spurious_a : 1; - bdrkreg_t eipw_spurious_b : 1; - bdrkreg_t eipw_spool_comp_a : 1; - bdrkreg_t eipw_spool_comp_b : 1; - } pi_err_int_pend_wr_fld_s; -} pi_err_int_pend_wr_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: A read of this register returns all sources of * - * Bedrock Error Interrupts. Storing to the write-with-clear location * - * clears any bit for which a one appears on the data bus. Storing to * - * the writable location does a direct write to all unreserved bits * - * (except for MEM_UNC). * - * In Synergy mode, the processor that is the source of the command * - * that got an error is independent of the A or B SysAD bus. So in * - * Synergy mode, Synergy provides the source processor number in bit * - * 52 of the SysAD bus in all commands. The PI saves this in the RRB * - * or WRB entry, and uses that value to determine which error bit (A * - * or B) to set, as well as which ERR_STATUS and spool registers to * - * use, for all error types in this register that are specified as an * - * error to CPU_A or CPU_B. * - * This register is not cleared at reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_pend_u { - bdrkreg_t pi_err_int_pend_regval; - struct { - bdrkreg_t eip_spool_comp_b : 1; - bdrkreg_t eip_spool_comp_a : 1; - bdrkreg_t eip_spurious_b : 1; - bdrkreg_t eip_spurious_a : 1; - bdrkreg_t eip_wrb_terr_b : 1; - bdrkreg_t eip_wrb_terr_a : 1; - bdrkreg_t eip_wrb_werr_b : 1; - bdrkreg_t eip_wrb_werr_a : 1; - bdrkreg_t eip_sysstate_par_b : 1; - bdrkreg_t eip_sysstate_par_a : 1; - bdrkreg_t eip_sysad_data_ecc_b : 1; - bdrkreg_t eip_sysad_data_ecc_a : 1; - bdrkreg_t eip_sysad_addr_ecc_b : 1; - bdrkreg_t eip_sysad_addr_ecc_a : 1; - bdrkreg_t eip_syscmd_data_par_b : 1; - bdrkreg_t eip_syscmd_data_par_a : 1; - bdrkreg_t eip_syscmd_addr_par_b : 1; - bdrkreg_t eip_syscmd_addr_par_a : 1; - bdrkreg_t eip_spool_err_b : 1; - bdrkreg_t eip_spool_err_a : 1; - bdrkreg_t eip_ue_uncached_b : 1; - bdrkreg_t eip_ue_uncached_a : 1; - bdrkreg_t eip_sysstate_tag_b : 1; - bdrkreg_t eip_sysstate_tag_a : 1; - bdrkreg_t eip_mem_unc : 1; - bdrkreg_t eip_sysad_bad_data_b : 1; - bdrkreg_t eip_sysad_bad_data_a : 1; - bdrkreg_t eip_ue_cached_b : 1; - bdrkreg_t eip_ue_cached_a : 1; - bdrkreg_t eip_pkt_len_err_b : 1; - bdrkreg_t eip_pkt_len_err_a : 1; - bdrkreg_t eip_irb_err_b : 1; - bdrkreg_t eip_irb_err_a : 1; - bdrkreg_t eip_irb_timeout_b : 1; - bdrkreg_t eip_irb_timeout_a : 1; - bdrkreg_t eip_rsvd : 29; - } pi_err_int_pend_fld_s; -} pi_err_int_pend_u_t; - -#else - -typedef union pi_err_int_pend_u { - bdrkreg_t pi_err_int_pend_regval; - struct { - bdrkreg_t eip_rsvd : 29; - bdrkreg_t eip_irb_timeout_a : 1; - bdrkreg_t eip_irb_timeout_b : 1; - bdrkreg_t eip_irb_err_a : 1; - bdrkreg_t eip_irb_err_b : 1; - bdrkreg_t eip_pkt_len_err_a : 1; - bdrkreg_t eip_pkt_len_err_b : 1; - bdrkreg_t eip_ue_cached_a : 1; - bdrkreg_t eip_ue_cached_b : 1; - bdrkreg_t eip_sysad_bad_data_a : 1; - bdrkreg_t eip_sysad_bad_data_b : 1; - bdrkreg_t eip_mem_unc : 1; - bdrkreg_t eip_sysstate_tag_a : 1; - bdrkreg_t eip_sysstate_tag_b : 1; - bdrkreg_t eip_ue_uncached_a : 1; - bdrkreg_t eip_ue_uncached_b : 1; - bdrkreg_t eip_spool_err_a : 1; - bdrkreg_t eip_spool_err_b : 1; - bdrkreg_t eip_syscmd_addr_par_a : 1; - bdrkreg_t eip_syscmd_addr_par_b : 1; - bdrkreg_t eip_syscmd_data_par_a : 1; - bdrkreg_t eip_syscmd_data_par_b : 1; - bdrkreg_t eip_sysad_addr_ecc_a : 1; - bdrkreg_t eip_sysad_addr_ecc_b : 1; - bdrkreg_t eip_sysad_data_ecc_a : 1; - bdrkreg_t eip_sysad_data_ecc_b : 1; - bdrkreg_t eip_sysstate_par_a : 1; - bdrkreg_t eip_sysstate_par_b : 1; - bdrkreg_t eip_wrb_werr_a : 1; - bdrkreg_t eip_wrb_werr_b : 1; - bdrkreg_t eip_wrb_terr_a : 1; - bdrkreg_t eip_wrb_terr_b : 1; - bdrkreg_t eip_spurious_a : 1; - bdrkreg_t eip_spurious_b : 1; - bdrkreg_t eip_spool_comp_a : 1; - bdrkreg_t eip_spool_comp_b : 1; - } pi_err_int_pend_fld_s; -} pi_err_int_pend_u_t; - -#endif - - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This read/write * - * register masks the contents of ERR_INT_PEND to determine which * - * conditions cause a Level-6 interrupt to CPU_A or CPU_B. A bit set * - * allows the interrupt. Only one processor in a Bedrock should * - * enable the Memory/Directory Uncorrectable Error bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_mask_a_u { - bdrkreg_t pi_err_int_mask_a_regval; - struct { - bdrkreg_t eima_mask : 35; - bdrkreg_t eima_rsvd : 29; - } pi_err_int_mask_a_fld_s; -} pi_err_int_mask_a_u_t; - -#else - -typedef union pi_err_int_mask_a_u { - bdrkreg_t pi_err_int_mask_a_regval; - struct { - bdrkreg_t eima_rsvd : 29; - bdrkreg_t eima_mask : 35; - } pi_err_int_mask_a_fld_s; -} pi_err_int_mask_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. This read/write * - * register masks the contents of ERR_INT_PEND to determine which * - * conditions cause a Level-6 interrupt to CPU_A or CPU_B. A bit set * - * allows the interrupt. Only one processor in a Bedrock should * - * enable the Memory/Directory Uncorrectable Error bit. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_int_mask_b_u { - bdrkreg_t pi_err_int_mask_b_regval; - struct { - bdrkreg_t eimb_mask : 35; - bdrkreg_t eimb_rsvd : 29; - } pi_err_int_mask_b_fld_s; -} pi_err_int_mask_b_u_t; - -#else - -typedef union pi_err_int_mask_b_u { - bdrkreg_t pi_err_int_mask_b_regval; - struct { - bdrkreg_t eimb_rsvd : 29; - bdrkreg_t eimb_mask : 35; - } pi_err_int_mask_b_fld_s; -} pi_err_int_mask_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * register is the address of the next write to the error stack. This * - * register is incremented after each such write. Only the low N bits * - * are incremented, where N is defined by the size of the error stack * - * specified in the ERR_STACK_SIZE register. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_addr_a_u { - bdrkreg_t pi_err_stack_addr_a_regval; - struct { - bdrkreg_t esaa_rsvd_1 : 3; - bdrkreg_t esaa_addr : 30; - bdrkreg_t esaa_rsvd : 31; - } pi_err_stack_addr_a_fld_s; -} pi_err_stack_addr_a_u_t; - -#else - -typedef union pi_err_stack_addr_a_u { - bdrkreg_t pi_err_stack_addr_a_regval; - struct { - bdrkreg_t esaa_rsvd : 31; - bdrkreg_t esaa_addr : 30; - bdrkreg_t esaa_rsvd_1 : 3; - } pi_err_stack_addr_a_fld_s; -} pi_err_stack_addr_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: There is one of these registers for each CPU. This * - * register is the address of the next write to the error stack. This * - * register is incremented after each such write. Only the low N bits * - * are incremented, where N is defined by the size of the error stack * - * specified in the ERR_STACK_SIZE register. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_addr_b_u { - bdrkreg_t pi_err_stack_addr_b_regval; - struct { - bdrkreg_t esab_rsvd_1 : 3; - bdrkreg_t esab_addr : 30; - bdrkreg_t esab_rsvd : 31; - } pi_err_stack_addr_b_fld_s; -} pi_err_stack_addr_b_u_t; - -#else - -typedef union pi_err_stack_addr_b_u { - bdrkreg_t pi_err_stack_addr_b_regval; - struct { - bdrkreg_t esab_rsvd : 31; - bdrkreg_t esab_addr : 30; - bdrkreg_t esab_rsvd_1 : 3; - } pi_err_stack_addr_b_fld_s; -} pi_err_stack_addr_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: Sets the size (number of 64-bit entries) in the * - * error stack that is spooled to local memory when an error occurs. * - * Table16 defines the format of each entry in the spooled error * - * stack. * - * This register is not reset by a soft reset. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_stack_size_u { - bdrkreg_t pi_err_stack_size_regval; - struct { - bdrkreg_t ess_size : 4; - bdrkreg_t ess_rsvd : 60; - } pi_err_stack_size_fld_s; -} pi_err_stack_size_u_t; - -#else - -typedef union pi_err_stack_size_u { - bdrkreg_t pi_err_stack_size_regval; - struct { - bdrkreg_t ess_rsvd : 60; - bdrkreg_t ess_size : 4; - } pi_err_stack_size_fld_s; -} pi_err_stack_size_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_a_u { - bdrkreg_t pi_err_status0_a_regval; - struct { - bdrkreg_t esa_error_type : 3; - bdrkreg_t esa_proc_req_num : 3; - bdrkreg_t esa_supplemental : 11; - bdrkreg_t esa_cmd : 8; - bdrkreg_t esa_addr : 37; - bdrkreg_t esa_over_run : 1; - bdrkreg_t esa_valid : 1; - } pi_err_status0_a_fld_s; -} pi_err_status0_a_u_t; - -#else - -typedef union pi_err_status0_a_u { - bdrkreg_t pi_err_status0_a_regval; - struct { - bdrkreg_t esa_valid : 1; - bdrkreg_t esa_over_run : 1; - bdrkreg_t esa_addr : 37; - bdrkreg_t esa_cmd : 8; - bdrkreg_t esa_supplemental : 11; - bdrkreg_t esa_proc_req_num : 3; - bdrkreg_t esa_error_type : 3; - } pi_err_status0_a_fld_s; -} pi_err_status0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_a_clr_u { - bdrkreg_t pi_err_status0_a_clr_regval; - struct { - bdrkreg_t esac_error_type : 3; - bdrkreg_t esac_proc_req_num : 3; - bdrkreg_t esac_supplemental : 11; - bdrkreg_t esac_cmd : 8; - bdrkreg_t esac_addr : 37; - bdrkreg_t esac_over_run : 1; - bdrkreg_t esac_valid : 1; - } pi_err_status0_a_clr_fld_s; -} pi_err_status0_a_clr_u_t; - -#else - -typedef union pi_err_status0_a_clr_u { - bdrkreg_t pi_err_status0_a_clr_regval; - struct { - bdrkreg_t esac_valid : 1; - bdrkreg_t esac_over_run : 1; - bdrkreg_t esac_addr : 37; - bdrkreg_t esac_cmd : 8; - bdrkreg_t esac_supplemental : 11; - bdrkreg_t esac_proc_req_num : 3; - bdrkreg_t esac_error_type : 3; - } pi_err_status0_a_clr_fld_s; -} pi_err_status0_a_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_a_u { - bdrkreg_t pi_err_status1_a_regval; - struct { - bdrkreg_t esa_spool_count : 21; - bdrkreg_t esa_time_out_count : 8; - bdrkreg_t esa_inval_count : 10; - bdrkreg_t esa_crb_num : 3; - bdrkreg_t esa_wrb : 1; - bdrkreg_t esa_e_bits : 2; - bdrkreg_t esa_t_bit : 1; - bdrkreg_t esa_i_bit : 1; - bdrkreg_t esa_h_bit : 1; - bdrkreg_t esa_w_bit : 1; - bdrkreg_t esa_a_bit : 1; - bdrkreg_t esa_r_bit : 1; - bdrkreg_t esa_v_bit : 1; - bdrkreg_t esa_p_bit : 1; - bdrkreg_t esa_source : 11; - } pi_err_status1_a_fld_s; -} pi_err_status1_a_u_t; - -#else - -typedef union pi_err_status1_a_u { - bdrkreg_t pi_err_status1_a_regval; - struct { - bdrkreg_t esa_source : 11; - bdrkreg_t esa_p_bit : 1; - bdrkreg_t esa_v_bit : 1; - bdrkreg_t esa_r_bit : 1; - bdrkreg_t esa_a_bit : 1; - bdrkreg_t esa_w_bit : 1; - bdrkreg_t esa_h_bit : 1; - bdrkreg_t esa_i_bit : 1; - bdrkreg_t esa_t_bit : 1; - bdrkreg_t esa_e_bits : 2; - bdrkreg_t esa_wrb : 1; - bdrkreg_t esa_crb_num : 3; - bdrkreg_t esa_inval_count : 10; - bdrkreg_t esa_time_out_count : 8; - bdrkreg_t esa_spool_count : 21; - } pi_err_status1_a_fld_s; -} pi_err_status1_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_A and ERR_STATUS1_A registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_a_clr_u { - bdrkreg_t pi_err_status1_a_clr_regval; - struct { - bdrkreg_t esac_spool_count : 21; - bdrkreg_t esac_time_out_count : 8; - bdrkreg_t esac_inval_count : 10; - bdrkreg_t esac_crb_num : 3; - bdrkreg_t esac_wrb : 1; - bdrkreg_t esac_e_bits : 2; - bdrkreg_t esac_t_bit : 1; - bdrkreg_t esac_i_bit : 1; - bdrkreg_t esac_h_bit : 1; - bdrkreg_t esac_w_bit : 1; - bdrkreg_t esac_a_bit : 1; - bdrkreg_t esac_r_bit : 1; - bdrkreg_t esac_v_bit : 1; - bdrkreg_t esac_p_bit : 1; - bdrkreg_t esac_source : 11; - } pi_err_status1_a_clr_fld_s; -} pi_err_status1_a_clr_u_t; - -#else - -typedef union pi_err_status1_a_clr_u { - bdrkreg_t pi_err_status1_a_clr_regval; - struct { - bdrkreg_t esac_source : 11; - bdrkreg_t esac_p_bit : 1; - bdrkreg_t esac_v_bit : 1; - bdrkreg_t esac_r_bit : 1; - bdrkreg_t esac_a_bit : 1; - bdrkreg_t esac_w_bit : 1; - bdrkreg_t esac_h_bit : 1; - bdrkreg_t esac_i_bit : 1; - bdrkreg_t esac_t_bit : 1; - bdrkreg_t esac_e_bits : 2; - bdrkreg_t esac_wrb : 1; - bdrkreg_t esac_crb_num : 3; - bdrkreg_t esac_inval_count : 10; - bdrkreg_t esac_time_out_count : 8; - bdrkreg_t esac_spool_count : 21; - } pi_err_status1_a_clr_fld_s; -} pi_err_status1_a_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_b_u { - bdrkreg_t pi_err_status0_b_regval; - struct { - bdrkreg_t esb_error_type : 3; - bdrkreg_t esb_proc_request_number : 3; - bdrkreg_t esb_supplemental : 11; - bdrkreg_t esb_cmd : 8; - bdrkreg_t esb_addr : 37; - bdrkreg_t esb_over_run : 1; - bdrkreg_t esb_valid : 1; - } pi_err_status0_b_fld_s; -} pi_err_status0_b_u_t; - -#else - -typedef union pi_err_status0_b_u { - bdrkreg_t pi_err_status0_b_regval; - struct { - bdrkreg_t esb_valid : 1; - bdrkreg_t esb_over_run : 1; - bdrkreg_t esb_addr : 37; - bdrkreg_t esb_cmd : 8; - bdrkreg_t esb_supplemental : 11; - bdrkreg_t esb_proc_request_number : 3; - bdrkreg_t esb_error_type : 3; - } pi_err_status0_b_fld_s; -} pi_err_status0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status0_b_clr_u { - bdrkreg_t pi_err_status0_b_clr_regval; - struct { - bdrkreg_t esbc_error_type : 3; - bdrkreg_t esbc_proc_request_number : 3; - bdrkreg_t esbc_supplemental : 11; - bdrkreg_t esbc_cmd : 8; - bdrkreg_t esbc_addr : 37; - bdrkreg_t esbc_over_run : 1; - bdrkreg_t esbc_valid : 1; - } pi_err_status0_b_clr_fld_s; -} pi_err_status0_b_clr_u_t; - -#else - -typedef union pi_err_status0_b_clr_u { - bdrkreg_t pi_err_status0_b_clr_regval; - struct { - bdrkreg_t esbc_valid : 1; - bdrkreg_t esbc_over_run : 1; - bdrkreg_t esbc_addr : 37; - bdrkreg_t esbc_cmd : 8; - bdrkreg_t esbc_supplemental : 11; - bdrkreg_t esbc_proc_request_number : 3; - bdrkreg_t esbc_error_type : 3; - } pi_err_status0_b_clr_fld_s; -} pi_err_status0_b_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_b_u { - bdrkreg_t pi_err_status1_b_regval; - struct { - bdrkreg_t esb_spool_count : 21; - bdrkreg_t esb_time_out_count : 8; - bdrkreg_t esb_inval_count : 10; - bdrkreg_t esb_crb_num : 3; - bdrkreg_t esb_wrb : 1; - bdrkreg_t esb_e_bits : 2; - bdrkreg_t esb_t_bit : 1; - bdrkreg_t esb_i_bit : 1; - bdrkreg_t esb_h_bit : 1; - bdrkreg_t esb_w_bit : 1; - bdrkreg_t esb_a_bit : 1; - bdrkreg_t esb_r_bit : 1; - bdrkreg_t esb_v_bit : 1; - bdrkreg_t esb_p_bit : 1; - bdrkreg_t esb_source : 11; - } pi_err_status1_b_fld_s; -} pi_err_status1_b_u_t; - -#else - -typedef union pi_err_status1_b_u { - bdrkreg_t pi_err_status1_b_regval; - struct { - bdrkreg_t esb_source : 11; - bdrkreg_t esb_p_bit : 1; - bdrkreg_t esb_v_bit : 1; - bdrkreg_t esb_r_bit : 1; - bdrkreg_t esb_a_bit : 1; - bdrkreg_t esb_w_bit : 1; - bdrkreg_t esb_h_bit : 1; - bdrkreg_t esb_i_bit : 1; - bdrkreg_t esb_t_bit : 1; - bdrkreg_t esb_e_bits : 2; - bdrkreg_t esb_wrb : 1; - bdrkreg_t esb_crb_num : 3; - bdrkreg_t esb_inval_count : 10; - bdrkreg_t esb_time_out_count : 8; - bdrkreg_t esb_spool_count : 21; - } pi_err_status1_b_fld_s; -} pi_err_status1_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. Writing this register with * - * the Write-clear address (with any data) clears both the * - * ERR_STATUS0_B and ERR_STATUS1_B registers. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_status1_b_clr_u { - bdrkreg_t pi_err_status1_b_clr_regval; - struct { - bdrkreg_t esbc_spool_count : 21; - bdrkreg_t esbc_time_out_count : 8; - bdrkreg_t esbc_inval_count : 10; - bdrkreg_t esbc_crb_num : 3; - bdrkreg_t esbc_wrb : 1; - bdrkreg_t esbc_e_bits : 2; - bdrkreg_t esbc_t_bit : 1; - bdrkreg_t esbc_i_bit : 1; - bdrkreg_t esbc_h_bit : 1; - bdrkreg_t esbc_w_bit : 1; - bdrkreg_t esbc_a_bit : 1; - bdrkreg_t esbc_r_bit : 1; - bdrkreg_t esbc_v_bit : 1; - bdrkreg_t esbc_p_bit : 1; - bdrkreg_t esbc_source : 11; - } pi_err_status1_b_clr_fld_s; -} pi_err_status1_b_clr_u_t; - -#else - -typedef union pi_err_status1_b_clr_u { - bdrkreg_t pi_err_status1_b_clr_regval; - struct { - bdrkreg_t esbc_source : 11; - bdrkreg_t esbc_p_bit : 1; - bdrkreg_t esbc_v_bit : 1; - bdrkreg_t esbc_r_bit : 1; - bdrkreg_t esbc_a_bit : 1; - bdrkreg_t esbc_w_bit : 1; - bdrkreg_t esbc_h_bit : 1; - bdrkreg_t esbc_i_bit : 1; - bdrkreg_t esbc_t_bit : 1; - bdrkreg_t esbc_e_bits : 2; - bdrkreg_t esbc_wrb : 1; - bdrkreg_t esbc_crb_num : 3; - bdrkreg_t esbc_inval_count : 10; - bdrkreg_t esbc_time_out_count : 8; - bdrkreg_t esbc_spool_count : 21; - } pi_err_status1_b_clr_fld_s; -} pi_err_status1_b_clr_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_cmp_a_u { - bdrkreg_t pi_spool_cmp_a_regval; - struct { - bdrkreg_t sca_compare : 20; - bdrkreg_t sca_rsvd : 44; - } pi_spool_cmp_a_fld_s; -} pi_spool_cmp_a_u_t; - -#else - -typedef union pi_spool_cmp_a_u { - bdrkreg_t pi_spool_cmp_a_regval; - struct { - bdrkreg_t sca_rsvd : 44; - bdrkreg_t sca_compare : 20; - } pi_spool_cmp_a_fld_s; -} pi_spool_cmp_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_cmp_b_u { - bdrkreg_t pi_spool_cmp_b_regval; - struct { - bdrkreg_t scb_compare : 20; - bdrkreg_t scb_rsvd : 44; - } pi_spool_cmp_b_fld_s; -} pi_spool_cmp_b_u_t; - -#else - -typedef union pi_spool_cmp_b_u { - bdrkreg_t pi_spool_cmp_b_regval; - struct { - bdrkreg_t scb_rsvd : 44; - bdrkreg_t scb_compare : 20; - } pi_spool_cmp_b_fld_s; -} pi_spool_cmp_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A timeout can be * - * forced by writing one(s). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_timeout_a_u { - bdrkreg_t pi_crb_timeout_a_regval; - struct { - bdrkreg_t cta_rrb : 4; - bdrkreg_t cta_wrb : 8; - bdrkreg_t cta_rsvd : 52; - } pi_crb_timeout_a_fld_s; -} pi_crb_timeout_a_u_t; - -#else - -typedef union pi_crb_timeout_a_u { - bdrkreg_t pi_crb_timeout_a_regval; - struct { - bdrkreg_t cta_rsvd : 52; - bdrkreg_t cta_wrb : 8; - bdrkreg_t cta_rrb : 4; - } pi_crb_timeout_a_fld_s; -} pi_crb_timeout_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. A timeout can be * - * forced by writing one(s). * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_crb_timeout_b_u { - bdrkreg_t pi_crb_timeout_b_regval; - struct { - bdrkreg_t ctb_rrb : 4; - bdrkreg_t ctb_wrb : 8; - bdrkreg_t ctb_rsvd : 52; - } pi_crb_timeout_b_fld_s; -} pi_crb_timeout_b_u_t; - -#else - -typedef union pi_crb_timeout_b_u { - bdrkreg_t pi_crb_timeout_b_regval; - struct { - bdrkreg_t ctb_rsvd : 52; - bdrkreg_t ctb_wrb : 8; - bdrkreg_t ctb_rrb : 4; - } pi_crb_timeout_b_fld_s; -} pi_crb_timeout_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls error checking and forwarding of SysAD * - * errors. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_sysad_errchk_en_u { - bdrkreg_t pi_sysad_errchk_en_regval; - struct { - bdrkreg_t see_ecc_gen_en : 1; - bdrkreg_t see_qual_gen_en : 1; - bdrkreg_t see_sadp_chk_en : 1; - bdrkreg_t see_cmdp_chk_en : 1; - bdrkreg_t see_state_chk_en : 1; - bdrkreg_t see_qual_chk_en : 1; - bdrkreg_t see_rsvd : 58; - } pi_sysad_errchk_en_fld_s; -} pi_sysad_errchk_en_u_t; - -#else - -typedef union pi_sysad_errchk_en_u { - bdrkreg_t pi_sysad_errchk_en_regval; - struct { - bdrkreg_t see_rsvd : 58; - bdrkreg_t see_qual_chk_en : 1; - bdrkreg_t see_state_chk_en : 1; - bdrkreg_t see_cmdp_chk_en : 1; - bdrkreg_t see_sadp_chk_en : 1; - bdrkreg_t see_qual_gen_en : 1; - bdrkreg_t see_ecc_gen_en : 1; - } pi_sysad_errchk_en_fld_s; -} pi_sysad_errchk_en_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If any bit in this * - * register is set, then whenever reply data arrives with the UE * - * (uncorrectable error) indication set, the check-bits that are * - * generated and sent to the SysAD will be inverted corresponding to * - * the bits set in the register. This will also prevent the assertion * - * of the data quality indicator. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_force_bad_check_bit_a_u { - bdrkreg_t pi_force_bad_check_bit_a_regval; - struct { - bdrkreg_t fbcba_bad_check_bit : 8; - bdrkreg_t fbcba_rsvd : 56; - } pi_force_bad_check_bit_a_fld_s; -} pi_force_bad_check_bit_a_u_t; - -#else - -typedef union pi_force_bad_check_bit_a_u { - bdrkreg_t pi_force_bad_check_bit_a_regval; - struct { - bdrkreg_t fbcba_rsvd : 56; - bdrkreg_t fbcba_bad_check_bit : 8; - } pi_force_bad_check_bit_a_fld_s; -} pi_force_bad_check_bit_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. If any bit in this * - * register is set, then whenever reply data arrives with the UE * - * (uncorrectable error) indication set, the check-bits that are * - * generated and sent to the SysAD will be inverted corresponding to * - * the bits set in the register. This will also prevent the assertion * - * of the data quality indicator. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_force_bad_check_bit_b_u { - bdrkreg_t pi_force_bad_check_bit_b_regval; - struct { - bdrkreg_t fbcbb_bad_check_bit : 8; - bdrkreg_t fbcbb_rsvd : 56; - } pi_force_bad_check_bit_b_fld_s; -} pi_force_bad_check_bit_b_u_t; - -#else - -typedef union pi_force_bad_check_bit_b_u { - bdrkreg_t pi_force_bad_check_bit_b_regval; - struct { - bdrkreg_t fbcbb_rsvd : 56; - bdrkreg_t fbcbb_bad_check_bit : 8; - } pi_force_bad_check_bit_b_fld_s; -} pi_force_bad_check_bit_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When a counter is * - * enabled, it increments each time a DNACK reply is received. The * - * counter is cleared when any other reply is received. The register * - * is cleared when the CNT_EN bit is zero. If a DNACK reply is * - * received when the counter equals the value in the NACK_CMP * - * register, the counter is cleared, an error response is sent to the * - * CPU instead of a nack response, and the NACK_INT_A/B bit is set in * - * INT_PEND1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cnt_a_u { - bdrkreg_t pi_nack_cnt_a_regval; - struct { - bdrkreg_t nca_nack_cnt : 20; - bdrkreg_t nca_cnt_en : 1; - bdrkreg_t nca_rsvd : 43; - } pi_nack_cnt_a_fld_s; -} pi_nack_cnt_a_u_t; - -#else - -typedef union pi_nack_cnt_a_u { - bdrkreg_t pi_nack_cnt_a_regval; - struct { - bdrkreg_t nca_rsvd : 43; - bdrkreg_t nca_cnt_en : 1; - bdrkreg_t nca_nack_cnt : 20; - } pi_nack_cnt_a_fld_s; -} pi_nack_cnt_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * There is one of these registers for each CPU. When a counter is * - * enabled, it increments each time a DNACK reply is received. The * - * counter is cleared when any other reply is received. The register * - * is cleared when the CNT_EN bit is zero. If a DNACK reply is * - * received when the counter equals the value in the NACK_CMP * - * register, the counter is cleared, an error response is sent to the * - * CPU instead of a nack response, and the NACK_INT_A/B bit is set in * - * INT_PEND1. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cnt_b_u { - bdrkreg_t pi_nack_cnt_b_regval; - struct { - bdrkreg_t ncb_nack_cnt : 20; - bdrkreg_t ncb_cnt_en : 1; - bdrkreg_t ncb_rsvd : 43; - } pi_nack_cnt_b_fld_s; -} pi_nack_cnt_b_u_t; - -#else - -typedef union pi_nack_cnt_b_u { - bdrkreg_t pi_nack_cnt_b_regval; - struct { - bdrkreg_t ncb_rsvd : 43; - bdrkreg_t ncb_cnt_en : 1; - bdrkreg_t ncb_nack_cnt : 20; - } pi_nack_cnt_b_fld_s; -} pi_nack_cnt_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * The setting of this register affects both CPUs on this PI. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_nack_cmp_u { - bdrkreg_t pi_nack_cmp_regval; - struct { - bdrkreg_t nc_nack_cmp : 20; - bdrkreg_t nc_rsvd : 44; - } pi_nack_cmp_fld_s; -} pi_nack_cmp_u_t; - -#else - -typedef union pi_nack_cmp_u { - bdrkreg_t pi_nack_cmp_regval; - struct { - bdrkreg_t nc_rsvd : 44; - bdrkreg_t nc_nack_cmp : 20; - } pi_nack_cmp_fld_s; -} pi_nack_cmp_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls which errors are spooled. When a bit in * - * this register is set, the corresponding error is spooled. The * - * setting of this register affects both CPUs on this PI. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spool_mask_u { - bdrkreg_t pi_spool_mask_regval; - struct { - bdrkreg_t sm_access_err : 1; - bdrkreg_t sm_uncached_err : 1; - bdrkreg_t sm_dir_err : 1; - bdrkreg_t sm_timeout_err : 1; - bdrkreg_t sm_poison_err : 1; - bdrkreg_t sm_nack_oflow_err : 1; - bdrkreg_t sm_rsvd : 58; - } pi_spool_mask_fld_s; -} pi_spool_mask_u_t; - -#else - -typedef union pi_spool_mask_u { - bdrkreg_t pi_spool_mask_regval; - struct { - bdrkreg_t sm_rsvd : 58; - bdrkreg_t sm_nack_oflow_err : 1; - bdrkreg_t sm_poison_err : 1; - bdrkreg_t sm_timeout_err : 1; - bdrkreg_t sm_dir_err : 1; - bdrkreg_t sm_uncached_err : 1; - bdrkreg_t sm_access_err : 1; - } pi_spool_mask_fld_s; -} pi_spool_mask_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. When the VALID bit is * - * zero, this register (along with SPURIOUS_HDR_1) will capture the * - * header of an incoming spurious message received from the XBar. A * - * spurious message is a message that does not match up with any of * - * the CRB entries. This is a read/write register, so it is cleared * - * by writing of all zeros. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spurious_hdr_0_u { - bdrkreg_t pi_spurious_hdr_0_regval; - struct { - bdrkreg_t sh0_prev_valid_b : 1; - bdrkreg_t sh0_prev_valid_a : 1; - bdrkreg_t sh0_rsvd : 4; - bdrkreg_t sh0_supplemental : 11; - bdrkreg_t sh0_cmd : 8; - bdrkreg_t sh0_addr : 37; - bdrkreg_t sh0_tail : 1; - bdrkreg_t sh0_valid : 1; - } pi_spurious_hdr_0_fld_s; -} pi_spurious_hdr_0_u_t; - -#else - -typedef union pi_spurious_hdr_0_u { - bdrkreg_t pi_spurious_hdr_0_regval; - struct { - bdrkreg_t sh0_valid : 1; - bdrkreg_t sh0_tail : 1; - bdrkreg_t sh0_addr : 37; - bdrkreg_t sh0_cmd : 8; - bdrkreg_t sh0_supplemental : 11; - bdrkreg_t sh0_rsvd : 4; - bdrkreg_t sh0_prev_valid_a : 1; - bdrkreg_t sh0_prev_valid_b : 1; - } pi_spurious_hdr_0_fld_s; -} pi_spurious_hdr_0_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is not cleared at reset. When the VALID bit in * - * SPURIOUS_HDR_0 is zero, this register (along with SPURIOUS_HDR_0) * - * will capture the header of an incoming spurious message received * - * from the XBar. A spurious message is a message that does not match * - * up with any of the CRB entries. This is a read/write register, so * - * it is cleared by writing of all zeros. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_spurious_hdr_1_u { - bdrkreg_t pi_spurious_hdr_1_regval; - struct { - bdrkreg_t sh1_rsvd : 53; - bdrkreg_t sh1_source : 11; - } pi_spurious_hdr_1_fld_s; -} pi_spurious_hdr_1_u_t; - -#else - -typedef union pi_spurious_hdr_1_u { - bdrkreg_t pi_spurious_hdr_1_regval; - struct { - bdrkreg_t sh1_source : 11; - bdrkreg_t sh1_rsvd : 53; - } pi_spurious_hdr_1_fld_s; -} pi_spurious_hdr_1_u_t; - -#endif - - - - -/************************************************************************ - * * - * Description: This register controls the injection of errors in * - * outbound SysAD transfers. When a write sets a bit in this * - * register, the PI logic is "armed" to inject that error. At the * - * first transfer of the specified type, the error is injected and * - * the bit in this register is cleared. Writing to this register does * - * not cause a transaction to occur. A bit in this register will * - * remain set until a transaction of the specified type occurs as a * - * result of normal system activity. This register can be polled to * - * determine if an error has been injected or is still "armed". * - * This register does not control injection of data quality bad * - * indicator on a data cycle. This type of error can be created by * - * reading from a memory location that has an uncorrectable ECC * - * error. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_err_inject_u { - bdrkreg_t pi_err_inject_regval; - struct { - bdrkreg_t ei_cmd_syscmd_par_a : 1; - bdrkreg_t ei_data_syscmd_par_a : 1; - bdrkreg_t ei_cmd_sysad_corecc_a : 1; - bdrkreg_t ei_data_sysad_corecc_a : 1; - bdrkreg_t ei_cmd_sysad_uncecc_a : 1; - bdrkreg_t ei_data_sysad_uncecc_a : 1; - bdrkreg_t ei_sysresp_par_a : 1; - bdrkreg_t ei_reserved_1 : 25; - bdrkreg_t ei_cmd_syscmd_par_b : 1; - bdrkreg_t ei_data_syscmd_par_b : 1; - bdrkreg_t ei_cmd_sysad_corecc_b : 1; - bdrkreg_t ei_data_sysad_corecc_b : 1; - bdrkreg_t ei_cmd_sysad_uncecc_b : 1; - bdrkreg_t ei_data_sysad_uncecc_b : 1; - bdrkreg_t ei_sysresp_par_b : 1; - bdrkreg_t ei_reserved : 25; - } pi_err_inject_fld_s; -} pi_err_inject_u_t; - -#else - -typedef union pi_err_inject_u { - bdrkreg_t pi_err_inject_regval; - struct { - bdrkreg_t ei_reserved : 25; - bdrkreg_t ei_sysresp_par_b : 1; - bdrkreg_t ei_data_sysad_uncecc_b : 1; - bdrkreg_t ei_cmd_sysad_uncecc_b : 1; - bdrkreg_t ei_data_sysad_corecc_b : 1; - bdrkreg_t ei_cmd_sysad_corecc_b : 1; - bdrkreg_t ei_data_syscmd_par_b : 1; - bdrkreg_t ei_cmd_syscmd_par_b : 1; - bdrkreg_t ei_reserved_1 : 25; - bdrkreg_t ei_sysresp_par_a : 1; - bdrkreg_t ei_data_sysad_uncecc_a : 1; - bdrkreg_t ei_cmd_sysad_uncecc_a : 1; - bdrkreg_t ei_data_sysad_corecc_a : 1; - bdrkreg_t ei_cmd_sysad_corecc_a : 1; - bdrkreg_t ei_data_syscmd_par_a : 1; - bdrkreg_t ei_cmd_syscmd_par_a : 1; - } pi_err_inject_fld_s; -} pi_err_inject_u_t; - -#endif - - - - -/************************************************************************ - * * - * This Read/Write location determines at what point the TRex+ is * - * stopped from issuing requests, based on the number of entries in * - * the incoming reply FIFO. When the number of entries in the Reply * - * FIFO is greater than the value of this register, the PI will * - * deassert both SysWrRdy and SysRdRdy to both processors. The Reply * - * FIFO has a depth of 0x3F entries, so setting this register to 0x3F * - * effectively disables this feature, allowing requests to be issued * - * always. Setting this register to 0x00 effectively lowers the * - * TRex+'s priority below the reply FIFO, disabling TRex+ requests * - * any time there is an entry waiting in the incoming FIFO.This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_reply_level_u { - bdrkreg_t pi_reply_level_regval; - struct { - bdrkreg_t rl_reply_level : 6; - bdrkreg_t rl_rsvd : 58; - } pi_reply_level_fld_s; -} pi_reply_level_u_t; - -#else - -typedef union pi_reply_level_u { - bdrkreg_t pi_reply_level_regval; - struct { - bdrkreg_t rl_rsvd : 58; - bdrkreg_t rl_reply_level : 6; - } pi_reply_level_fld_s; -} pi_reply_level_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register is used to change the graphics credit counter * - * operation from "Doubleword" mode to "Transaction" mode. This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_gfx_credit_mode_u { - bdrkreg_t pi_gfx_credit_mode_regval; - struct { - bdrkreg_t gcm_trans_mode : 1; - bdrkreg_t gcm_rsvd : 63; - } pi_gfx_credit_mode_fld_s; -} pi_gfx_credit_mode_u_t; - -#else - -typedef union pi_gfx_credit_mode_u { - bdrkreg_t pi_gfx_credit_mode_regval; - struct { - bdrkreg_t gcm_rsvd : 63; - bdrkreg_t gcm_trans_mode : 1; - } pi_gfx_credit_mode_fld_s; -} pi_gfx_credit_mode_u_t; - -#endif - - - -/************************************************************************ - * * - * This location contains a 55-bit read/write counter that wraps to * - * zero when the maximum value is reached. This counter is * - * incremented at each rising edge of the global clock (GCLK). This * - * register is in its own 64KB page so that it can be mapped to user * - * space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_rt_counter_u { - bdrkreg_t pi_rt_counter_regval; - struct { - bdrkreg_t rc_count : 55; - bdrkreg_t rc_rsvd : 9; - } pi_rt_counter_fld_s; -} pi_rt_counter_u_t; - -#else - -typedef union pi_rt_counter_u { - bdrkreg_t pi_rt_counter_regval; - struct { - bdrkreg_t rc_rsvd : 9; - bdrkreg_t rc_count : 55; - } pi_rt_counter_fld_s; -} pi_rt_counter_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register controls the performance counters for one CPU. * - * There are two counters for each CPU. Each counter can be * - * configured to count a variety of events. The performance counter * - * registers for each processor are in their own 64KB page so that * - * they can be mapped to user space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntl_a_u { - bdrkreg_t pi_perf_cntl_a_regval; - struct { - bdrkreg_t pca_cntr_0_select : 28; - bdrkreg_t pca_cntr_0_mode : 3; - bdrkreg_t pca_cntr_0_enable : 1; - bdrkreg_t pca_cntr_1_select : 28; - bdrkreg_t pca_cntr_1_mode : 3; - bdrkreg_t pca_cntr_1_enable : 1; - } pi_perf_cntl_a_fld_s; -} pi_perf_cntl_a_u_t; - -#else - -typedef union pi_perf_cntl_a_u { - bdrkreg_t pi_perf_cntl_a_regval; - struct { - bdrkreg_t pca_cntr_1_enable : 1; - bdrkreg_t pca_cntr_1_mode : 3; - bdrkreg_t pca_cntr_1_select : 28; - bdrkreg_t pca_cntr_0_enable : 1; - bdrkreg_t pca_cntr_0_mode : 3; - bdrkreg_t pca_cntr_0_select : 28; - } pi_perf_cntl_a_fld_s; -} pi_perf_cntl_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 0 for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr0_a_u { - bdrkreg_t pi_perf_cntr0_a_regval; - struct { - bdrkreg_t pca_count_value : 40; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_rsvd : 23; - } pi_perf_cntr0_a_fld_s; -} pi_perf_cntr0_a_u_t; - -#else - -typedef union pi_perf_cntr0_a_u { - bdrkreg_t pi_perf_cntr0_a_regval; - struct { - bdrkreg_t pca_rsvd : 23; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_count_value : 40; - } pi_perf_cntr0_a_fld_s; -} pi_perf_cntr0_a_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 1for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr1_a_u { - bdrkreg_t pi_perf_cntr1_a_regval; - struct { - bdrkreg_t pca_count_value : 40; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_rsvd : 23; - } pi_perf_cntr1_a_fld_s; -} pi_perf_cntr1_a_u_t; - -#else - -typedef union pi_perf_cntr1_a_u { - bdrkreg_t pi_perf_cntr1_a_regval; - struct { - bdrkreg_t pca_rsvd : 23; - bdrkreg_t pca_overflow : 1; - bdrkreg_t pca_count_value : 40; - } pi_perf_cntr1_a_fld_s; -} pi_perf_cntr1_a_u_t; - -#endif - - - - - -/************************************************************************ - * * - * This register controls the performance counters for one CPU. * - * There are two counters for each CPU. Each counter can be * - * configured to count a variety of events. The performance counter * - * registers for each processor are in their own 64KB page so that * - * they can be mapped to user space. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntl_b_u { - bdrkreg_t pi_perf_cntl_b_regval; - struct { - bdrkreg_t pcb_cntr_0_select : 28; - bdrkreg_t pcb_cntr_0_mode : 3; - bdrkreg_t pcb_cntr_0_enable : 1; - bdrkreg_t pcb_cntr_1_select : 28; - bdrkreg_t pcb_cntr_1_mode : 3; - bdrkreg_t pcb_cntr_1_enable : 1; - } pi_perf_cntl_b_fld_s; -} pi_perf_cntl_b_u_t; - -#else - -typedef union pi_perf_cntl_b_u { - bdrkreg_t pi_perf_cntl_b_regval; - struct { - bdrkreg_t pcb_cntr_1_enable : 1; - bdrkreg_t pcb_cntr_1_mode : 3; - bdrkreg_t pcb_cntr_1_select : 28; - bdrkreg_t pcb_cntr_0_enable : 1; - bdrkreg_t pcb_cntr_0_mode : 3; - bdrkreg_t pcb_cntr_0_select : 28; - } pi_perf_cntl_b_fld_s; -} pi_perf_cntl_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 0 for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr0_b_u { - bdrkreg_t pi_perf_cntr0_b_regval; - struct { - bdrkreg_t pcb_count_value : 40; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_rsvd : 23; - } pi_perf_cntr0_b_fld_s; -} pi_perf_cntr0_b_u_t; - -#else - -typedef union pi_perf_cntr0_b_u { - bdrkreg_t pi_perf_cntr0_b_regval; - struct { - bdrkreg_t pcb_rsvd : 23; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_count_value : 40; - } pi_perf_cntr0_b_fld_s; -} pi_perf_cntr0_b_u_t; - -#endif - - - - -/************************************************************************ - * * - * This register accesses the performance counter 1for each CPU. * - * Each performance counter is 40-bits wide. On overflow, It wraps to * - * zero, sets the overflow bit in this register, and sets the * - * PERF_CNTR_OFLOW bit in the INT_PEND1 register. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union pi_perf_cntr1_b_u { - bdrkreg_t pi_perf_cntr1_b_regval; - struct { - bdrkreg_t pcb_count_value : 40; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_rsvd : 23; - } pi_perf_cntr1_b_fld_s; -} pi_perf_cntr1_b_u_t; - -#else - -typedef union pi_perf_cntr1_b_u { - bdrkreg_t pi_perf_cntr1_b_regval; - struct { - bdrkreg_t pcb_rsvd : 23; - bdrkreg_t pcb_overflow : 1; - bdrkreg_t pcb_count_value : 40; - } pi_perf_cntr1_b_fld_s; -} pi_perf_cntr1_b_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - -#define PI_GFX_OFFSET (PI_GFX_PAGE_B - PI_GFX_PAGE_A) -#define PI_GFX_PAGE_ENABLE 0x0000010000000000LL - - -#endif /* _ASM_IA64_SN_SN1_HUBPI_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubpi_next.h b/include/asm-ia64/sn/sn1/hubpi_next.h --- a/include/asm-ia64/sn/sn1/hubpi_next.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,331 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBPI_NEXT_H -#define _ASM_IA64_SN_SN1_HUBPI_NEXT_H - - -/* define for remote PI_1 space. It is always half of a node_addressspace - * from PI_0. The normal REMOTE_HUB space for PI registers access - * the PI_0 space, unless they are qualified by PI_1. - */ -#define PI_0(x) (x) -#define PI_1(x) ((x) + 0x200000) -#define PIREG(x,sn) ((sn) ? PI_1(x) : PI_0(x)) - -#define PI_MIN_STACK_SIZE 4096 /* For figuring out the size to set */ -#define PI_STACK_SIZE_SHFT 12 /* 4k */ - -#define PI_STACKADDR_OFFSET (PI_ERR_STACK_ADDR_B - PI_ERR_STACK_ADDR_A) -#define PI_ERRSTAT_OFFSET (PI_ERR_STATUS0_B - PI_ERR_STATUS0_A) -#define PI_RDCLR_OFFSET (PI_ERR_STATUS0_A_RCLR - PI_ERR_STATUS0_A) -/* these macros are correct, but fix their users to understand two PIs - and 4 CPUs (slices) per bedrock */ -#define PI_INT_MASK_OFFSET (PI_INT_MASK0_B - PI_INT_MASK0_A) -#define PI_INT_SET_OFFSET (PI_CC_PEND_CLR_B - PI_CC_PEND_CLR_A) -#define PI_NMI_OFFSET (PI_NMI_B - PI_NMI_A) - -#define ERR_STACK_SIZE_BYTES(_sz) \ - ((_sz) ? (PI_MIN_STACK_SIZE << ((_sz) - 1)) : 0) - -#define PI_CRB_STS_P (1 << 9) /* "P" (partial word read/write) bit */ -#define PI_CRB_STS_V (1 << 8) /* "V" (valid) bit */ -#define PI_CRB_STS_R (1 << 7) /* "R" (response data sent to CPU) */ -#define PI_CRB_STS_A (1 << 6) /* "A" (data ack. received) bit */ -#define PI_CRB_STS_W (1 << 5) /* "W" (waiting for write compl.) */ -#define PI_CRB_STS_H (1 << 4) /* "H" (gathering invalidates) bit */ -#define PI_CRB_STS_I (1 << 3) /* "I" (targ. inbound invalidate) */ -#define PI_CRB_STS_T (1 << 2) /* "T" (targ. inbound intervention) */ -#define PI_CRB_STS_E (0x3) /* "E" (coherent read type) */ - -/* When the "P" bit is set in the sk_crb_sts field of an error stack - * entry, the "R," "A," "H," and "I" bits are actually bits 6..3 of - * the address. This macro extracts those address bits and shifts - * them to their proper positions, ready to be ORed in to the rest of - * the address (which is calculated as sk_addr << 7). - */ -#define PI_CRB_STS_ADDR_BITS(sts) \ - ((sts) & (PI_CRB_STS_I | PI_CRB_STS_H) | \ - ((sts) & (PI_CRB_STS_A | PI_CRB_STS_R)) >> 1) - -#ifndef __ASSEMBLY__ -/* - * format of error stack and error status registers. - */ - -#ifdef LITTLE_ENDIAN - -struct err_stack_format { - uint64_t sk_err_type: 3, /* error type */ - sk_suppl : 3, /* lowest 3 bit of supplemental */ - sk_t5_req : 3, /* RRB T5 request number */ - sk_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - sk_rw_rb : 1, /* RRB == 0, WRB == 1 */ - sk_crb_sts : 10, /* status from RRB or WRB */ - sk_cmd : 8, /* message command */ - sk_addr : 33; /* address */ -}; - -#else - -struct err_stack_format { - uint64_t sk_addr : 33, /* address */ - sk_cmd : 8, /* message command */ - sk_crb_sts : 10, /* status from RRB or WRB */ - sk_rw_rb : 1, /* RRB == 0, WRB == 1 */ - sk_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - sk_t5_req : 3, /* RRB T5 request number */ - sk_suppl : 3, /* lowest 3 bit of supplemental */ - sk_err_type: 3; /* error type */ -}; - -#endif - -typedef union pi_err_stack { - uint64_t pi_stk_word; - struct err_stack_format pi_stk_fmt; -} pi_err_stack_t; - -/* Simplified version of pi_err_status0_a_u_t (PI_ERR_STATUS0_A) */ -#ifdef LITTLE_ENDIAN - -struct err_status0_format { - uint64_t s0_err_type : 3, /* Encoded error cause */ - s0_proc_req_num : 3, /* Request number for RRB only */ - s0_supplemental : 11, /* ncoming message sup field */ - s0_cmd : 8, /* Incoming message command */ - s0_addr : 37, /* Address */ - s0_over_run : 1, /* Subsequent errors spooled */ - s0_valid : 1; /* error is valid */ -}; - -#else - -struct err_status0_format { - uint64_t s0_valid : 1, /* error is valid */ - s0_over_run : 1, /* Subsequent errors spooled */ - s0_addr : 37, /* Address */ - s0_cmd : 8, /* Incoming message command */ - s0_supplemental : 11, /* ncoming message sup field */ - s0_proc_req_num : 3, /* Request number for RRB only */ - s0_err_type : 3; /* Encoded error cause */ -}; - -#endif - - -typedef union pi_err_stat0 { - uint64_t pi_stat0_word; - struct err_status0_format pi_stat0_fmt; -} pi_err_stat0_t; - -/* Simplified version of pi_err_status1_a_u_t (PI_ERR_STATUS1_A) */ - -#ifdef LITTLE_ENDIAN - -struct err_status1_format { - uint64_t s1_spl_cnt : 21, /* number spooled to memory */ - s1_to_cnt : 8, /* crb timeout counter */ - s1_inval_cnt:10, /* signed invalidate counter RRB */ - s1_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - s1_rw_rb : 1, /* RRB == 0, WRB == 1 */ - s1_crb_sts : 10, /* status from RRB or WRB */ - s1_src : 11; /* message source */ -}; - -#else - -struct err_status1_format { - uint64_t s1_src : 11, /* message source */ - s1_crb_sts : 10, /* status from RRB or WRB */ - s1_rw_rb : 1, /* RRB == 0, WRB == 1 */ - s1_crb_num : 3, /* WRB (0 to 7) or RRB (0 to 4) */ - s1_inval_cnt:10, /* signed invalidate counter RRB */ - s1_to_cnt : 8, /* crb timeout counter */ - s1_spl_cnt : 21; /* number spooled to memory */ -}; - -#endif - -typedef union pi_err_stat1 { - uint64_t pi_stat1_word; - struct err_status1_format pi_stat1_fmt; -} pi_err_stat1_t; -#endif - -/* Error stack types (sk_err_type) for reads: */ -#define PI_ERR_RD_AERR 0 /* Read Access Error */ -#define PI_ERR_RD_PRERR 1 /* Uncached Partitial Read */ -#define PI_ERR_RD_DERR 2 /* Directory Error */ -#define PI_ERR_RD_TERR 3 /* read timeout */ -#define PI_ERR_RD_PERR 4 /* Poison Access Violation */ -#define PI_ERR_RD_NACK 5 /* Excessive NACKs */ -#define PI_ERR_RD_RDE 6 /* Response Data Error */ -#define PI_ERR_RD_PLERR 7 /* Packet Length Error */ -/* Error stack types (sk_err_type) for writes: */ -#define PI_ERR_WR_WERR 0 /* Write Access Error */ -#define PI_ERR_WR_PWERR 1 /* Uncached Write Error */ -#define PI_ERR_WR_TERR 3 /* write timeout */ -#define PI_ERR_WR_RDE 6 /* Response Data Error */ -#define PI_ERR_WR_PLERR 7 /* Packet Length Error */ - - -/* For backwards compatibility */ -#define PI_RT_COUNT PI_RT_COUNTER /* Real Time Counter */ -#define PI_RT_EN_A PI_RT_INT_EN_A /* RT int for CPU A enable */ -#define PI_RT_EN_B PI_RT_INT_EN_B /* RT int for CPU B enable */ -#define PI_PROF_EN_A PI_PROF_INT_EN_A /* PROF int for CPU A enable */ -#define PI_PROF_EN_B PI_PROF_INT_EN_B /* PROF int for CPU B enable */ -#define PI_RT_PEND_A PI_RT_INT_PEND_A /* RT interrupt pending */ -#define PI_RT_PEND_B PI_RT_INT_PEND_B /* RT interrupt pending */ -#define PI_PROF_PEND_A PI_PROF_INT_PEND_A /* Profiling interrupt pending */ -#define PI_PROF_PEND_B PI_PROF_INT_PEND_B /* Profiling interrupt pending */ - - -/* Bits in PI_SYSAD_ERRCHK_EN */ -#define PI_SYSAD_ERRCHK_ECCGEN 0x01 /* Enable ECC generation */ -#define PI_SYSAD_ERRCHK_QUALGEN 0x02 /* Enable data quality signal gen. */ -#define PI_SYSAD_ERRCHK_SADP 0x04 /* Enable SysAD parity checking */ -#define PI_SYSAD_ERRCHK_CMDP 0x08 /* Enable SysCmd parity checking */ -#define PI_SYSAD_ERRCHK_STATE 0x10 /* Enable SysState parity checking */ -#define PI_SYSAD_ERRCHK_QUAL 0x20 /* Enable data quality checking */ -#define PI_SYSAD_CHECK_ALL 0x3f /* Generate and check all signals. */ - -/* CALIAS values */ -#define PI_CALIAS_SIZE_0 0 -#define PI_CALIAS_SIZE_4K 1 -#define PI_CALIAS_SIZE_8K 2 -#define PI_CALIAS_SIZE_16K 3 -#define PI_CALIAS_SIZE_32K 4 -#define PI_CALIAS_SIZE_64K 5 -#define PI_CALIAS_SIZE_128K 6 -#define PI_CALIAS_SIZE_256K 7 -#define PI_CALIAS_SIZE_512K 8 -#define PI_CALIAS_SIZE_1M 9 -#define PI_CALIAS_SIZE_2M 10 -#define PI_CALIAS_SIZE_4M 11 -#define PI_CALIAS_SIZE_8M 12 -#define PI_CALIAS_SIZE_16M 13 -#define PI_CALIAS_SIZE_32M 14 -#define PI_CALIAS_SIZE_64M 15 - -/* Fields in PI_ERR_STATUS0_[AB] */ -#define PI_ERR_ST0_VALID_MASK 0x8000000000000000 -#define PI_ERR_ST0_VALID_SHFT 63 - -/* Fields in PI_SPURIOUS_HDR_0 */ -#define PI_SPURIOUS_HDR_VALID_MASK 0x8000000000000000 -#define PI_SPURIOUS_HDR_VALID_SHFT 63 - -/* Fields in PI_NACK_CNT_A/B */ -#define PI_NACK_CNT_EN_SHFT 20 -#define PI_NACK_CNT_EN_MASK 0x100000 -#define PI_NACK_CNT_MASK 0x0fffff -#define PI_NACK_CNT_MAX 0x0fffff - -/* Bits in PI_ERR_INT_PEND */ -#define PI_ERR_SPOOL_CMP_B 0x000000001 /* Spool end hit high water */ -#define PI_ERR_SPOOL_CMP_A 0x000000002 -#define PI_ERR_SPUR_MSG_B 0x000000004 /* Spurious message intr. */ -#define PI_ERR_SPUR_MSG_A 0x000000008 -#define PI_ERR_WRB_TERR_B 0x000000010 /* WRB TERR */ -#define PI_ERR_WRB_TERR_A 0x000000020 -#define PI_ERR_WRB_WERR_B 0x000000040 /* WRB WERR */ -#define PI_ERR_WRB_WERR_A 0x000000080 -#define PI_ERR_SYSSTATE_B 0x000000100 /* SysState parity error */ -#define PI_ERR_SYSSTATE_A 0x000000200 -#define PI_ERR_SYSAD_DATA_B 0x000000400 /* SysAD data parity error */ -#define PI_ERR_SYSAD_DATA_A 0x000000800 -#define PI_ERR_SYSAD_ADDR_B 0x000001000 /* SysAD addr parity error */ -#define PI_ERR_SYSAD_ADDR_A 0x000002000 -#define PI_ERR_SYSCMD_DATA_B 0x000004000 /* SysCmd data parity error */ -#define PI_ERR_SYSCMD_DATA_A 0x000008000 -#define PI_ERR_SYSCMD_ADDR_B 0x000010000 /* SysCmd addr parity error */ -#define PI_ERR_SYSCMD_ADDR_A 0x000020000 -#define PI_ERR_BAD_SPOOL_B 0x000040000 /* Error spooling to memory */ -#define PI_ERR_BAD_SPOOL_A 0x000080000 -#define PI_ERR_UNCAC_UNCORR_B 0x000100000 /* Uncached uncorrectable */ -#define PI_ERR_UNCAC_UNCORR_A 0x000200000 -#define PI_ERR_SYSSTATE_TAG_B 0x000400000 /* SysState tag parity error */ -#define PI_ERR_SYSSTATE_TAG_A 0x000800000 -#define PI_ERR_MD_UNCORR 0x001000000 /* Must be cleared in MD */ -#define PI_ERR_SYSAD_BAD_DATA_B 0x002000000 /* SysAD Data quality bad */ -#define PI_ERR_SYSAD_BAD_DATA_A 0x004000000 -#define PI_ERR_UE_CACHED_B 0x008000000 /* UE during cached load */ -#define PI_ERR_UE_CACHED_A 0x010000000 -#define PI_ERR_PKT_LEN_ERR_B 0x020000000 /* Xbar data too long/short */ -#define PI_ERR_PKT_LEN_ERR_A 0x040000000 -#define PI_ERR_IRB_ERR_B 0x080000000 /* Protocol error */ -#define PI_ERR_IRB_ERR_A 0x100000000 -#define PI_ERR_IRB_TIMEOUT_B 0x200000000 /* IRB_B got a timeout */ -#define PI_ERR_IRB_TIMEOUT_A 0x400000000 - -#define PI_ERR_CLEAR_ALL_A 0x554aaaaaa -#define PI_ERR_CLEAR_ALL_B 0x2aa555555 - - -/* - * The following three macros define all possible error int pends. - */ - -#define PI_FATAL_ERR_CPU_A (PI_ERR_IRB_TIMEOUT_A | \ - PI_ERR_IRB_ERR_A | \ - PI_ERR_PKT_LEN_ERR_A | \ - PI_ERR_SYSSTATE_TAG_A | \ - PI_ERR_BAD_SPOOL_A | \ - PI_ERR_SYSCMD_ADDR_A | \ - PI_ERR_SYSCMD_DATA_A | \ - PI_ERR_SYSAD_ADDR_A | \ - PI_ERR_SYSAD_DATA_A | \ - PI_ERR_SYSSTATE_A) - -#define PI_MISC_ERR_CPU_A (PI_ERR_UE_CACHED_A | \ - PI_ERR_SYSAD_BAD_DATA_A| \ - PI_ERR_UNCAC_UNCORR_A | \ - PI_ERR_WRB_WERR_A | \ - PI_ERR_WRB_TERR_A | \ - PI_ERR_SPUR_MSG_A | \ - PI_ERR_SPOOL_CMP_A) - -#define PI_FATAL_ERR_CPU_B (PI_ERR_IRB_TIMEOUT_B | \ - PI_ERR_IRB_ERR_B | \ - PI_ERR_PKT_LEN_ERR_B | \ - PI_ERR_SYSSTATE_TAG_B | \ - PI_ERR_BAD_SPOOL_B | \ - PI_ERR_SYSCMD_ADDR_B | \ - PI_ERR_SYSCMD_DATA_B | \ - PI_ERR_SYSAD_ADDR_B | \ - PI_ERR_SYSAD_DATA_B | \ - PI_ERR_SYSSTATE_B) - -#define PI_MISC_ERR_CPU_B (PI_ERR_UE_CACHED_B | \ - PI_ERR_SYSAD_BAD_DATA_B| \ - PI_ERR_UNCAC_UNCORR_B | \ - PI_ERR_WRB_WERR_B | \ - PI_ERR_WRB_TERR_B | \ - PI_ERR_SPUR_MSG_B | \ - PI_ERR_SPOOL_CMP_B) - -#define PI_ERR_GENERIC (PI_ERR_MD_UNCORR) - -/* Values for PI_MAX_CRB_TIMEOUT and PI_CRB_SFACTOR */ -#define PMCT_MAX 0xff -#define PCS_MAX 0xffffff - -/* pi_err_status0_a_u_t address shift */ -#define ERR_STAT0_ADDR_SHFT 3 - -/* PI error read/write bit (RRB == 0, WRB == 1) */ -/* pi_err_status1_a_u_t.pi_err_status1_a_fld_s.esa_wrb */ -#define PI_ERR_RRB 0 -#define PI_ERR_WRB 1 - -/* Error stack address shift, for use with pi_stk_fmt.sk_addr */ -#define ERR_STK_ADDR_SHFT 3 - -#endif /* _ASM_IA64_SN_SN1_HUBPI_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubspc.h b/include/asm-ia64/sn/sn1/hubspc.h --- a/include/asm-ia64/sn/sn1/hubspc.h Fri Mar 8 18:11:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBSPC_H -#define _ASM_IA64_SN_SN1_HUBSPC_H - -typedef enum { - HUBSPC_REFCOUNTERS, - HUBSPC_PROM -} hubspc_subdevice_t; - - -/* - * Reference Counters - */ - -extern int refcounters_attach(devfs_handle_t hub); - -#endif /* _ASM_IA64_SN_SN1_HUBSPC_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubstat.h b/include/asm-ia64/sn/sn1/hubstat.h --- a/include/asm-ia64/sn/sn1/hubstat.h Sat Mar 9 02:24:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,56 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 - 2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_HUBSTAT_H -#define _ASM_IA64_SN_SN1_HUBSTAT_H - -typedef int64_t hub_count_t; - -#define HUBSTAT_VERSION 1 - -typedef struct hubstat_s { - char hs_version; /* structure version */ - cnodeid_t hs_cnode; /* cnode of this hub */ - nasid_t hs_nasid; /* Nasid of same */ - int64_t hs_timebase; /* Time of first sample */ - int64_t hs_timestamp; /* Time of last sample */ - int64_t hs_per_minute; /* Ticks per minute */ - - union { - hubreg_t hs_niu_stat_rev_id; /* SN0: Status rev ID */ - hubreg_t hs_niu_port_status; /* SN1: Port status */ - } hs_niu; - - hub_count_t hs_ni_retry_errors; /* Total retry errors */ - hub_count_t hs_ni_sn_errors; /* Total sn errors */ - hub_count_t hs_ni_cb_errors; /* Total cb errors */ - int hs_ni_overflows; /* NI count overflows */ - hub_count_t hs_ii_sn_errors; /* Total sn errors */ - hub_count_t hs_ii_cb_errors; /* Total cb errors */ - int hs_ii_overflows; /* II count overflows */ - - /* - * Anything below this comment is intended for kernel internal-use - * only and may be changed at any time. - * - * Any members that contain pointers or are conditionally compiled - * need to be below here also. - */ - int64_t hs_last_print; /* When we last printed */ - char hs_print; /* Should we print */ - - char *hs_name; /* This hub's name */ - unsigned char hs_maint; /* Should we print to availmon */ -} hubstat_t; - -#define hs_ni_stat_rev_id hs_niu.hs_niu_stat_rev_id -#define hs_ni_port_status hs_niu.hs_niu_port_status - -extern struct file_operations hub_mon_fops; - -#endif /* _ASM_IA64_SN_SN1_HUBSTAT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubxb.h b/include/asm-ia64/sn/sn1/hubxb.h --- a/include/asm-ia64/sn/sn1/hubxb.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1288 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBXB_H -#define _ASM_IA64_SN_SN1_HUBXB_H - -/************************************************************************ - * * - * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! * - * * - * This file is created by an automated script. Any (minimal) changes * - * made manually to this file should be made with care. * - * * - * MAKE ALL ADDITIONS TO THE END OF THIS FILE * - * * - ************************************************************************/ - - -#define XB_PARMS 0x00700000 /* - * Controls - * crossbar-wide - * parameters. - */ - - - -#define XB_SLOW_GNT 0x00700008 /* - * Controls wavefront - * arbiter grant - * frequency, used to - * slow XB grants - */ - - - -#define XB_SPEW_CONTROL 0x00700010 /* - * Controls spew - * settings (debug - * only). - */ - - - -#define XB_IOQ_ARB_TRIGGER 0x00700018 /* - * Controls IOQ - * trigger level - */ - - - -#define XB_FIRST_ERROR 0x00700090 /* - * Records the first - * crossbar error - * seen. - */ - - - -#define XB_POQ0_ERROR 0x00700020 /* - * POQ0 error - * register. - */ - - - -#define XB_PIQ0_ERROR 0x00700028 /* - * PIQ0 error - * register. - */ - - - -#define XB_POQ1_ERROR 0x00700030 /* - * POQ1 error - * register. - */ - - - -#define XB_PIQ1_ERROR 0x00700038 /* - * PIQ1 error - * register. - */ - - - -#define XB_MP0_ERROR 0x00700040 /* - * MOQ for PI0 error - * register. - */ - - - -#define XB_MP1_ERROR 0x00700048 /* - * MOQ for PI1 error - * register. - */ - - - -#define XB_MMQ_ERROR 0x00700050 /* - * MOQ for misc. (LB, - * NI, II) error - * register. - */ - - - -#define XB_MIQ_ERROR 0x00700058 /* - * MIQ error register, - * addtional MIQ - * errors are logged - * in MD "Input - * Error - * Registers". - */ - - - -#define XB_NOQ_ERROR 0x00700060 /* NOQ error register. */ - - - -#define XB_NIQ_ERROR 0x00700068 /* NIQ error register. */ - - - -#define XB_IOQ_ERROR 0x00700070 /* IOQ error register. */ - - - -#define XB_IIQ_ERROR 0x00700078 /* IIQ error register. */ - - - -#define XB_LOQ_ERROR 0x00700080 /* LOQ error register. */ - - - -#define XB_LIQ_ERROR 0x00700088 /* LIQ error register. */ - - - -#define XB_DEBUG_DATA_CTL 0x00700098 /* - * Debug Datapath - * Select - */ - - - -#define XB_DEBUG_ARB_CTL 0x007000A0 /* - * XB master debug - * control - */ - - - -#define XB_POQ0_ERROR_CLEAR 0x00700120 /* - * Clears - * XB_POQ0_ERROR - * register. - */ - - - -#define XB_PIQ0_ERROR_CLEAR 0x00700128 /* - * Clears - * XB_PIQ0_ERROR - * register. - */ - - - -#define XB_POQ1_ERROR_CLEAR 0x00700130 /* - * Clears - * XB_POQ1_ERROR - * register. - */ - - - -#define XB_PIQ1_ERROR_CLEAR 0x00700138 /* - * Clears - * XB_PIQ1_ERROR - * register. - */ - - - -#define XB_MP0_ERROR_CLEAR 0x00700140 /* - * Clears XB_MP0_ERROR - * register. - */ - - - -#define XB_MP1_ERROR_CLEAR 0x00700148 /* - * Clears XB_MP1_ERROR - * register. - */ - - - -#define XB_MMQ_ERROR_CLEAR 0x00700150 /* - * Clears XB_MMQ_ERROR - * register. - */ - - - -#define XB_XM_MIQ_ERROR_CLEAR 0x00700158 /* - * Clears XB_MIQ_ERROR - * register - */ - - - -#define XB_NOQ_ERROR_CLEAR 0x00700160 /* - * Clears XB_NOQ_ERROR - * register. - */ - - - -#define XB_NIQ_ERROR_CLEAR 0x00700168 /* - * Clears XB_NIQ_ERROR - * register. - */ - - - -#define XB_IOQ_ERROR_CLEAR 0x00700170 /* - * Clears XB_IOQ - * _ERROR register. - */ - - - -#define XB_IIQ_ERROR_CLEAR 0x00700178 /* - * Clears XB_IIQ - * _ERROR register. - */ - - - -#define XB_LOQ_ERROR_CLEAR 0x00700180 /* - * Clears XB_LOQ_ERROR - * register. - */ - - - -#define XB_LIQ_ERROR_CLEAR 0x00700188 /* - * Clears XB_LIQ_ERROR - * register. - */ - - - -#define XB_FIRST_ERROR_CLEAR 0x00700190 /* - * Clears - * XB_FIRST_ERROR - * register - */ - - - - - -#ifndef __ASSEMBLY__ - -/************************************************************************ - * * - * Access to parameters which control various aspects of the * - * crossbar's operation. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_parms_u { - bdrkreg_t xb_parms_regval; - struct { - bdrkreg_t p_byp_en : 1; - bdrkreg_t p_rsrvd_1 : 3; - bdrkreg_t p_age_wrap : 8; - bdrkreg_t p_deadlock_to_wrap : 20; - bdrkreg_t p_tail_to_wrap : 20; - bdrkreg_t p_rsrvd : 12; - } xb_parms_fld_s; -} xb_parms_u_t; - -#else - -typedef union xb_parms_u { - bdrkreg_t xb_parms_regval; - struct { - bdrkreg_t p_rsrvd : 12; - bdrkreg_t p_tail_to_wrap : 20; - bdrkreg_t p_deadlock_to_wrap : 20; - bdrkreg_t p_age_wrap : 8; - bdrkreg_t p_rsrvd_1 : 3; - bdrkreg_t p_byp_en : 1; - } xb_parms_fld_s; -} xb_parms_u_t; - -#endif - - - - -/************************************************************************ - * * - * Sets the period of wavefront grants given to each unit. The * - * register's value corresponds to the number of cycles between each * - * wavefront grant opportunity given to the requesting unit. If set * - * to 0xF, no grants are given to this unit. If set to 0xE, the unit * - * is granted at the slowest rate (sometimes called "molasses mode"). * - * This feature can be used to apply backpressure to a unit's output * - * queue(s). The setting does not affect bypass grants. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_slow_gnt_u { - bdrkreg_t xb_slow_gnt_regval; - struct { - bdrkreg_t sg_lb_slow_gnt : 4; - bdrkreg_t sg_ii_slow_gnt : 4; - bdrkreg_t sg_ni_slow_gnt : 4; - bdrkreg_t sg_mmq_slow_gnt : 4; - bdrkreg_t sg_mp1_slow_gnt : 4; - bdrkreg_t sg_mp0_slow_gnt : 4; - bdrkreg_t sg_pi1_slow_gnt : 4; - bdrkreg_t sg_pi0_slow_gnt : 4; - bdrkreg_t sg_rsrvd : 32; - } xb_slow_gnt_fld_s; -} xb_slow_gnt_u_t; - -#else - -typedef union xb_slow_gnt_u { - bdrkreg_t xb_slow_gnt_regval; - struct { - bdrkreg_t sg_rsrvd : 32; - bdrkreg_t sg_pi0_slow_gnt : 4; - bdrkreg_t sg_pi1_slow_gnt : 4; - bdrkreg_t sg_mp0_slow_gnt : 4; - bdrkreg_t sg_mp1_slow_gnt : 4; - bdrkreg_t sg_mmq_slow_gnt : 4; - bdrkreg_t sg_ni_slow_gnt : 4; - bdrkreg_t sg_ii_slow_gnt : 4; - bdrkreg_t sg_lb_slow_gnt : 4; - } xb_slow_gnt_fld_s; -} xb_slow_gnt_u_t; - -#endif - - - - -/************************************************************************ - * * - * Enables snooping of internal crossbar traffic by spewing all * - * traffic across a selected crossbar point to the PI1 port. Only one * - * bit should be set at any one time, and any bit set will preclude * - * using the P1 for anything but a debug connection. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_spew_control_u { - bdrkreg_t xb_spew_control_regval; - struct { - bdrkreg_t sc_snoop_liq : 1; - bdrkreg_t sc_snoop_iiq : 1; - bdrkreg_t sc_snoop_niq : 1; - bdrkreg_t sc_snoop_miq : 1; - bdrkreg_t sc_snoop_piq0 : 1; - bdrkreg_t sc_snoop_loq : 1; - bdrkreg_t sc_snoop_ioq : 1; - bdrkreg_t sc_snoop_noq : 1; - bdrkreg_t sc_snoop_mmq : 1; - bdrkreg_t sc_snoop_mp0 : 1; - bdrkreg_t sc_snoop_poq0 : 1; - bdrkreg_t sc_rsrvd : 53; - } xb_spew_control_fld_s; -} xb_spew_control_u_t; - -#else - -typedef union xb_spew_control_u { - bdrkreg_t xb_spew_control_regval; - struct { - bdrkreg_t sc_rsrvd : 53; - bdrkreg_t sc_snoop_poq0 : 1; - bdrkreg_t sc_snoop_mp0 : 1; - bdrkreg_t sc_snoop_mmq : 1; - bdrkreg_t sc_snoop_noq : 1; - bdrkreg_t sc_snoop_ioq : 1; - bdrkreg_t sc_snoop_loq : 1; - bdrkreg_t sc_snoop_piq0 : 1; - bdrkreg_t sc_snoop_miq : 1; - bdrkreg_t sc_snoop_niq : 1; - bdrkreg_t sc_snoop_iiq : 1; - bdrkreg_t sc_snoop_liq : 1; - } xb_spew_control_fld_s; -} xb_spew_control_u_t; - -#endif - - - - -/************************************************************************ - * * - * Number of clocks the IOQ will wait before beginning XB * - * arbitration. This is set so that the slower IOQ data rate can * - * catch up up with the XB data rate in the IOQ buffer. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_ioq_arb_trigger_u { - bdrkreg_t xb_ioq_arb_trigger_regval; - struct { - bdrkreg_t iat_ioq_arb_trigger : 4; - bdrkreg_t iat_rsrvd : 60; - } xb_ioq_arb_trigger_fld_s; -} xb_ioq_arb_trigger_u_t; - -#else - -typedef union xb_ioq_arb_trigger_u { - bdrkreg_t xb_ioq_arb_trigger_regval; - struct { - bdrkreg_t iat_rsrvd : 60; - bdrkreg_t iat_ioq_arb_trigger : 4; - } xb_ioq_arb_trigger_fld_s; -} xb_ioq_arb_trigger_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by POQ0.Can be written to test software, will * - * cause an interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_poq0_error_u { - bdrkreg_t xb_poq0_error_regval; - struct { - bdrkreg_t pe_invalid_xsel : 2; - bdrkreg_t pe_rsrvd_3 : 2; - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_2 : 2; - bdrkreg_t pe_underflow : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_tail_timeout : 2; - bdrkreg_t pe_unused : 6; - bdrkreg_t pe_rsrvd : 44; - } xb_poq0_error_fld_s; -} xb_poq0_error_u_t; - -#else - -typedef union xb_poq0_error_u { - bdrkreg_t xb_poq0_error_regval; - struct { - bdrkreg_t pe_rsrvd : 44; - bdrkreg_t pe_unused : 6; - bdrkreg_t pe_tail_timeout : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_underflow : 2; - bdrkreg_t pe_rsrvd_2 : 2; - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_3 : 2; - bdrkreg_t pe_invalid_xsel : 2; - } xb_poq0_error_fld_s; -} xb_poq0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by PIQ0. Note that the PIQ/PI interface * - * precludes PIQ underflow. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_piq0_error_u { - bdrkreg_t xb_piq0_error_regval; - struct { - bdrkreg_t pe_overflow : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_deadlock_timeout : 2; - bdrkreg_t pe_rsrvd : 58; - } xb_piq0_error_fld_s; -} xb_piq0_error_u_t; - -#else - -typedef union xb_piq0_error_u { - bdrkreg_t xb_piq0_error_regval; - struct { - bdrkreg_t pe_rsrvd : 58; - bdrkreg_t pe_deadlock_timeout : 2; - bdrkreg_t pe_rsrvd_1 : 2; - bdrkreg_t pe_overflow : 2; - } xb_piq0_error_fld_s; -} xb_piq0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MP0 queue (the MOQ for processor 0). Since * - * the xselect is decoded on the MD/MOQ interface, no invalid xselect * - * errors are possible. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_mp0_error_u { - bdrkreg_t xb_mp0_error_regval; - struct { - bdrkreg_t me_rsrvd_3 : 4; - bdrkreg_t me_overflow : 2; - bdrkreg_t me_rsrvd_2 : 2; - bdrkreg_t me_underflow : 2; - bdrkreg_t me_rsrvd_1 : 2; - bdrkreg_t me_tail_timeout : 2; - bdrkreg_t me_rsrvd : 50; - } xb_mp0_error_fld_s; -} xb_mp0_error_u_t; - -#else - -typedef union xb_mp0_error_u { - bdrkreg_t xb_mp0_error_regval; - struct { - bdrkreg_t me_rsrvd : 50; - bdrkreg_t me_tail_timeout : 2; - bdrkreg_t me_rsrvd_1 : 2; - bdrkreg_t me_underflow : 2; - bdrkreg_t me_rsrvd_2 : 2; - bdrkreg_t me_overflow : 2; - bdrkreg_t me_rsrvd_3 : 4; - } xb_mp0_error_fld_s; -} xb_mp0_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MIQ. * - * * - ************************************************************************/ - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_miq_error_u { - bdrkreg_t xb_miq_error_regval; - struct { - bdrkreg_t me_rsrvd_1 : 4; - bdrkreg_t me_deadlock_timeout : 4; - bdrkreg_t me_rsrvd : 56; - } xb_miq_error_fld_s; -} xb_miq_error_u_t; - -#else - -typedef union xb_miq_error_u { - bdrkreg_t xb_miq_error_regval; - struct { - bdrkreg_t me_rsrvd : 56; - bdrkreg_t me_deadlock_timeout : 4; - bdrkreg_t me_rsrvd_1 : 4; - } xb_miq_error_fld_s; -} xb_miq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by NOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_noq_error_u { - bdrkreg_t xb_noq_error_regval; - struct { - bdrkreg_t ne_rsvd : 4; - bdrkreg_t ne_overflow : 4; - bdrkreg_t ne_underflow : 4; - bdrkreg_t ne_tail_timeout : 4; - bdrkreg_t ne_rsrvd : 48; - } xb_noq_error_fld_s; -} xb_noq_error_u_t; - -#else - -typedef union xb_noq_error_u { - bdrkreg_t xb_noq_error_regval; - struct { - bdrkreg_t ne_rsrvd : 48; - bdrkreg_t ne_tail_timeout : 4; - bdrkreg_t ne_underflow : 4; - bdrkreg_t ne_overflow : 4; - bdrkreg_t ne_rsvd : 4; - } xb_noq_error_fld_s; -} xb_noq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_loq_error_u { - bdrkreg_t xb_loq_error_regval; - struct { - bdrkreg_t le_invalid_xsel : 2; - bdrkreg_t le_rsrvd_1 : 6; - bdrkreg_t le_underflow : 2; - bdrkreg_t le_rsvd : 2; - bdrkreg_t le_tail_timeout : 2; - bdrkreg_t le_rsrvd : 50; - } xb_loq_error_fld_s; -} xb_loq_error_u_t; - -#else - -typedef union xb_loq_error_u { - bdrkreg_t xb_loq_error_regval; - struct { - bdrkreg_t le_rsrvd : 50; - bdrkreg_t le_tail_timeout : 2; - bdrkreg_t le_rsvd : 2; - bdrkreg_t le_underflow : 2; - bdrkreg_t le_rsrvd_1 : 6; - bdrkreg_t le_invalid_xsel : 2; - } xb_loq_error_fld_s; -} xb_loq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LIQ. Note that the LIQ only records errors * - * for the request channel. The reply channel can never deadlock or * - * overflow because it does not have hardware flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_liq_error_u { - bdrkreg_t xb_liq_error_regval; - struct { - bdrkreg_t le_overflow : 1; - bdrkreg_t le_rsrvd_1 : 3; - bdrkreg_t le_deadlock_timeout : 1; - bdrkreg_t le_rsrvd : 59; - } xb_liq_error_fld_s; -} xb_liq_error_u_t; - -#else - -typedef union xb_liq_error_u { - bdrkreg_t xb_liq_error_regval; - struct { - bdrkreg_t le_rsrvd : 59; - bdrkreg_t le_deadlock_timeout : 1; - bdrkreg_t le_rsrvd_1 : 3; - bdrkreg_t le_overflow : 1; - } xb_liq_error_fld_s; -} xb_liq_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * First error is latched whenever the Valid bit is clear and an * - * error occurs. Any valid bit on in this register causes an * - * interrupt to PI0 and PI1. This interrupt bit will persist until * - * the specific error register to capture the error is cleared, then * - * the FIRST_ERROR register is cleared (in that oder.) The * - * FIRST_ERROR register is not writable, but will be set when any of * - * the corresponding error registers are written by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_first_error_u { - bdrkreg_t xb_first_error_regval; - struct { - bdrkreg_t fe_type : 4; - bdrkreg_t fe_channel : 4; - bdrkreg_t fe_source : 4; - bdrkreg_t fe_valid : 1; - bdrkreg_t fe_rsrvd : 51; - } xb_first_error_fld_s; -} xb_first_error_u_t; - -#else - -typedef union xb_first_error_u { - bdrkreg_t xb_first_error_regval; - struct { - bdrkreg_t fe_rsrvd : 51; - bdrkreg_t fe_valid : 1; - bdrkreg_t fe_source : 4; - bdrkreg_t fe_channel : 4; - bdrkreg_t fe_type : 4; - } xb_first_error_fld_s; -} xb_first_error_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls DEBUG_DATA mux setting. Allows user to watch the output * - * of any OQ or input of any IQ on the DEBUG port. Note that bits * - * 13:0 are one-hot. If more than one bit is set in [13:0], the debug * - * output is undefined. Details on the debug output lines can be * - * found in the XB chapter of the Bedrock Interface Specification. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_debug_data_ctl_u { - bdrkreg_t xb_debug_data_ctl_regval; - struct { - bdrkreg_t ddc_observe_liq_traffic : 1; - bdrkreg_t ddc_observe_iiq_traffic : 1; - bdrkreg_t ddc_observe_niq_traffic : 1; - bdrkreg_t ddc_observe_miq_traffic : 1; - bdrkreg_t ddc_observe_piq1_traffic : 1; - bdrkreg_t ddc_observe_piq0_traffic : 1; - bdrkreg_t ddc_observe_loq_traffic : 1; - bdrkreg_t ddc_observe_ioq_traffic : 1; - bdrkreg_t ddc_observe_noq_traffic : 1; - bdrkreg_t ddc_observe_mp1_traffic : 1; - bdrkreg_t ddc_observe_mp0_traffic : 1; - bdrkreg_t ddc_observe_mmq_traffic : 1; - bdrkreg_t ddc_observe_poq1_traffic : 1; - bdrkreg_t ddc_observe_poq0_traffic : 1; - bdrkreg_t ddc_observe_source_field : 1; - bdrkreg_t ddc_observe_lodata : 1; - bdrkreg_t ddc_rsrvd : 48; - } xb_debug_data_ctl_fld_s; -} xb_debug_data_ctl_u_t; - -#else - -typedef union xb_debug_data_ctl_u { - bdrkreg_t xb_debug_data_ctl_regval; - struct { - bdrkreg_t ddc_rsrvd : 48; - bdrkreg_t ddc_observe_lodata : 1; - bdrkreg_t ddc_observe_source_field : 1; - bdrkreg_t ddc_observe_poq0_traffic : 1; - bdrkreg_t ddc_observe_poq1_traffic : 1; - bdrkreg_t ddc_observe_mmq_traffic : 1; - bdrkreg_t ddc_observe_mp0_traffic : 1; - bdrkreg_t ddc_observe_mp1_traffic : 1; - bdrkreg_t ddc_observe_noq_traffic : 1; - bdrkreg_t ddc_observe_ioq_traffic : 1; - bdrkreg_t ddc_observe_loq_traffic : 1; - bdrkreg_t ddc_observe_piq0_traffic : 1; - bdrkreg_t ddc_observe_piq1_traffic : 1; - bdrkreg_t ddc_observe_miq_traffic : 1; - bdrkreg_t ddc_observe_niq_traffic : 1; - bdrkreg_t ddc_observe_iiq_traffic : 1; - bdrkreg_t ddc_observe_liq_traffic : 1; - } xb_debug_data_ctl_fld_s; -} xb_debug_data_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Controls debug mux setting for XB Input/Output Queues and * - * Arbiter. Can select one of the following values. Details on the * - * debug output lines can be found in the XB chapter of the Bedrock * - * Interface Specification. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_debug_arb_ctl_u { - bdrkreg_t xb_debug_arb_ctl_regval; - struct { - bdrkreg_t dac_xb_debug_select : 3; - bdrkreg_t dac_rsrvd : 61; - } xb_debug_arb_ctl_fld_s; -} xb_debug_arb_ctl_u_t; - -#else - -typedef union xb_debug_arb_ctl_u { - bdrkreg_t xb_debug_arb_ctl_regval; - struct { - bdrkreg_t dac_rsrvd : 61; - bdrkreg_t dac_xb_debug_select : 3; - } xb_debug_arb_ctl_fld_s; -} xb_debug_arb_ctl_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by POQ0.Can be written to test software, will * - * cause an interrupt. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_poq0_error_clear_u { - bdrkreg_t xb_poq0_error_clear_regval; - struct { - bdrkreg_t pec_invalid_xsel : 2; - bdrkreg_t pec_rsrvd_3 : 2; - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_2 : 2; - bdrkreg_t pec_underflow : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_tail_timeout : 2; - bdrkreg_t pec_unused : 6; - bdrkreg_t pec_rsrvd : 44; - } xb_poq0_error_clear_fld_s; -} xb_poq0_error_clear_u_t; - -#else - -typedef union xb_poq0_error_clear_u { - bdrkreg_t xb_poq0_error_clear_regval; - struct { - bdrkreg_t pec_rsrvd : 44; - bdrkreg_t pec_unused : 6; - bdrkreg_t pec_tail_timeout : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_underflow : 2; - bdrkreg_t pec_rsrvd_2 : 2; - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_3 : 2; - bdrkreg_t pec_invalid_xsel : 2; - } xb_poq0_error_clear_fld_s; -} xb_poq0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by PIQ0. Note that the PIQ/PI interface * - * precludes PIQ underflow. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_piq0_error_clear_u { - bdrkreg_t xb_piq0_error_clear_regval; - struct { - bdrkreg_t pec_overflow : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_deadlock_timeout : 2; - bdrkreg_t pec_rsrvd : 58; - } xb_piq0_error_clear_fld_s; -} xb_piq0_error_clear_u_t; - -#else - -typedef union xb_piq0_error_clear_u { - bdrkreg_t xb_piq0_error_clear_regval; - struct { - bdrkreg_t pec_rsrvd : 58; - bdrkreg_t pec_deadlock_timeout : 2; - bdrkreg_t pec_rsrvd_1 : 2; - bdrkreg_t pec_overflow : 2; - } xb_piq0_error_clear_fld_s; -} xb_piq0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MP0 queue (the MOQ for processor 0). Since * - * the xselect is decoded on the MD/MOQ interface, no invalid xselect * - * errors are possible. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_mp0_error_clear_u { - bdrkreg_t xb_mp0_error_clear_regval; - struct { - bdrkreg_t mec_rsrvd_3 : 4; - bdrkreg_t mec_overflow : 2; - bdrkreg_t mec_rsrvd_2 : 2; - bdrkreg_t mec_underflow : 2; - bdrkreg_t mec_rsrvd_1 : 2; - bdrkreg_t mec_tail_timeout : 2; - bdrkreg_t mec_rsrvd : 50; - } xb_mp0_error_clear_fld_s; -} xb_mp0_error_clear_u_t; - -#else - -typedef union xb_mp0_error_clear_u { - bdrkreg_t xb_mp0_error_clear_regval; - struct { - bdrkreg_t mec_rsrvd : 50; - bdrkreg_t mec_tail_timeout : 2; - bdrkreg_t mec_rsrvd_1 : 2; - bdrkreg_t mec_underflow : 2; - bdrkreg_t mec_rsrvd_2 : 2; - bdrkreg_t mec_overflow : 2; - bdrkreg_t mec_rsrvd_3 : 4; - } xb_mp0_error_clear_fld_s; -} xb_mp0_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by MIQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_xm_miq_error_clear_u { - bdrkreg_t xb_xm_miq_error_clear_regval; - struct { - bdrkreg_t xmec_rsrvd_1 : 4; - bdrkreg_t xmec_deadlock_timeout : 4; - bdrkreg_t xmec_rsrvd : 56; - } xb_xm_miq_error_clear_fld_s; -} xb_xm_miq_error_clear_u_t; - -#else - -typedef union xb_xm_miq_error_clear_u { - bdrkreg_t xb_xm_miq_error_clear_regval; - struct { - bdrkreg_t xmec_rsrvd : 56; - bdrkreg_t xmec_deadlock_timeout : 4; - bdrkreg_t xmec_rsrvd_1 : 4; - } xb_xm_miq_error_clear_fld_s; -} xb_xm_miq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by NOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_noq_error_clear_u { - bdrkreg_t xb_noq_error_clear_regval; - struct { - bdrkreg_t nec_rsvd : 4; - bdrkreg_t nec_overflow : 4; - bdrkreg_t nec_underflow : 4; - bdrkreg_t nec_tail_timeout : 4; - bdrkreg_t nec_rsrvd : 48; - } xb_noq_error_clear_fld_s; -} xb_noq_error_clear_u_t; - -#else - -typedef union xb_noq_error_clear_u { - bdrkreg_t xb_noq_error_clear_regval; - struct { - bdrkreg_t nec_rsrvd : 48; - bdrkreg_t nec_tail_timeout : 4; - bdrkreg_t nec_underflow : 4; - bdrkreg_t nec_overflow : 4; - bdrkreg_t nec_rsvd : 4; - } xb_noq_error_clear_fld_s; -} xb_noq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LOQ. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_loq_error_clear_u { - bdrkreg_t xb_loq_error_clear_regval; - struct { - bdrkreg_t lec_invalid_xsel : 2; - bdrkreg_t lec_rsrvd_1 : 6; - bdrkreg_t lec_underflow : 2; - bdrkreg_t lec_rsvd : 2; - bdrkreg_t lec_tail_timeout : 2; - bdrkreg_t lec_rsrvd : 50; - } xb_loq_error_clear_fld_s; -} xb_loq_error_clear_u_t; - -#else - -typedef union xb_loq_error_clear_u { - bdrkreg_t xb_loq_error_clear_regval; - struct { - bdrkreg_t lec_rsrvd : 50; - bdrkreg_t lec_tail_timeout : 2; - bdrkreg_t lec_rsvd : 2; - bdrkreg_t lec_underflow : 2; - bdrkreg_t lec_rsrvd_1 : 6; - bdrkreg_t lec_invalid_xsel : 2; - } xb_loq_error_clear_fld_s; -} xb_loq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * Records errors seen by LIQ. Note that the LIQ only records errors * - * for the request channel. The reply channel can never deadlock or * - * overflow because it does not have hardware flow control. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_liq_error_clear_u { - bdrkreg_t xb_liq_error_clear_regval; - struct { - bdrkreg_t lec_overflow : 1; - bdrkreg_t lec_rsrvd_1 : 3; - bdrkreg_t lec_deadlock_timeout : 1; - bdrkreg_t lec_rsrvd : 59; - } xb_liq_error_clear_fld_s; -} xb_liq_error_clear_u_t; - -#else - -typedef union xb_liq_error_clear_u { - bdrkreg_t xb_liq_error_clear_regval; - struct { - bdrkreg_t lec_rsrvd : 59; - bdrkreg_t lec_deadlock_timeout : 1; - bdrkreg_t lec_rsrvd_1 : 3; - bdrkreg_t lec_overflow : 1; - } xb_liq_error_clear_fld_s; -} xb_liq_error_clear_u_t; - -#endif - - - - -/************************************************************************ - * * - * First error is latched whenever the Valid bit is clear and an * - * error occurs. Any valid bit on in this register causes an * - * interrupt to PI0 and PI1. This interrupt bit will persist until * - * the specific error register to capture the error is cleared, then * - * the FIRST_ERROR register is cleared (in that oder.) The * - * FIRST_ERROR register is not writable, but will be set when any of * - * the corresponding error registers are written by software. * - * * - ************************************************************************/ - - - - -#ifdef LITTLE_ENDIAN - -typedef union xb_first_error_clear_u { - bdrkreg_t xb_first_error_clear_regval; - struct { - bdrkreg_t fec_type : 4; - bdrkreg_t fec_channel : 4; - bdrkreg_t fec_source : 4; - bdrkreg_t fec_valid : 1; - bdrkreg_t fec_rsrvd : 51; - } xb_first_error_clear_fld_s; -} xb_first_error_clear_u_t; - -#else - -typedef union xb_first_error_clear_u { - bdrkreg_t xb_first_error_clear_regval; - struct { - bdrkreg_t fec_rsrvd : 51; - bdrkreg_t fec_valid : 1; - bdrkreg_t fec_source : 4; - bdrkreg_t fec_channel : 4; - bdrkreg_t fec_type : 4; - } xb_first_error_clear_fld_s; -} xb_first_error_clear_u_t; - -#endif - - - - - - -#endif /* __ASSEMBLY__ */ - -/************************************************************************ - * * - * The following defines were not formed into structures * - * * - * This could be because the document did not contain details of the * - * register, or because the automated script did not recognize the * - * register details in the documentation. If these register need * - * structure definition, please create them manually * - * * - * XB_POQ1_ERROR 0x700030 * - * XB_PIQ1_ERROR 0x700038 * - * XB_MP1_ERROR 0x700048 * - * XB_MMQ_ERROR 0x700050 * - * XB_NIQ_ERROR 0x700068 * - * XB_IOQ_ERROR 0x700070 * - * XB_IIQ_ERROR 0x700078 * - * XB_POQ1_ERROR_CLEAR 0x700130 * - * XB_PIQ1_ERROR_CLEAR 0x700138 * - * XB_MP1_ERROR_CLEAR 0x700148 * - * XB_MMQ_ERROR_CLEAR 0x700150 * - * XB_NIQ_ERROR_CLEAR 0x700168 * - * XB_IOQ_ERROR_CLEAR 0x700170 * - * XB_IIQ_ERROR_CLEAR 0x700178 * - * * - ************************************************************************/ - - -/************************************************************************ - * * - * MAKE ALL ADDITIONS AFTER THIS LINE * - * * - ************************************************************************/ - - - - - -#endif /* _ASM_IA64_SN_SN1_HUBXB_H */ diff -Nru a/include/asm-ia64/sn/sn1/hubxb_next.h b/include/asm-ia64/sn/sn1/hubxb_next.h --- a/include/asm-ia64/sn/sn1/hubxb_next.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,32 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HUBXB_NEXT_H -#define _ASM_IA64_SN_SN1_HUBXB_NEXT_H - -/* XB_FIRST_ERROR fe_source field encoding */ -#define XVE_SOURCE_POQ0 0xf /* 1111 */ -#define XVE_SOURCE_PIQ0 0xe /* 1110 */ -#define XVE_SOURCE_POQ1 0xd /* 1101 */ -#define XVE_SOURCE_PIQ1 0xc /* 1100 */ -#define XVE_SOURCE_MP0 0xb /* 1011 */ -#define XVE_SOURCE_MP1 0xa /* 1010 */ -#define XVE_SOURCE_MMQ 0x9 /* 1001 */ -#define XVE_SOURCE_MIQ 0x8 /* 1000 */ -#define XVE_SOURCE_NOQ 0x7 /* 0111 */ -#define XVE_SOURCE_NIQ 0x6 /* 0110 */ -#define XVE_SOURCE_IOQ 0x5 /* 0101 */ -#define XVE_SOURCE_IIQ 0x4 /* 0100 */ -#define XVE_SOURCE_LOQ 0x3 /* 0011 */ -#define XVE_SOURCE_LIQ 0x2 /* 0010 */ - -/* XB_PARMS fields */ -#define XBP_RESET_DEFAULTS 0x0008000080000021LL -#define XBP_ACTIVE_DEFAULTS 0x00080000fffff021LL - -#endif /* _ASM_IA64_SN_SN1_HUBXB_NEXT_H */ diff -Nru a/include/asm-ia64/sn/sn1/hwcntrs.h b/include/asm-ia64/sn/sn1/hwcntrs.h --- a/include/asm-ia64/sn/sn1/hwcntrs.h Fri Mar 8 18:11:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,96 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_HWCNTRS_H -#define _ASM_IA64_SN_SN1_HWCNTRS_H - - -typedef uint64_t refcnt_t; - -#define SN0_REFCNT_MAX_COUNTERS 64 - -typedef struct sn0_refcnt_set { - refcnt_t refcnt[SN0_REFCNT_MAX_COUNTERS]; - uint64_t flags; - uint64_t reserved[4]; -} sn0_refcnt_set_t; - -typedef struct sn0_refcnt_buf { - sn0_refcnt_set_t refcnt_set; - uint64_t paddr; - uint64_t page_size; - cnodeid_t cnodeid; /* cnodeid + pad[3] use 64 bits */ - uint16_t pad[3]; - uint64_t reserved[4]; -} sn0_refcnt_buf_t; - -typedef struct sn0_refcnt_args { - uint64_t vaddr; - uint64_t len; - sn0_refcnt_buf_t* buf; - uint64_t reserved[4]; -} sn0_refcnt_args_t; - -/* - * Info needed by the user level program - * to mmap the refcnt buffer - */ - -#define RCB_INFO_GET 1 -#define RCB_SLOT_GET 2 - -typedef struct rcb_info { - uint64_t rcb_len; /* total refcnt buffer len in bytes */ - - int rcb_sw_sets; /* number of sw counter sets in buffer */ - int rcb_sw_counters_per_set; /* sw counters per set -- num_compact_nodes */ - int rcb_sw_counter_size; /* sizeof(refcnt_t) -- size of sw cntr */ - - int rcb_base_pages; /* number of base pages in node */ - int rcb_base_page_size; /* sw base page size */ - uint64_t rcb_base_paddr; /* base physical address for this node */ - - int rcb_cnodeid; /* cnodeid for this node */ - int rcb_granularity; /* hw page size used for counter sets */ - uint rcb_hw_counter_max; /* max hwcounter count (width mask) */ - int rcb_diff_threshold; /* current node differential threshold */ - int rcb_abs_threshold; /* current node absolute threshold */ - int rcb_num_slots; /* physmem slots */ - - int rcb_reserved[512]; - -} rcb_info_t; - -typedef struct rcb_slot { - uint64_t base; - uint64_t size; -} rcb_slot_t; - -#if defined(__KERNEL__) -typedef struct sn0_refcnt_args_32 { - uint64_t vaddr; - uint64_t len; - app32_ptr_t buf; - uint64_t reserved[4]; -} sn0_refcnt_args_32_t; - -/* Defines and Macros */ -/* A set of reference counts are for 4k bytes of physical memory */ -#define NBPREFCNTP 0x1000 -#define BPREFCNTPSHIFT 12 -#define bytes_to_refcntpages(x) (((__psunsigned_t)(x)+(NBPREFCNTP-1))>>BPREFCNTPSHIFT) -#define refcntpage_offset(x) ((__psunsigned_t)(x)&((NBPP-1)&~(NBPREFCNTP-1))) -#define align_to_refcntpage(x) ((__psunsigned_t)(x)&(~(NBPREFCNTP-1))) - -extern void migr_refcnt_read(sn0_refcnt_buf_t*); -extern void migr_refcnt_read_extended(sn0_refcnt_buf_t*); -extern int migr_refcnt_enabled(void); - -#endif /* __KERNEL__ */ - -#endif /* _ASM_IA64_SN_SN1_HWCNTRS_H */ diff -Nru a/include/asm-ia64/sn/sn1/intr.h b/include/asm-ia64/sn/sn1/intr.h --- a/include/asm-ia64/sn/sn1/intr.h Tue Dec 3 10:07:34 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,237 +0,0 @@ -/* $Id: intr.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_INTR_H -#define _ASM_IA64_SN_SN1_INTR_H - -/* Subnode wildcard */ -#define SUBNODE_ANY (-1) - -/* Number of interrupt levels associated with each interrupt register. */ -#define N_INTPEND_BITS 64 - -#define INT_PEND0_BASELVL 0 -#define INT_PEND1_BASELVL 64 - -#define N_INTPENDJUNK_BITS 8 -#define INTPENDJUNK_CLRBIT 0x80 - -#include -#include -#include -#include - -#ifndef __ASSEMBLY__ -#define II_NAMELEN 24 - -/* - * Dispatch table entry - contains information needed to call an interrupt - * routine. - */ -typedef struct intr_vector_s { - intr_func_t iv_func; /* Interrupt handler function */ - intr_func_t iv_prefunc; /* Interrupt handler prologue func */ - void *iv_arg; /* Argument to pass to handler */ - cpuid_t iv_mustruncpu; /* Where we must run. */ -} intr_vector_t; - -/* Interrupt information table. */ -typedef struct intr_info_s { - xtalk_intr_setfunc_t ii_setfunc; /* Function to set the interrupt - * destination and level register. - * It returns 0 (success) or an - * error code. - */ - void *ii_cookie; /* arg passed to setfunc */ - devfs_handle_t ii_owner_dev; /* device that owns this intr */ - char ii_name[II_NAMELEN]; /* Name of this intr. */ - int ii_flags; /* informational flags */ -} intr_info_t; - - -#define THD_CREATED 0x00000001 /* - * We've created a thread for this - * interrupt. - */ - -/* - * Bits for ii_flags: - */ -#define II_UNRESERVE 0 -#define II_RESERVE 1 /* Interrupt reserved. */ -#define II_INUSE 2 /* Interrupt connected */ -#define II_ERRORINT 4 /* INterrupt is an error condition */ -#define II_THREADED 8 /* Interrupt handler is threaded. */ - -/* - * Interrupt level wildcard - */ -#define INTRCONNECT_ANYBIT (-1) - -/* - * This structure holds information needed both to call and to maintain - * interrupts. The two are in separate arrays for the locality benefits. - * Since there's only one set of vectors per hub chip (but more than one - * CPU, the lock to change the vector tables must be here rather than in - * the PDA. - */ - -typedef struct intr_vecblk_s { - intr_vector_t vectors[N_INTPEND_BITS]; /* information needed to - call an intr routine. */ - intr_info_t info[N_INTPEND_BITS]; /* information needed only - to maintain interrupts. */ - spinlock_t vector_lock; /* Lock for this and the - masks in the PDA. */ - splfunc_t vector_spl; /* vector_lock req'd spl */ - int vector_state; /* Initialized to zero. - Set to INTR_INITED - by hubintr_init. - */ - int vector_count; /* Number of vectors - * reserved. - */ - int cpu_count[CPUS_PER_SUBNODE]; /* How many interrupts are - * connected to each CPU - */ - int ithreads_enabled; /* Are interrupt threads - * initialized on this node. - * and block? - */ -} intr_vecblk_t; - -/* Possible values for vector_state: */ -#define VECTOR_UNINITED 0 -#define VECTOR_INITED 1 -#define VECTOR_SET 2 - -#define hub_intrvect0 private.p_intmasks.dispatch0->vectors -#define hub_intrvect1 private.p_intmasks.dispatch1->vectors -#define hub_intrinfo0 private.p_intmasks.dispatch0->info -#define hub_intrinfo1 private.p_intmasks.dispatch1->info - -/* - * Macros to manipulate the interrupt register on the calling hub chip. - */ - -#define LOCAL_HUB_SEND_INTR(_level) LOCAL_HUB_S(PI_INT_PEND_MOD, \ - (0x100|(_level))) -#define REMOTE_HUB_PI_SEND_INTR(_hub, _sn, _level) \ - REMOTE_HUB_PI_S((_hub), _sn, PI_INT_PEND_MOD, (0x100|(_level))) - -#define REMOTE_CPU_SEND_INTR(_cpuid, _level) \ - REMOTE_HUB_PI_S(cpuid_to_nasid(_cpuid), \ - SUBNODE(cpuid_to_slice(_cpuid)), \ - PI_INT_PEND_MOD, (0x100|(_level))) - -/* - * When clearing the interrupt, make sure this clear does make it - * to the hub. Otherwise we could end up losing interrupts. - * We do an uncached load of the int_pend0 register to ensure this. - */ - -#define LOCAL_HUB_CLR_INTR(_level) \ - LOCAL_HUB_S(PI_INT_PEND_MOD, (_level)), \ - LOCAL_HUB_L(PI_INT_PEND0) -#define REMOTE_HUB_PI_CLR_INTR(_hub, _sn, _level) \ - REMOTE_HUB_PI_S((_hub), (_sn), PI_INT_PEND_MOD, (_level)), \ - REMOTE_HUB_PI_L((_hub), (_sn), PI_INT_PEND0) - -/* Special support for use by gfx driver only. Supports special gfx hub interrupt. */ -extern void install_gfxintr(cpuid_t cpu, ilvl_t swlevel, intr_func_t intr_func, void *intr_arg); - -void setrtvector(intr_func_t func); - -/* - * Interrupt blocking - */ -extern void intr_block_bit(cpuid_t cpu, int bit); -extern void intr_unblock_bit(cpuid_t cpu, int bit); - -#endif /* __ASSEMBLY__ */ - -/* - * Hard-coded interrupt levels: - */ - -/* - * L0 = SW1 - * L1 = SW2 - * L2 = INT_PEND0 - * L3 = INT_PEND1 - * L4 = RTC - * L5 = Profiling Timer - * L6 = Hub Errors - * L7 = Count/Compare (T5 counters) - */ - - -/* INT_PEND0 hard-coded bits. */ -#ifdef DEBUG_INTR_TSTAMP -/* hard coded interrupt level for interrupt latency test interrupt */ -#define CPU_INTRLAT_B 62 -#define CPU_INTRLAT_A 61 -#endif - -/* Hardcoded bits required by software. */ -#define MSC_MESG_INTR 9 -#define CPU_ACTION_B 8 -#define CPU_ACTION_A 7 - -/* These are determined by hardware: */ -#define CC_PEND_B 6 -#define CC_PEND_A 5 -#define UART_INTR 4 -#define PG_MIG_INTR 3 -#define GFX_INTR_B 2 -#define GFX_INTR_A 1 -#define RESERVED_INTR 0 - -/* INT_PEND1 hard-coded bits: */ -#define MSC_PANIC_INTR 63 -#define NI_ERROR_INTR 62 -#define MD_COR_ERR_INTR 61 -#define COR_ERR_INTR_B 60 -#define COR_ERR_INTR_A 59 -#define CLK_ERR_INTR 58 - -# define NACK_INT_B 57 -# define NACK_INT_A 56 -# define LB_ERROR 55 -# define XB_ERROR 54 - -#define BRIDGE_ERROR_INTR 53 /* Setup by PROM to catch Bridge Errors */ - -#define IP27_INTR_0 52 /* Reserved for PROM use */ -#define IP27_INTR_1 51 /* (do not use in Kernel) */ -#define IP27_INTR_2 50 -#define IP27_INTR_3 49 -#define IP27_INTR_4 48 -#define IP27_INTR_5 47 -#define IP27_INTR_6 46 -#define IP27_INTR_7 45 - -#define TLB_INTR_B 44 /* used for tlb flush random */ -#define TLB_INTR_A 43 - -#define LLP_PFAIL_INTR_B 42 /* see ml/SN/SN0/sysctlr.c */ -#define LLP_PFAIL_INTR_A 41 - -#define NI_BRDCAST_ERR_B 40 -#define NI_BRDCAST_ERR_A 39 - -# define IO_ERROR_INTR 38 /* set up by prom */ -# define DEBUG_INTR_B 37 /* used by symmon to stop all cpus */ -# define DEBUG_INTR_A 36 - -// These aren't strictly accurate or complete. See the -// Synergy Spec. for details. -#define SGI_UART_IRQ (65) -#define SGI_HUB_ERROR_IRQ (182) - -#endif /* _ASM_IA64_SN_SN1_INTR_H */ diff -Nru a/include/asm-ia64/sn/sn1/intr_public.h b/include/asm-ia64/sn/sn1/intr_public.h --- a/include/asm-ia64/sn/sn1/intr_public.h Tue Dec 3 10:07:34 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -/* $Id: intr_public.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_INTR_PUBLIC_H -#define _ASM_IA64_SN_SN1_INTR_PUBLIC_H - -/* REMEMBER: If you change these, the whole world needs to be recompiled. - * It would also require changing the hubspl.s code and SN0/intr.c - * Currently, the spl code has no support for multiple INTPEND1 masks. - */ - -#define N_INTPEND0_MASKS 1 -#define N_INTPEND1_MASKS 1 - -#define INTPEND0_MAXMASK (N_INTPEND0_MASKS - 1) -#define INTPEND1_MAXMASK (N_INTPEND1_MASKS - 1) - -#ifndef __ASSEMBLY__ -#include - -struct intr_vecblk_s; /* defined in asm/sn/intr.h */ - -/* - * The following are necessary to create the illusion of a CEL - * on the IP27 hub. We'll add more priority levels soon, but for - * now, any interrupt in a particular band effectively does an spl. - * These must be in the PDA since they're different for each processor. - * Users of this structure must hold the vector_lock in the appropriate vector - * block before modifying the mask arrays. There's only one vector block - * for each Hub so a lock in the PDA wouldn't be adequate. - */ -typedef struct hub_intmasks_s { - /* - * The masks are stored with the lowest-priority (most inclusive) - * in the lowest-numbered masks (i.e., 0, 1, 2...). - */ - /* INT_PEND0: */ - hubreg_t intpend0_masks[N_INTPEND0_MASKS]; - /* INT_PEND1: */ - hubreg_t intpend1_masks[N_INTPEND1_MASKS]; - /* INT_PEND0: */ - struct intr_vecblk_s *dispatch0; - /* INT_PEND1: */ - struct intr_vecblk_s *dispatch1; -} hub_intmasks_t; - -#endif /* __ASSEMBLY__ */ -#endif /* _ASM_IA64_SN_SN1_INTR_PUBLIC_H */ diff -Nru a/include/asm-ia64/sn/sn1/ip27config.h b/include/asm-ia64/sn/sn1/ip27config.h --- a/include/asm-ia64/sn/sn1/ip27config.h Fri Mar 8 18:11:39 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,657 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_IP27CONFIG_H -#define _ASM_IA64_SN_SN1_IP27CONFIG_H - - -/* - * Structure: ip27config_s - * Typedef: ip27config_t - * Purpose: Maps out the region of the boot prom used to define - * configuration information. - * Notes: Corresponds to ip27config structure found in start.s. - * Fields are ulong where possible to facilitate IP27 PROM fetches. - */ - -#define CONFIG_INFO_OFFSET 0x60 - -#define IP27CONFIG_ADDR (LBOOT_BASE + \ - CONFIG_INFO_OFFSET) -#define IP27CONFIG_ADDR_NODE(n) (NODE_RBOOT_BASE(n) + \ - CONFIG_INFO_OFFSET) - -/* Offset to the config_type field within local ip27config structure */ -#define CONFIG_FLAGS_ADDR (IP27CONFIG_ADDR + 72) -/* Offset to the config_type field in the ip27config structure on - * node with nasid n - */ -#define CONFIG_FLAGS_ADDR_NODE(n) (IP27CONFIG_ADDR_NODE(n) + 72) - -/* Meaning of each valid bit in the config flags - * None are currently defined - */ - -/* Meaning of each mach_type value - */ -#define SN1_MACH_TYPE 0 - -/* - * Since 800 ns works well with various HUB frequencies, (such as 360, - * 380, 390, and 400 MHZ), we now use 800ns rtc cycle time instead of - * 1 microsec. - */ -#define IP27_RTC_FREQ 1250 /* 800ns cycle time */ - -#ifndef __ASSEMBLY__ - -typedef struct ip27config_s { /* KEEP IN SYNC w/ start.s & below */ - uint time_const; /* Time constant */ - uint r10k_mode; /* R10k boot mode bits */ - - uint64_t magic; /* CONFIG_MAGIC */ - - uint64_t freq_cpu; /* Hz */ - uint64_t freq_hub; /* Hz */ - uint64_t freq_rtc; /* Hz */ - - uint ecc_enable; /* ECC enable flag */ - uint fprom_cyc; /* FPROM_CYC speed control */ - - uint mach_type; /* Inidicate IP27 (0) or Sn00 (1) */ - - uint check_sum_adj; /* Used after config hdr overlay */ - /* to make the checksum 0 again */ - uint flash_count; /* Value incr'd on each PROM flash */ - uint fprom_wr; /* FPROM_WR speed control */ - - uint pvers_vers; /* Prom version number */ - uint pvers_rev; /* Prom revision number */ - uint config_type; /* To support special configurations - * (none currently defined) - */ -} ip27config_t; - -typedef struct { - uint r10k_mode; /* R10k boot mode bits */ - uint freq_cpu; /* Hz */ - uint freq_hub; /* Hz */ - char fprom_cyc; /* FPROM_CYC speed control */ - char mach_type; /* IP35(0) is only type defined */ - char fprom_wr; /* FPROM_WR speed control */ -} config_modifiable_t; - -#define IP27CONFIG (*(ip27config_t *) IP27CONFIG_ADDR) -#define IP27CONFIG_NODE(n) (*(ip27config_t *) IP27CONFIG_ADDR_NODE(n)) -#define SN00 0 /* IP35 has no Speedo equivalent */ - -/* Get the config flags from local ip27config */ -#define CONFIG_FLAGS (*(uint *) (CONFIG_FLAGS_ADDR)) - -/* Get the config flags from ip27config on the node - * with nasid n - */ -#define CONFIG_FLAGS_NODE(n) (*(uint *) (CONFIG_FLAGS_ADDR_NODE(n))) - -/* Macro to check if the local ip27config indicates a config - * of 12 p 4io - */ -#define CONFIG_12P4I (0) /* IP35 has no 12p4i equivalent */ - -/* Macro to check if the ip27config on node with nasid n - * indicates a config of 12 p 4io - */ -#define CONFIG_12P4I_NODE(n) (0) - -#endif /* __ASSEMBLY__ */ - -#if __ASSEMBLY__ - .struct 0 /* KEEP IN SYNC WITH C structure */ - -ip27c_time_const: .word 0 -ip27c_r10k_mode: .word 0 - -ip27c_magic: .dword 0 - -ip27c_freq_cpu: .dword 0 -ip27c_freq_hub: .dword 0 -ip27c_freq_rtc: .dword 0 - -ip27c_ecc_enable: .word 1 -ip27c_fprom_cyc: .word 0 - -ip27c_mach_type: .word 0 -ip27c_check_sum_adj: .word 0 - -ip27c_flash_count: .word 0 -ip27c_fprom_wr: .word 0 - -ip27c_pvers_vers: .word 0 -ip27c_pvers_rev: .word 0 - -ip27c_config_type: .word 0 /* To recognize special configs */ -#endif /* __ASSEMBLY__ */ - -/* - * R10000 Configuration Cycle - These define the SYSAD values used - * during the reset cycle. - */ - -#define IP27C_R10000_KSEG0CA_SHFT 0 -#define IP27C_R10000_KSEG0CA_MASK (7 << IP27C_R10000_KSEG0CA_SHFT) -#define IP27C_R10000_KSEG0CA(_B) ((_B) << IP27C_R10000_KSEG0CA_SHFT) - -#define IP27C_R10000_DEVNUM_SHFT 3 -#define IP27C_R10000_DEVNUM_MASK (3 << IP27C_R10000_DEVNUM_SHFT) -#define IP27C_R10000_DEVNUM(_B) ((_B) << IP27C_R10000_DEVNUM_SHFT) - -#define IP27C_R10000_CRPT_SHFT 5 -#define IP27C_R10000_CRPT_MASK (1 << IP27C_R10000_CRPT_SHFT) -#define IP27C_R10000_CPRT(_B) ((_B)< - - -/* - * SGI SN1 Arch defined values - * - * An SN1 physical address is broken down as follows: - * - * +-----------------------------------------+ - * | | | | node offset | - * | unused | AS | node |-------------------| - * | | | | cn | clump offset | - * +-----------------------------------------+ - * 6 4 4 4 3 3 3 3 2 0 - * 3 4 3 0 9 3 2 0 9 0 - * - * bits 63-44 Unused - must be zero - * bits 43-40 Address space ID. Cached memory has a value of 0. - * Chipset & IO addresses have non-zero values. - * bits 39-33 Node number. Note that some configurations do NOT - * have a node zero. - * bits 32-0 Node offset. - * - * The node offset can be further broken down as: - * bits 32-30 Clump (bank) number. - * bits 29-0 Clump (bank) offset. - * - * A node consists of up to 8 clumps (banks) of memory. A clump may be empty, or may be - * populated with a single contiguous block of memory starting at clump - * offset 0. The size of the block is (2**n) * 64MB, where 0> SN1_NODE_SHIFT) & SN1_NODE_MASK) -#define SN1_NODE_CLUMP_NUMBER(addr) (((unsigned long)(addr) >>30) & 7) -#define SN1_NODE_OFFSET(addr) (((unsigned long)(addr)) & SN1_NODE_OFFSET_MASK) -#define SN1_KADDR(nasid, offset) (((unsigned long)(nasid)<> SN1_CHUNKSHIFT) - - -/* - * Given a kaddr, find the nid (compact nodeid) - */ -#ifdef CONFIG_IA64_SGI_SN_DEBUG -#define DISCONBUG(kaddr) panic("DISCONTIG BUG: line %d, %s. kaddr 0x%lx", \ - __LINE__, __FILE__, (long)(kaddr)) - -#define KVADDR_TO_NID(kaddr) ({long _ktn=(long)(kaddr); \ - kern_addr_valid(_ktn) ? \ - local_node_data->physical_node_map[SN1_NODE_NUMBER(_ktn)] :\ - (DISCONBUG(_ktn), 0UL);}) -#else -#define KVADDR_TO_NID(kaddr) (local_node_data->physical_node_map[SN1_NODE_NUMBER(kaddr)]) -#endif - - - -/* - * Given a kaddr, find the index into the clump_mem_map_base array of the page struct entry - * for the first page of the clump. - */ -#define PLAT_CLUMP_MEM_MAP_INDEX(kaddr) ({long _kmmi=(long)(kaddr); \ - KVADDR_TO_NID(_kmmi) * PLAT_CLUMPS_PER_NODE + \ - SN1_NODE_CLUMP_NUMBER(_kmmi);}) - - -/* - * Calculate a "goal" value to be passed to __alloc_bootmem_node for allocating structures on - * nodes so that they don't alias to the same line in the cache as the previous allocated structure. - * This macro takes an address of the end of previous allocation, rounds it to a page boundary & - * changes the node number. - */ -#define PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) __pa(SN1_KADDR(PLAT_PXM_TO_PHYS_NODE_NUMBER(nid_to_pxm_map[cnode]), \ - (SN1_NODE_OFFSET(kaddr) + PAGE_SIZE - 1) >> PAGE_SHIFT << PAGE_SHIFT)) - - - - -/* - * Convert a proximity domain number (from the ACPI tables) into a physical node number. - */ - -#define PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) (pxm) - -#endif /* _ASM_IA64_SN_MMZONE_SN1_H */ diff -Nru a/include/asm-ia64/sn/sn1/slotnum.h b/include/asm-ia64/sn/sn1/slotnum.h --- a/include/asm-ia64/sn/sn1/slotnum.h Fri Mar 8 18:11:40 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,87 +0,0 @@ -/* $Id$ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SN1_SLOTNUM_H -#define _ASM_IA64_SN_SN1_SLOTNUM_H - -#define SLOTNUM_MAXLENGTH 16 - -/* - * This file attempts to define a slot number space across all slots. - * - * Node slots - * Router slots - * Crosstalk slots - * - * Other slots are children of their parent crosstalk slot: - * PCI slots - * VME slots - * - * The PCI class has been added since the XBridge ASIC on SN-MIPS - * has built-in PCI bridges (2). On IBricks, widget E & F serve - * PCI busses, and on PBricks all widgets serve as PCI busses - * with the use of the super-bridge mode of the XBridge ASIC. - */ - -#define SLOTNUM_NODE_CLASS 0x00 /* Node */ -#define SLOTNUM_ROUTER_CLASS 0x10 /* Router */ -#define SLOTNUM_XTALK_CLASS 0x20 /* Xtalk */ -#define SLOTNUM_MIDPLANE_CLASS 0x30 /* Midplane */ -#define SLOTNUM_XBOW_CLASS 0x40 /* Xbow */ -#define SLOTNUM_KNODE_CLASS 0x50 /* Kego node */ -#define SLOTNUM_PCI_CLASS 0x60 /* PCI widgets on XBridge */ -#define SLOTNUM_INVALID_CLASS 0xf0 /* Invalid */ - -#define SLOTNUM_CLASS_MASK 0xf0 -#define SLOTNUM_SLOT_MASK 0x0f - -#define SLOTNUM_GETCLASS(_sn) ((_sn) & SLOTNUM_CLASS_MASK) -#define SLOTNUM_GETSLOT(_sn) ((_sn) & SLOTNUM_SLOT_MASK) - -/* This determines module to pnode mapping. */ -/* NODESLOTS_PER_MODULE has changed from 4 to 6 - * to support the 12P 4IO configuration. This change - * helps in minimum number of changes to code which - * depend on the number of node boards within a module. - */ -#define NODESLOTS_PER_MODULE 6 -#define NODESLOTS_PER_MODULE_SHFT 2 - -#define HIGHEST_I2C_VISIBLE_NODESLOT 4 -#define RTRSLOTS_PER_MODULE 2 - -#if __KERNEL__ -#include - -extern slotid_t xbwidget_to_xtslot(int crossbow, int widget); -extern slotid_t hub_slotbits_to_slot(slotid_t slotbits); -extern slotid_t hub_slot_to_crossbow(slotid_t hub_slot); -extern slotid_t router_slotbits_to_slot(slotid_t slotbits); -extern slotid_t get_node_slotid(nasid_t nasid); -extern slotid_t get_my_slotid(void); -extern slotid_t get_node_crossbow(nasid_t); -extern xwidgetnum_t hub_slot_to_widget(slotid_t); -extern void get_slotname(slotid_t, char *); -extern void get_my_slotname(char *); -extern slotid_t get_widget_slotnum(int xbow, int widget); -extern void get_widget_slotname(int, int, char *); -extern void router_slotbits_to_slotname(int, char *); -extern slotid_t meta_router_slotbits_to_slot(slotid_t) ; -extern slotid_t hub_slot_get(void); - -extern int node_can_talk_to_elsc(void); - -extern int slot_to_widget(int) ; -#define MAX_IO_SLOT_NUM 12 -#define MAX_NODE_SLOT_NUM 4 -#define MAX_ROUTER_SLOTNUM 2 - -#endif /* __KERNEL__ */ - -#endif /* _ASM_IA64_SN_SN1_SLOTNUM_H */ diff -Nru a/include/asm-ia64/sn/sn1/sn_private.h b/include/asm-ia64/sn/sn1/sn_private.h --- a/include/asm-ia64/sn/sn1/sn_private.h Tue Dec 3 10:07:34 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,292 +0,0 @@ -/* $Id: sn_private.h,v 1.1 2002/02/28 17:31:25 marcelo Exp $ - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. - */ -#ifndef _ASM_IA64_SN_SN1_SN_PRIVATE_H -#define _ASM_IA64_SN_SN1_SN_PRIVATE_H - -#include -#include -#include - -extern nasid_t master_nasid; - -/* promif.c */ -#ifdef LATER -extern cpuid_t cpu_node_probe(cpumask_t *cpumask, int *numnodes); -#endif -extern void he_arcs_set_vectors(void); -extern void mem_init(void); -#ifdef LATER -extern int cpu_enabled(cpuid_t); -#endif -extern void cpu_unenable(cpuid_t); -extern nasid_t get_lowest_nasid(void); -extern __psunsigned_t get_master_bridge_base(void); -extern void set_master_bridge_base(void); -extern int check_nasid_equiv(nasid_t, nasid_t); -extern nasid_t get_console_nasid(void); -extern char get_console_pcislot(void); -#ifdef LATER -extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int); -#endif - -extern int is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid); - -/* memsupport.c */ -extern void poison_state_alter_range(__psunsigned_t start, int len, int poison); -extern int memory_present(paddr_t); -extern int memory_read_accessible(paddr_t); -extern int memory_write_accessible(paddr_t); -extern void memory_set_access(paddr_t, int, int); -extern void show_dir_state(paddr_t, void (*)(char *, ...)); -extern void check_dir_state(nasid_t, int, void (*)(char *, ...)); -extern void set_dir_owner(paddr_t, int); -extern void set_dir_state(paddr_t, int); -extern void set_dir_state_POISONED(paddr_t); -extern void set_dir_state_UNOWNED(paddr_t); -extern int is_POISONED_dir_state(paddr_t); -extern int is_UNOWNED_dir_state(paddr_t); -extern void get_dir_ent(paddr_t paddr, int *state, - uint64_t *vec_ptr, hubreg_t *elo); - -/* intr.c */ -extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name); -extern void intr_unreserve_level(cpuid_t cpu, int level); -extern int intr_connect_level(cpuid_t cpu, int bit, ilvl_t mask_no, - intr_func_t intr_prefunc); -extern int intr_disconnect_level(cpuid_t cpu, int bit); -extern cpuid_t intr_heuristic(devfs_handle_t dev, device_desc_t dev_desc, - int req_bit,int intr_resflags,devfs_handle_t owner_dev, - char *intr_name,int *resp_bit); -extern void intr_block_bit(cpuid_t cpu, int bit); -extern void intr_unblock_bit(cpuid_t cpu, int bit); -extern void setrtvector(intr_func_t); -extern void install_cpuintr(cpuid_t cpu); -extern void install_dbgintr(cpuid_t cpu); -extern void install_tlbintr(cpuid_t cpu); -extern void hub_migrintr_init(cnodeid_t /*cnode*/); -extern int cause_intr_connect(int level, intr_func_t handler, uint intr_spl_mask); -extern int cause_intr_disconnect(int level); -extern void intr_reserve_hardwired(cnodeid_t); -extern void intr_clear_all(nasid_t); -extern void intr_dumpvec(cnodeid_t cnode, void (*pf)(char *, ...)); - -/* error_dump.c */ -extern char *hub_rrb_err_type[]; -extern char *hub_wrb_err_type[]; - -void nmi_dump(void); -void install_cpu_nmi_handler(int slice); - -/* klclock.c */ -extern void hub_rtc_init(cnodeid_t); - -/* bte.c */ -void bte_lateinit(void); -void bte_wait_for_xfer_completion(void *); - -/* klgraph.c */ -void klhwg_add_all_nodes(devfs_handle_t); -void klhwg_add_all_modules(devfs_handle_t); - -/* klidbg.c */ -void install_klidbg_functions(void); - -/* klnuma.c */ -extern void replicate_kernel_text(int numnodes); -extern __psunsigned_t get_freemem_start(cnodeid_t cnode); -extern void setup_replication_mask(int maxnodes); - -/* init.c */ -extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ -extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); -extern void init_platform_pda(cpuid_t cpu); -extern void per_cpu_init(void); -#ifdef LATER -extern cpumask_t boot_cpumask; -#endif -extern int is_fine_dirmode(void); -extern void update_node_information(cnodeid_t); - -#ifdef LATER -/* clksupport.c */ -extern void early_counter_intr(eframe_t *); -#endif - -/* hubio.c */ -extern void hubio_init(void); -extern void hub_merge_clean(nasid_t nasid); -extern void hub_set_piomode(nasid_t nasid, int conveyor); - -/* huberror.c */ -extern void hub_error_init(cnodeid_t); -extern void dump_error_spool(cpuid_t cpu, void (*pf)(char *, ...)); -extern void hubni_error_handler(char *, int); -extern int check_ni_errors(void); - -/* Used for debugger to signal upper software a breakpoint has taken place */ - -extern void *debugger_update; -extern __psunsigned_t debugger_stopped; - -/* - * IP27 piomap, created by hub_pio_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_piomap_s by generic xtalk routines. - */ -struct hub_piomap_s { - struct xtalk_piomap_s hpio_xtalk_info;/* standard crosstalk pio info */ - devfs_handle_t hpio_hub; /* which hub's mapping registers are set up */ - short hpio_holdcnt; /* count of current users of bigwin mapping */ - char hpio_bigwin_num;/* if big window map, which one */ - int hpio_flags; /* defined below */ -}; -/* hub_piomap flags */ -#define HUB_PIOMAP_IS_VALID 0x1 -#define HUB_PIOMAP_IS_BIGWINDOW 0x2 -#define HUB_PIOMAP_IS_FIXED 0x4 - -#define hub_piomap_xt_piomap(hp) (&hp->hpio_xtalk_info) -#define hub_piomap_hub_v(hp) (hp->hpio_hub) -#define hub_piomap_winnum(hp) (hp->hpio_bigwin_num) - -#if TBD - /* Ensure that hpio_xtalk_info is first */ - #assert (&(((struct hub_piomap_s *)0)->hpio_xtalk_info) == 0) -#endif - - -/* - * IP27 dmamap, created by hub_pio_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_dmamap_s by generic xtalk routines. - */ -struct hub_dmamap_s { - struct xtalk_dmamap_s hdma_xtalk_info;/* standard crosstalk dma info */ - devfs_handle_t hdma_hub; /* which hub we go through */ - int hdma_flags; /* defined below */ -}; -/* hub_dmamap flags */ -#define HUB_DMAMAP_IS_VALID 0x1 -#define HUB_DMAMAP_USED 0x2 -#define HUB_DMAMAP_IS_FIXED 0x4 - -#if TBD - /* Ensure that hdma_xtalk_info is first */ - #assert (&(((struct hub_dmamap_s *)0)->hdma_xtalk_info) == 0) -#endif - -/* - * IP27 interrupt handle, created by hub_intr_alloc. - * xtalk_info MUST BE FIRST, since this structure is cast to a - * xtalk_intr_s by generic xtalk routines. - */ -struct hub_intr_s { - struct xtalk_intr_s i_xtalk_info; /* standard crosstalk intr info */ - ilvl_t i_swlevel; /* software level for blocking intr */ - cpuid_t i_cpuid; /* which cpu */ - int i_bit; /* which bit */ - int i_flags; -}; -/* flag values */ -#define HUB_INTR_IS_ALLOCED 0x1 /* for debug: allocated */ -#define HUB_INTR_IS_CONNECTED 0x4 /* for debug: connected to a software driver */ - -#if TBD - /* Ensure that i_xtalk_info is first */ - #assert (&(((struct hub_intr_s *)0)->i_xtalk_info) == 0) -#endif - - -/* IP27 hub-specific information stored under INFO_LBL_HUB_INFO */ -/* TBD: IP27-dependent stuff currently in nodepda.h should be here */ -typedef struct hubinfo_s { - nodepda_t *h_nodepda; /* pointer to node's private data area */ - cnodeid_t h_cnodeid; /* compact nodeid */ - nasid_t h_nasid; /* nasid */ - - /* structures for PIO management */ - xwidgetnum_t h_widgetid; /* my widget # (as viewed from xbow) */ - struct hub_piomap_s h_small_window_piomap[HUB_WIDGET_ID_MAX+1]; - sv_t h_bwwait; /* wait for big window to free */ - spinlock_t h_bwlock; /* guard big window piomap's */ - spinlock_t h_crblock; /* gaurd CRB error handling */ - int h_num_big_window_fixed; /* count number of FIXED maps */ - struct hub_piomap_s h_big_window_piomap[HUB_NUM_BIG_WINDOW]; - hub_intr_t hub_ii_errintr; -} *hubinfo_t; - -#define hubinfo_get(vhdl, infoptr) ((void)hwgraph_info_get_LBL \ - (vhdl, INFO_LBL_NODE_INFO, (arbitrary_info_t *)infoptr)) - -#define hubinfo_set(vhdl, infoptr) (void)hwgraph_info_add_LBL \ - (vhdl, INFO_LBL_NODE_INFO, (arbitrary_info_t)infoptr) - -#define hubinfo_to_hubv(hinfo, hub_v) (hinfo->h_nodepda->node_vertex) - -/* - * Hub info PIO map access functions. - */ -#define hubinfo_bwin_piomap_get(hinfo, win) \ - (&hinfo->h_big_window_piomap[win]) -#define hubinfo_swin_piomap_get(hinfo, win) \ - (&hinfo->h_small_window_piomap[win]) - -/* IP27 cpu-specific information stored under INFO_LBL_CPU_INFO */ -/* TBD: IP27-dependent stuff currently in pda.h should be here */ -typedef struct cpuinfo_s { -#ifdef LATER - pda_t *ci_cpupda; /* pointer to CPU's private data area */ -#endif - cpuid_t ci_cpuid; /* CPU ID */ -} *cpuinfo_t; - -#define cpuinfo_get(vhdl, infoptr) ((void)hwgraph_info_get_LBL \ - (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t *)infoptr)) - -#define cpuinfo_set(vhdl, infoptr) (void)hwgraph_info_add_LBL \ - (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t)infoptr) - -/* Special initialization function for xswitch vertices created during startup. */ -extern void xswitch_vertex_init(devfs_handle_t xswitch); - -extern xtalk_provider_t hub_provider; - -/* du.c */ -int ducons_write(char *buf, int len); - -/* memerror.c */ - -extern void install_eccintr(cpuid_t cpu); -extern void memerror_get_stats(cnodeid_t cnode, - int *bank_stats, int *bank_stats_max); -extern void probe_md_errors(nasid_t); -/* sysctlr.c */ -extern void sysctlr_init(void); -extern void sysctlr_power_off(int sdonly); -extern void sysctlr_keepalive(void); - -#define valid_cpuid(_x) (((_x) >= 0) && ((_x) < maxcpus)) - -/* Useful definitions to get the memory dimm given a physical - * address. - */ -#define paddr_dimm(_pa) ((_pa & MD_BANK_MASK) >> MD_BANK_SHFT) -#define paddr_cnode(_pa) (NASID_TO_COMPACT_NODEID(NASID_GET(_pa))) -extern void membank_pathname_get(paddr_t,char *); - -/* To redirect the output into the error buffer */ -#define errbuf_print(_s) printf("#%s",_s) - -extern void crbx(nasid_t nasid, void (*pf)(char *, ...)); -void bootstrap(void); - -/* sndrv.c */ -extern int sndrv_attach(devfs_handle_t vertex); - -#endif /* _ASM_IA64_SN_SN1_SN_PRIVATE_H */ diff -Nru a/include/asm-ia64/sn/sn1/synergy.h b/include/asm-ia64/sn/sn1/synergy.h --- a/include/asm-ia64/sn/sn1/synergy.h Tue Dec 3 10:07:34 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,184 +0,0 @@ -#ifndef _ASM_IA64_SN_SN1_SYNERGY_H -#define _ASM_IA64_SN_SN1_SYNERGY_H - -#include -#include -#include -#include - - -/* - * Definitions for the synergy asic driver - * - * These are for SGI platforms only. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#define SYNERGY_L4_BYTES (64UL*1024*1024) -#define SYNERGY_L4_WAYS 8 -#define SYNERGY_L4_BYTES_PER_WAY (SYNERGY_L4_BYTES/SYNERGY_L4_WAYS) -#define SYNERGY_BLOCK_SIZE 512UL - - -#define SSPEC_BASE (0xe0000000000UL) -#define LB_REG_BASE (SSPEC_BASE + 0x0) - -#define VEC_MASK3A_ADDR (0x2a0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK3B_ADDR (0x2a8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK3A (0x2a0) -#define VEC_MASK3B (0x2a8) - -#define VEC_MASK2A_ADDR (0x2b0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK2B_ADDR (0x2b8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK2A (0x2b0) -#define VEC_MASK2B (0x2b8) - -#define VEC_MASK1A_ADDR (0x2c0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK1B_ADDR (0x2c8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK1A (0x2c0) -#define VEC_MASK1B (0x2c8) - -#define VEC_MASK0A_ADDR (0x2d0 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK0B_ADDR (0x2d8 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define VEC_MASK0A (0x2d0) -#define VEC_MASK0B (0x2d8) - -#define GBL_PERF_A_ADDR (0x330 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) -#define GBL_PERF_B_ADDR (0x338 + LB_REG_BASE + __IA64_UNCACHED_OFFSET) - -#define WRITE_LOCAL_SYNERGY_REG(addr, value) __synergy_out(addr, value) - -#define HSPEC_SYNERGY0_0 0x04000000 /* Synergy0 Registers */ -#define HSPEC_SYNERGY1_0 0x05000000 /* Synergy1 Registers */ -#define HS_SYNERGY_STRIDE (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0) -#define REMOTE_HSPEC(_n, _x) (HUBREG_CAST (RREG_BASE(_n) + (_x))) - -#define RREG_BASE(_n) (NODE_LREG_BASE(_n)) -#define NODE_LREG_BASE(_n) (NODE_HSPEC_BASE(_n) + 0x30000000) -#define NODE_HSPEC_BASE(_n) (HSPEC_BASE + NODE_OFFSET(_n)) -#ifndef HSPEC_BASE -#define HSPEC_BASE (SYN_UNCACHED_SPACE | HSPEC_BASE_SYN) -#endif -#define SYN_UNCACHED_SPACE 0xc000000000000000 -#define HSPEC_BASE_SYN 0x00000b0000000000 -#define NODE_OFFSET(_n) (UINT64_CAST (_n) << NODE_SIZE_BITS) -#define NODE_SIZE_BITS 33 - -#define SYN_TAG_DISABLE_WAY (SSPEC_BASE+0xae0) - - -#define RSYN_REG_OFFSET(fsb, reg) (((fsb) ? HSPEC_SYNERGY1_0 : HSPEC_SYNERGY0_0) | (reg)) - -#define REMOTE_SYNERGY_LOAD(nasid, fsb, reg) __remote_synergy_in(nasid, fsb, reg) -#define REMOTE_SYNERGY_STORE(nasid, fsb, reg, val) __remote_synergy_out(nasid, fsb, reg, val) - -static inline uint64_t -__remote_synergy_in(int nasid, int fsb, uint64_t reg) { - volatile uint64_t *addr; - - addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, reg)); - return (*addr); -} - -static inline void -__remote_synergy_out(int nasid, int fsb, uint64_t reg, uint64_t value) { - volatile uint64_t *addr; - - addr = (uint64_t *)(RREG_BASE(nasid) + RSYN_REG_OFFSET(fsb, (reg<<2))); - *(addr+0) = value >> 48; - *(addr+1) = value >> 32; - *(addr+2) = value >> 16; - *(addr+3) = value; - __ia64_mf_a(); -} - -/* XX this doesn't make a lot of sense. Which fsb? */ -static inline void -__synergy_out(unsigned long addr, unsigned long value) -{ - volatile unsigned long *adr = (unsigned long *) - (addr | __IA64_UNCACHED_OFFSET); - - *adr = value; - __ia64_mf_a(); -} - -#define READ_LOCAL_SYNERGY_REG(addr) __synergy_in(addr) - -/* XX this doesn't make a lot of sense. Which fsb? */ -static inline unsigned long -__synergy_in(unsigned long addr) -{ - unsigned long ret, *adr = (unsigned long *) - (addr | __IA64_UNCACHED_OFFSET); - - ret = *adr; - __ia64_mf_a(); - return ret; -} - -struct sn1_intr_action { - void (*handler)(int, void *, struct pt_regs *); - void *intr_arg; - unsigned long flags; - struct sn1_intr_action * next; -}; - -typedef struct synergy_da_s { - hub_intmasks_t s_intmasks; -}synergy_da_t; - -struct sn1_cnode_action_list { - spinlock_t action_list_lock; - struct sn1_intr_action *action_list; -}; - -/* - * ioctl cmds for node/hub/synergy/[01]/mon for synergy - * perf monitoring are defined in sndrv.h - */ - -/* multiplex the counters every 10 timer interrupts */ -#define SYNERGY_PERF_FREQ_DEFAULT 10 - -/* macros for synergy "mon" device ioctl handler */ -#define SYNERGY_PERF_INFO(_s, _f) (arbitrary_info_t)(((_s) << 16)|(_f)) -#define SYNERGY_PERF_INFO_CNODE(_x) (cnodeid_t)(((uint64_t)_x) >> 16) -#define SYNERGY_PERF_INFO_FSB(_x) (((uint64_t)_x) & 1) - -/* synergy perf control registers */ -#define PERF_CNTL0_A 0xab0UL /* control A on FSB0 */ -#define PERF_CNTL0_B 0xab8UL /* control B on FSB0 */ -#define PERF_CNTL1_A 0xac0UL /* control A on FSB1 */ -#define PERF_CNTL1_B 0xac8UL /* control B on FSB1 */ - -/* synergy perf counters */ -#define PERF_CNTR0_A 0xad0UL /* counter A on FSB0 */ -#define PERF_CNTR0_B 0xad8UL /* counter B on FSB0 */ -#define PERF_CNTR1_A 0xaf0UL /* counter A on FSB1 */ -#define PERF_CNTR1_B 0xaf8UL /* counter B on FSB1 */ - -/* Synergy perf data. Each nodepda keeps a list of these */ -struct synergy_perf_s { - uint64_t intervals; /* count of active intervals for this event */ - uint64_t total_intervals;/* snapshot of total intervals */ - uint64_t modesel; /* mode and sel bits, both A and B registers */ - struct synergy_perf_s *next; /* next in circular linked list */ - uint64_t counts[2]; /* [0] is synergy-A counter, [1] synergy-B counter */ -}; - -typedef struct synergy_perf_s synergy_perf_t; - -typedef struct synergy_info_s synergy_info_t; - -extern void synergy_perf_init(void); -extern void synergy_perf_update(int); -extern struct file_operations synergy_mon_fops; - -#endif /* _ASM_IA64_SN_SN1_SYNERGY_H */ diff -Nru a/include/asm-ia64/sn/sn2/addrs.h b/include/asm-ia64/sn/sn2/addrs.h --- a/include/asm-ia64/sn/sn2/addrs.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn2/addrs.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ADDRS_H @@ -57,7 +57,7 @@ #define LOCAL_MEM_SPACE 0xc000010000000000 /* Local Memory space */ #define GLOBAL_MMR_SPACE 0xc000000800000000 /* Global MMR space */ #define GLOBAL_PHYS_MMR_SPACE 0x0000000800000000 /* Global Physical MMR space */ -#define GET_SPACE 0xc000001000000000 /* GET space */ +#define GET_SPACE 0xe000001000000000 /* GET space */ #define AMO_SPACE 0xc000002000000000 /* AMO space */ #define CACHEABLE_MEM_SPACE 0xe000003000000000 /* Cacheable memory space */ #define UNCACHED 0xc000000000000000 /* UnCacheable memory space */ diff -Nru a/include/asm-ia64/sn/sn2/arch.h b/include/asm-ia64/sn/sn2/arch.h --- a/include/asm-ia64/sn/sn2/arch.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn2/arch.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_ARCH_H #define _ASM_IA64_SN_SN2_ARCH_H @@ -46,6 +46,7 @@ #define NASID_MASK_BYTES ((MAX_NASIDS + 7) / 8) +#define CNASID_MASK_BYTES (NASID_MASK_BYTES / 2) /* diff -Nru a/include/asm-ia64/sn/sn2/intr.h b/include/asm-ia64/sn/sn2/intr.h --- a/include/asm-ia64/sn/sn2/intr.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn2/intr.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_INTR_H #define _ASM_IA64_SN_SN2_INTR_H @@ -14,13 +14,17 @@ // These two IRQ's are used by partitioning. #define SGI_XPC_ACTIVATE (0x30) +#define SGI_II_ERROR (0x31) +#define SGI_XBOW_ERROR (0x32) +#define SGI_PCIBR_ERROR (0x33) #define SGI_XPC_NOTIFY (0xe7) -#define IA64_SN2_FIRST_DEVICE_VECTOR (0x31) +#define IA64_SN2_FIRST_DEVICE_VECTOR (0x34) #define IA64_SN2_LAST_DEVICE_VECTOR (0xe6) #define SN2_IRQ_RESERVED (0x1) #define SN2_IRQ_CONNECTED (0x2) +#define SN2_IRQ_SHARED (0x4) #define SN2_IRQ_PER_HUB (2048) diff -Nru a/include/asm-ia64/sn/sn2/io.h b/include/asm-ia64/sn/sn2/io.h --- a/include/asm-ia64/sn/sn2/io.h Thu Mar 27 07:51:35 2003 +++ b/include/asm-ia64/sn/sn2/io.h Fri May 16 04:18:18 2003 @@ -32,8 +32,8 @@ unsigned char ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -44,8 +44,8 @@ unsigned short ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -56,8 +56,8 @@ unsigned int ret; ret = *addr; - sn_dma_flush((unsigned long)addr); __sn_mf_a(); + sn_dma_flush((unsigned long)addr); return ret; } @@ -103,6 +103,7 @@ unsigned char val; val = *(volatile unsigned char *)addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -113,6 +114,7 @@ unsigned short val; val = *(volatile unsigned short *)addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -123,6 +125,7 @@ unsigned int val; val = *(volatile unsigned int *) addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } @@ -133,6 +136,7 @@ unsigned long val; val = *(volatile unsigned long *) addr; + __sn_mf_a(); sn_dma_flush((unsigned long)addr); return val; } diff -Nru a/include/asm-ia64/sn/sn2/mmzone_sn2.h b/include/asm-ia64/sn/sn2/mmzone_sn2.h --- a/include/asm-ia64/sn/sn2/mmzone_sn2.h Tue Feb 25 02:48:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,165 +0,0 @@ -#ifndef _ASM_IA64_SN_MMZONE_SN2_H -#define _ASM_IA64_SN_MMZONE_SN2_H - -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. - */ - -#include - - -/* - * SGI SN2 Arch defined values - * - * An SN2 physical address is broken down as follows: - * - * +-----------------------------------------+ - * | | | | node offset | - * | unused | node | AS |-------------------| - * | | | | cn | clump offset | - * +-----------------------------------------+ - * 6 4 4 3 3 3 3 3 3 0 - * 3 9 8 8 7 6 5 4 3 0 - * - * bits 63-49 Unused - must be zero - * bits 48-38 Node number. Note that some configurations do NOT - * have a node zero. - * bits 37-36 Address space ID. Cached memory has a value of 3 (!!!). - * Chipset & IO addresses have other values. - * (Yikes!! The hardware folks hate us...) - * bits 35-0 Node offset. - * - * The node offset can be further broken down as: - * bits 35-34 Clump (bank) number. - * bits 33-0 Clump (bank) offset. - * - * A node consists of up to 4 clumps (banks) of memory. A clump may be empty, or may be - * populated with a single contiguous block of memory starting at clump - * offset 0. The size of the block is (2**n) * 64MB, where 0> SN2_NODE_SHIFT) & SN2_NODE_MASK) -#define SN2_NODE_CLUMP_NUMBER(kaddr) (((unsigned long)(kaddr) >>34) & 3) -#define SN2_NODE_OFFSET(addr) (((unsigned long)(addr)) & SN2_NODE_OFFSET_MASK) -#define SN2_KADDR(nasid, offset) (((unsigned long)(nasid)<>2) | \ - (_p&SN2_NODE_OFFSET_MASK)) >>SN2_CHUNKSHIFT;}) - -/* - * Given a kaddr, find the nid (compact nodeid) - */ -#ifdef CONFIG_IA64_SGI_SN_DEBUG -#define DISCONBUG(kaddr) panic("DISCONTIG BUG: line %d, %s. kaddr 0x%lx", \ - __LINE__, __FILE__, (long)(kaddr)) - -#define KVADDR_TO_NID(kaddr) ({long _ktn=(long)(kaddr); \ - kern_addr_valid(_ktn) ? \ - local_node_data->physical_node_map[SN2_NODE_NUMBER(_ktn)] : \ - (DISCONBUG(_ktn), 0UL);}) -#else -#define KVADDR_TO_NID(kaddr) (local_node_data->physical_node_map[SN2_NODE_NUMBER(kaddr)]) -#endif - - - -/* - * Given a kaddr, find the index into the clump_mem_map_base array of the page struct entry - * for the first page of the clump. - */ -#define PLAT_CLUMP_MEM_MAP_INDEX(kaddr) ({long _kmmi=(long)(kaddr); \ - KVADDR_TO_NID(_kmmi) * PLAT_CLUMPS_PER_NODE + \ - SN2_NODE_CLUMP_NUMBER(_kmmi);}) - - - -/* - * Calculate a "goal" value to be passed to __alloc_bootmem_node for allocating structures on - * nodes so that they don't alias to the same line in the cache as the previous allocated structure. - * This macro takes an address of the end of previous allocation, rounds it to a page boundary & - * changes the node number. - */ -#define PLAT_BOOTMEM_ALLOC_GOAL(cnode,kaddr) __pa(SN2_KADDR(PLAT_PXM_TO_PHYS_NODE_NUMBER(nid_to_pxm_map[cnode]), \ - (SN2_NODE_OFFSET(kaddr) + PAGE_SIZE - 1) >> PAGE_SHIFT << PAGE_SHIFT)) - - - - -/* - * Convert a proximity domain number (from the ACPI tables) into a physical node number. - * Note: on SN2, the promity domain number is the same as bits [8:1] of the NASID. The following - * algorithm relies on: - * - bit 0 of the NASID for cpu nodes is always 0 - * - bits [10:9] of all NASIDs in a partition are always the same - * - hard_smp_processor_id return the SAPIC of the current cpu & - * bits 0..11 contain the NASID. - * - * All of this complexity is because MS architectually limited proximity domain numbers to - * 8 bits. - */ - -#define PLAT_PXM_TO_PHYS_NODE_NUMBER(pxm) (((pxm)<<1) | (hard_smp_processor_id() & 0x300)) - -#endif /* _ASM_IA64_SN_MMZONE_SN2_H */ diff -Nru a/include/asm-ia64/sn/sn2/shub.h b/include/asm-ia64/sn/sn2/shub.h --- a/include/asm-ia64/sn/sn2/shub.h Sat Mar 9 02:24:41 2002 +++ b/include/asm-ia64/sn/sn2/shub.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nru a/include/asm-ia64/sn/sn2/shub_md.h b/include/asm-ia64/sn/sn2/shub_md.h --- a/include/asm-ia64/sn/sn2/shub_md.h Tue Feb 18 10:12:35 2003 +++ b/include/asm-ia64/sn/sn2/shub_md.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001, 2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001, 2002-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nru a/include/asm-ia64/sn/sn2/shub_mmr.h b/include/asm-ia64/sn/sn2/shub_mmr.h --- a/include/asm-ia64/sn/sn2/shub_mmr.h Mon Feb 24 10:18:42 2003 +++ b/include/asm-ia64/sn/sn2/shub_mmr.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -25746,14 +25746,14 @@ /* Real-time Clock */ /* ==================================================================== */ -#define SH_RTC 0x00000001101c0000 -#define SH_RTC_MASK 0x007fffffffffffff +#define SH_RTC 0x00000001101c0000UL +#define SH_RTC_MASK 0x007fffffffffffffUL #define SH_RTC_INIT 0x0000000000000000 /* SH_RTC_REAL_TIME_CLOCK */ /* Description: Real-time Clock */ #define SH_RTC_REAL_TIME_CLOCK_SHFT 0 -#define SH_RTC_REAL_TIME_CLOCK_MASK 0x007fffffffffffff +#define SH_RTC_REAL_TIME_CLOCK_MASK 0x007fffffffffffffUL /* ==================================================================== */ /* Register "SH_SCRATCH0" */ diff -Nru a/include/asm-ia64/sn/sn2/shub_mmr_t.h b/include/asm-ia64/sn/sn2/shub_mmr_t.h --- a/include/asm-ia64/sn/sn2/shub_mmr_t.h Sat Mar 9 02:24:41 2002 +++ b/include/asm-ia64/sn/sn2/shub_mmr_t.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2001-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ diff -Nru a/include/asm-ia64/sn/sn2/shubio.h b/include/asm-ia64/sn/sn2/shubio.h --- a/include/asm-ia64/sn/sn2/shubio.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn2/shubio.h Mon May 19 05:42:20 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SHUBIO_H @@ -3035,31 +3035,31 @@ /* Scratch registers (all bits available) */ #define IIO_SCRATCH_REG0 IIO_ISCR0 #define IIO_SCRATCH_REG1 IIO_ISCR1 -#define IIO_SCRATCH_MASK 0xffffffffffffffff +#define IIO_SCRATCH_MASK 0xffffffffffffffffUL -#define IIO_SCRATCH_BIT0_0 0x0000000000000001 -#define IIO_SCRATCH_BIT0_1 0x0000000000000002 -#define IIO_SCRATCH_BIT0_2 0x0000000000000004 -#define IIO_SCRATCH_BIT0_3 0x0000000000000008 -#define IIO_SCRATCH_BIT0_4 0x0000000000000010 -#define IIO_SCRATCH_BIT0_5 0x0000000000000020 -#define IIO_SCRATCH_BIT0_6 0x0000000000000040 -#define IIO_SCRATCH_BIT0_7 0x0000000000000080 -#define IIO_SCRATCH_BIT0_8 0x0000000000000100 -#define IIO_SCRATCH_BIT0_9 0x0000000000000200 -#define IIO_SCRATCH_BIT0_A 0x0000000000000400 +#define IIO_SCRATCH_BIT0_0 0x0000000000000001UL +#define IIO_SCRATCH_BIT0_1 0x0000000000000002UL +#define IIO_SCRATCH_BIT0_2 0x0000000000000004UL +#define IIO_SCRATCH_BIT0_3 0x0000000000000008UL +#define IIO_SCRATCH_BIT0_4 0x0000000000000010UL +#define IIO_SCRATCH_BIT0_5 0x0000000000000020UL +#define IIO_SCRATCH_BIT0_6 0x0000000000000040UL +#define IIO_SCRATCH_BIT0_7 0x0000000000000080UL +#define IIO_SCRATCH_BIT0_8 0x0000000000000100UL +#define IIO_SCRATCH_BIT0_9 0x0000000000000200UL +#define IIO_SCRATCH_BIT0_A 0x0000000000000400UL -#define IIO_SCRATCH_BIT1_0 0x0000000000000001 -#define IIO_SCRATCH_BIT1_1 0x0000000000000002 +#define IIO_SCRATCH_BIT1_0 0x0000000000000001UL +#define IIO_SCRATCH_BIT1_1 0x0000000000000002UL /* IO Translation Table Entries */ #define IIO_NUM_ITTES 7 /* ITTEs numbered 0..6 */ /* Hw manuals number them 1..7! */ /* * IIO_IMEM Register fields. */ -#define IIO_IMEM_W0ESD 0x1 /* Widget 0 shut down due to error */ -#define IIO_IMEM_B0ESD (1 << 4) /* BTE 0 shut down due to error */ -#define IIO_IMEM_B1ESD (1 << 8) /* BTE 1 Shut down due to error */ +#define IIO_IMEM_W0ESD 0x1UL /* Widget 0 shut down due to error */ +#define IIO_IMEM_B0ESD (1UL << 4) /* BTE 0 shut down due to error */ +#define IIO_IMEM_B1ESD (1UL << 8) /* BTE 1 Shut down due to error */ /* * As a permanent workaround for a bug in the PI side of the shub, we've @@ -3191,23 +3191,23 @@ /* * IO BTE Length/Status (IIO_IBLS) register bit field definitions */ -#define IBLS_BUSY (0x1 << 20) +#define IBLS_BUSY (0x1UL << 20) #define IBLS_ERROR_SHFT 16 -#define IBLS_ERROR (0x1 << IBLS_ERROR_SHFT) +#define IBLS_ERROR (0x1UL << IBLS_ERROR_SHFT) #define IBLS_LENGTH_MASK 0xffff /* * IO BTE Control/Terminate register (IBCT) register bit field definitions */ -#define IBCT_POISON (0x1 << 8) -#define IBCT_NOTIFY (0x1 << 4) -#define IBCT_ZFIL_MODE (0x1 << 0) +#define IBCT_POISON (0x1UL << 8) +#define IBCT_NOTIFY (0x1UL << 4) +#define IBCT_ZFIL_MODE (0x1UL << 0) /* * IIO Incoming Error Packet Header (IIO_IIEPH1/IIO_IIEPH2) */ -#define IIEPH1_VALID (1 << 44) -#define IIEPH1_OVERRUN (1 << 40) +#define IIEPH1_VALID (1UL << 44) +#define IIEPH1_OVERRUN (1UL << 40) #define IIEPH1_ERR_TYPE_SHFT 32 #define IIEPH1_ERR_TYPE_MASK 0xf #define IIEPH1_SOURCE_SHFT 20 @@ -3217,7 +3217,7 @@ #define IIEPH1_CMD_SHFT 0 #define IIEPH1_CMD_MASK 7 -#define IIEPH2_TAIL (1 << 40) +#define IIEPH2_TAIL (1UL << 40) #define IIEPH2_ADDRESS_SHFT 0 #define IIEPH2_ADDRESS_MASK 38 @@ -3229,21 +3229,21 @@ /* * IO Error Clear register bit field definitions */ -#define IECLR_PI1_FWD_INT (1 << 31) /* clear PI1_FORWARD_INT in iidsr */ -#define IECLR_PI0_FWD_INT (1 << 30) /* clear PI0_FORWARD_INT in iidsr */ -#define IECLR_SPUR_RD_HDR (1 << 29) /* clear valid bit in ixss reg */ -#define IECLR_BTE1 (1 << 18) /* clear bte error 1 */ -#define IECLR_BTE0 (1 << 17) /* clear bte error 0 */ -#define IECLR_CRAZY (1 << 16) /* clear crazy bit in wstat reg */ -#define IECLR_PRB_F (1 << 15) /* clear err bit in PRB_F reg */ -#define IECLR_PRB_E (1 << 14) /* clear err bit in PRB_E reg */ -#define IECLR_PRB_D (1 << 13) /* clear err bit in PRB_D reg */ -#define IECLR_PRB_C (1 << 12) /* clear err bit in PRB_C reg */ -#define IECLR_PRB_B (1 << 11) /* clear err bit in PRB_B reg */ -#define IECLR_PRB_A (1 << 10) /* clear err bit in PRB_A reg */ -#define IECLR_PRB_9 (1 << 9) /* clear err bit in PRB_9 reg */ -#define IECLR_PRB_8 (1 << 8) /* clear err bit in PRB_8 reg */ -#define IECLR_PRB_0 (1 << 0) /* clear err bit in PRB_0 reg */ +#define IECLR_PI1_FWD_INT (1UL << 31) /* clear PI1_FORWARD_INT in iidsr */ +#define IECLR_PI0_FWD_INT (1UL << 30) /* clear PI0_FORWARD_INT in iidsr */ +#define IECLR_SPUR_RD_HDR (1UL << 29) /* clear valid bit in ixss reg */ +#define IECLR_BTE1 (1UL << 18) /* clear bte error 1 */ +#define IECLR_BTE0 (1UL << 17) /* clear bte error 0 */ +#define IECLR_CRAZY (1UL << 16) /* clear crazy bit in wstat reg */ +#define IECLR_PRB_F (1UL << 15) /* clear err bit in PRB_F reg */ +#define IECLR_PRB_E (1UL << 14) /* clear err bit in PRB_E reg */ +#define IECLR_PRB_D (1UL << 13) /* clear err bit in PRB_D reg */ +#define IECLR_PRB_C (1UL << 12) /* clear err bit in PRB_C reg */ +#define IECLR_PRB_B (1UL << 11) /* clear err bit in PRB_B reg */ +#define IECLR_PRB_A (1UL << 10) /* clear err bit in PRB_A reg */ +#define IECLR_PRB_9 (1UL << 9) /* clear err bit in PRB_9 reg */ +#define IECLR_PRB_8 (1UL << 8) /* clear err bit in PRB_8 reg */ +#define IECLR_PRB_0 (1UL << 0) /* clear err bit in PRB_0 reg */ /* * IIO CRB control register Fields: IIO_ICCR @@ -3495,7 +3495,7 @@ typedef struct hub_piomap_s *hub_piomap_t; extern hub_piomap_t -hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ +hub_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -3513,7 +3513,7 @@ hub_piomap_done(hub_piomap_t hub_piomap); extern caddr_t -hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ +hub_piotrans_addr( vertex_hdl_t dev, /* translate to this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -3523,7 +3523,7 @@ typedef struct hub_dmamap_s *hub_dmamap_t; extern hub_dmamap_t -hub_dmamap_alloc( devfs_handle_t dev, /* set up mappings for dev */ +hub_dmamap_alloc( vertex_hdl_t dev, /* set up mappings for dev */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -3545,14 +3545,14 @@ hub_dmamap_done( hub_dmamap_t dmamap); /* done w/ mapping resources */ extern iopaddr_t -hub_dmatrans_addr( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_addr( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); /* defined in dma.h */ extern alenlist_t -hub_dmatrans_list( devfs_handle_t dev, /* translate for this device */ +hub_dmatrans_list( vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system addr/length list */ unsigned flags); /* defined in dma.h */ @@ -3561,12 +3561,12 @@ hub_dmamap_drain( hub_dmamap_t map); extern void -hub_dmaaddr_drain( devfs_handle_t vhdl, +hub_dmaaddr_drain( vertex_hdl_t vhdl, paddr_t addr, size_t bytes); extern void -hub_dmalist_drain( devfs_handle_t vhdl, +hub_dmalist_drain( vertex_hdl_t vhdl, alenlist_t list); @@ -3574,14 +3574,14 @@ typedef struct hub_intr_s *hub_intr_t; extern hub_intr_t -hub_intr_alloc( devfs_handle_t dev, /* which device */ +hub_intr_alloc( vertex_hdl_t dev, /* which device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ + vertex_hdl_t owner_dev); /* owner of this interrupt */ extern hub_intr_t -hub_intr_alloc_nothd(devfs_handle_t dev, /* which device */ +hub_intr_alloc_nothd(vertex_hdl_t dev, /* which device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this interrupt */ + vertex_hdl_t owner_dev); /* owner of this interrupt */ extern void hub_intr_free(hub_intr_t intr_hdl); @@ -3596,16 +3596,14 @@ extern void hub_intr_disconnect(hub_intr_t intr_hdl); -extern devfs_handle_t -hub_intr_cpu_get(hub_intr_t intr_hdl); /* CONFIGURATION MANAGEMENT */ extern void -hub_provider_startup(devfs_handle_t hub); +hub_provider_startup(vertex_hdl_t hub); extern void -hub_provider_shutdown(devfs_handle_t hub); +hub_provider_shutdown(vertex_hdl_t hub); #define HUB_PIO_CONVEYOR 0x1 /* PIO in conveyor belt mode */ #define HUB_PIO_FIRE_N_FORGET 0x2 /* PIO in fire-and-forget mode */ @@ -3619,38 +3617,17 @@ typedef int hub_widget_flags_t; -/* Set the PIO mode for a widget. These two functions perform the - * same operation, but hub_device_flags_set() takes a hardware graph - * vertex while hub_widget_flags_set() takes a nasid and widget - * number. In most cases, hub_device_flags_set() should be used. - */ +/* Set the PIO mode for a widget. */ extern int hub_widget_flags_set(nasid_t nasid, xwidgetnum_t widget_num, hub_widget_flags_t flags); -/* Depending on the flags set take the appropriate actions */ -extern int hub_device_flags_set(devfs_handle_t widget_dev, - hub_widget_flags_t flags); - - /* Error Handling. */ -extern int hub_ioerror_handler(devfs_handle_t, int, int, struct io_error_s *); +extern int hub_ioerror_handler(vertex_hdl_t, int, int, struct io_error_s *); extern int kl_ioerror_handler(cnodeid_t, cnodeid_t, cpuid_t, int, paddr_t, caddr_t, ioerror_mode_t); -extern void hub_widget_reset(devfs_handle_t, xwidgetnum_t); -extern int hub_error_devenable(devfs_handle_t, int, int); -extern void hub_widgetdev_enable(devfs_handle_t, int); -extern void hub_widgetdev_shutdown(devfs_handle_t, int); -extern int hub_dma_enabled(devfs_handle_t); - -/* hubdev */ -extern void hubdev_init(void); -extern void hubdev_register(int (*attach_method)(devfs_handle_t)); -extern int hubdev_unregister(int (*attach_method)(devfs_handle_t)); -extern int hubdev_docallouts(devfs_handle_t hub); - -extern caddr_t hubdev_prombase_get(devfs_handle_t hub); -extern cnodeid_t hubdev_cnodeid_get(devfs_handle_t hub); +extern int hub_error_devenable(vertex_hdl_t, int, int); +extern int hub_dma_enabled(vertex_hdl_t); #endif /* __ASSEMBLY__ */ #endif /* _KERNEL */ diff -Nru a/include/asm-ia64/sn/sn2/slotnum.h b/include/asm-ia64/sn/sn2/slotnum.h --- a/include/asm-ia64/sn/sn2/slotnum.h Sat Mar 9 02:24:41 2002 +++ b/include/asm-ia64/sn/sn2/slotnum.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1992 - 1997,2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 1992-1997,2001-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SLOTNUM_H diff -Nru a/include/asm-ia64/sn/sn2/sn_private.h b/include/asm-ia64/sn/sn2/sn_private.h --- a/include/asm-ia64/sn/sn2/sn_private.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn2/sn_private.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN2_SN_PRIVATE_H #define _ASM_IA64_SN_SN2_SN_PRIVATE_H @@ -49,13 +49,13 @@ #endif /* intr.c */ -extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name); +extern int intr_reserve_level(cpuid_t cpu, int level, int err, vertex_hdl_t owner_dev, char *name); extern void intr_unreserve_level(cpuid_t cpu, int level); extern int intr_connect_level(cpuid_t cpu, int bit, ilvl_t mask_no, intr_func_t intr_prefunc); extern int intr_disconnect_level(cpuid_t cpu, int bit); -extern cpuid_t intr_heuristic(devfs_handle_t dev, device_desc_t dev_desc, - int req_bit,int intr_resflags,devfs_handle_t owner_dev, +extern cpuid_t intr_heuristic(vertex_hdl_t dev, device_desc_t dev_desc, + int req_bit,int intr_resflags,vertex_hdl_t owner_dev, char *intr_name,int *resp_bit); extern void intr_block_bit(cpuid_t cpu, int bit); extern void intr_unblock_bit(cpuid_t cpu, int bit); @@ -83,8 +83,8 @@ void bte_wait_for_xfer_completion(void *); /* klgraph.c */ -void klhwg_add_all_nodes(devfs_handle_t); -void klhwg_add_all_modules(devfs_handle_t); +void klhwg_add_all_nodes(vertex_hdl_t); +void klhwg_add_all_modules(vertex_hdl_t); /* klidbg.c */ void install_klidbg_functions(void); @@ -97,7 +97,6 @@ /* init.c */ extern cnodeid_t get_compact_nodeid(void); /* get compact node id */ extern void init_platform_nodepda(nodepda_t *npda, cnodeid_t node); -extern void init_platform_pda(cpuid_t cpu); extern void per_cpu_init(void); extern int is_fine_dirmode(void); extern void update_node_information(cnodeid_t); @@ -125,7 +124,7 @@ */ struct hub_piomap_s { struct xtalk_piomap_s hpio_xtalk_info;/* standard crosstalk pio info */ - devfs_handle_t hpio_hub; /* which shub's mapping registers are set up */ + vertex_hdl_t hpio_hub; /* which shub's mapping registers are set up */ short hpio_holdcnt; /* count of current users of bigwin mapping */ char hpio_bigwin_num;/* if big window map, which one */ int hpio_flags; /* defined below */ @@ -146,7 +145,7 @@ */ struct hub_dmamap_s { struct xtalk_dmamap_s hdma_xtalk_info;/* standard crosstalk dma info */ - devfs_handle_t hdma_hub; /* which shub we go through */ + vertex_hdl_t hdma_hub; /* which shub we go through */ int hdma_flags; /* defined below */ }; /* shub_dmamap flags */ @@ -214,7 +213,7 @@ (vhdl, INFO_LBL_CPU_INFO, (arbitrary_info_t)infoptr) /* Special initialization function for xswitch vertices created during startup. */ -extern void xswitch_vertex_init(devfs_handle_t xswitch); +extern void xswitch_vertex_init(vertex_hdl_t xswitch); extern xtalk_provider_t hub_provider; @@ -248,6 +247,6 @@ void bootstrap(void); /* sndrv.c */ -extern int sndrv_attach(devfs_handle_t vertex); +extern int sndrv_attach(vertex_hdl_t vertex); #endif /* _ASM_IA64_SN_SN2_SN_PRIVATE_H */ diff -Nru a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h --- a/include/asm-ia64/sn/sn_cpuid.h Tue Feb 25 02:48:12 2003 +++ b/include/asm-ia64/sn/sn_cpuid.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -18,6 +18,7 @@ #include #include #include +#include /* @@ -51,11 +52,6 @@ * * LID - processor defined register (see PRM V2). * - * On SN1 - * 31:24 - id Contains the NASID - * 23:16 - eid Contains 0-3 to identify the cpu on the node - * bit 17 - synergy number - * bit 16 - FSB slot number * On SN2 * 31:28 - id Contains 0-3 to identify the cpu on the node * 27:16 - eid Contains the NASID @@ -64,34 +60,30 @@ * * The following assumes the following mappings for LID register values: * - * The macros convert between cpu physical ids & slice/fsb/synergy/nasid/cnodeid. + * The macros convert between cpu physical ids & slice/nasid/cnodeid. * These terms are described below: * * + * Brick * ----- ----- ----- ----- CPU - * | 0 | | 1 | | 2 | | 3 | SLICE + * | 0 | | 1 | | 0 | | 1 | SLICE * ----- ----- ----- ----- * | | | | * | | | | - * 0 | | 1 0 | | 1 FSB SLOT + * 0 | | 2 0 | | 2 FSB SLOT * ------- ------- * | | * | | - * ------- ------- - * | | | | - * | 0 | | 1 | SYNERGY (SN1 only) - * | | | | - * ------- ------- * | | - * | | - * ------------------------------- - * | | - * | BEDROCK / SHUB | NASID (0..MAX_NASIDS) - * | | CNODEID (0..num_compact_nodes-1) - * | | - * | | - * ------------------------------- - * | + * ------------ ------------- + * | | | | + * | SHUB | | SHUB | NASID (0..MAX_NASIDS) + * | |----- | | CNODEID (0..num_compact_nodes-1) + * | | | | + * | | | | + * ------------ ------------- + * | | + * * */ @@ -100,25 +92,15 @@ #define cpu_physical_id(cpuid) ((ia64_get_lid() >> 16) & 0xffff) #endif -#ifdef CONFIG_IA64_SGI_SN1 /* * macros for some of these exist in sn/addrs.h & sn/arch.h, etc. However, * trying #include these files here causes circular dependencies. */ -#define cpu_physical_id_to_nasid(cpi) ((cpi) >> 8) -#define cpu_physical_id_to_synergy(cpi) (((cpi) >> 1) & 1) -#define cpu_physical_id_to_fsb_slot(cpi) ((cpi) & 1) -#define cpu_physical_id_to_slice(cpi) ((cpi) & 3) -#define get_nasid() ((ia64_get_lid() >> 24)) -#define get_slice() ((ia64_get_lid() >> 16) & 3) -#define get_node_number(addr) (((unsigned long)(addr)>>33) & 0x7f) -#else #define cpu_physical_id_to_nasid(cpi) ((cpi) &0xfff) #define cpu_physical_id_to_slice(cpi) ((cpi>>12) & 3) #define get_nasid() ((ia64_get_lid() >> 16) & 0xfff) #define get_slice() ((ia64_get_lid() >> 28) & 0xf) #define get_node_number(addr) (((unsigned long)(addr)>>38) & 0x7ff) -#endif /* * NOTE: id & eid refer to Intel's definitions of the LID register @@ -129,11 +111,7 @@ #define nasid_slice_to_cpuid(nasid,slice) (cpu_logical_id(nasid_slice_to_cpu_physical_id((nasid),(slice)))) -#ifdef CONFIG_IA64_SGI_SN1 -#define nasid_slice_to_cpu_physical_id(nasid, slice) (((nasid)<<8) | (slice)) -#else #define nasid_slice_to_cpu_physical_id(nasid, slice) (((slice)<<12) | (nasid)) -#endif /* * The following table/struct is used for managing PTC coherency domains. @@ -145,26 +123,9 @@ } sn_sapicid_info_t; extern sn_sapicid_info_t sn_sapicid_info[]; /* indexed by cpuid */ +extern short physical_node_map[]; /* indexed by nasid to get cnode */ - -#ifdef CONFIG_IA64_SGI_SN1 -/* - * cpuid_to_fsb_slot - convert a cpuid to the fsb slot number that it is in. - * (there are 2 cpus per FSB. This function returns 0 or 1) - */ -#define cpuid_to_fsb_slot(cpuid) (cpu_physical_id_to_fsb_slot(cpu_physical_id(cpuid))) - - -/* - * cpuid_to_synergy - convert a cpuid to the synergy that it resides on - * (there are 2 synergies per node. Function returns 0 or 1 to - * specify which synergy the cpu is on) - */ -#define cpuid_to_synergy(cpuid) (cpu_physical_id_to_synergy(cpu_physical_id(cpuid))) - -#endif - /* * cpuid_to_slice - convert a cpuid to the slice that it resides on * There are 4 cpus per node. This function returns 0 .. 3) @@ -181,7 +142,7 @@ /* * cpuid_to_cnodeid - convert a cpuid to the cnode that it resides on */ -#define cpuid_to_cnodeid(cpuid) (local_node_data->physical_node_map[cpuid_to_nasid(cpuid)]) +#define cpuid_to_cnodeid(cpuid) (physical_node_map[cpuid_to_nasid(cpuid)]) /* @@ -190,13 +151,13 @@ * Just extract the NASID from the pointer. * */ -#define cnodeid_to_nasid(cnodeid) (get_node_number(local_node_data->pg_data_ptrs[cnodeid])) +#define cnodeid_to_nasid(cnodeid) pda->cnodeid_to_nasid_table[cnodeid] /* * nasid_to_cnodeid - convert a NASID to a cnodeid */ -#define nasid_to_cnodeid(nasid) (nasid) /* (local_node_data->physical_node_map[nasid]) */ +#define nasid_to_cnodeid(nasid) (physical_node_map[nasid]) /* @@ -214,22 +175,7 @@ #define cpuid_to_subnode(cpuid) ((cpuid_to_slice(cpuid)<2) ? 0 : 1) -/* - * cpuid_to_localslice - convert a cpuid to a local slice - * slice 0 & 2 are local slice 0 - * slice 1 & 3 are local slice 1 - */ -#define cpuid_to_localslice(cpuid) (cpuid_to_slice(cpuid) & 1) - - #define smp_physical_node_id() (cpuid_to_nasid(smp_processor_id())) - - -/* - * cnodeid_to_cpuid - convert a cnode to a cpuid of a cpu on the node. - * returns -1 if no cpus exist on the node - */ -extern int cnodeid_to_cpuid(int cnode); #endif /* _ASM_IA64_SN_SN_CPUID_H */ diff -Nru a/include/asm-ia64/sn/sn_fru.h b/include/asm-ia64/sn/sn_fru.h --- a/include/asm-ia64/sn/sn_fru.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/sn_fru.h Fri May 16 04:18:17 2003 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 1999-2001 Silicon Graphics, Inc. - * All rights reserved. + * Copyright (C) 1992-1997,1999-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_FRU_H #define _ASM_IA64_SN_SN_FRU_H diff -Nru a/include/asm-ia64/sn/sn_pio_sync.h b/include/asm-ia64/sn/sn_pio_sync.h --- a/include/asm-ia64/sn/sn_pio_sync.h Sat Mar 9 02:24:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -/* - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved. - */ - - -#ifndef _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H -#define _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H - -#include -#ifdef CONFIG_IA64_SGI_SN2 -#include -#include -#include -#include - -/* - * This macro flushes all outstanding PIOs performed by this cpu to the - * intended destination SHUB. This in essence ensures that all PIO's - * issues by this cpu has landed at it's destination. - * - * This macro expects the caller: - * 1. The thread is locked. - * 2. All prior PIO operations has been fenced with __ia64_mf_a(). - * - * The expectation is that get_slice() will return either 0 or 2. - * When we have multi-core cpu's, the expectation is get_slice() will - * return either 0,1 or 2,3. - */ - -#define SN_PIO_WRITE_SYNC \ - { \ - volatile unsigned long sn_pio_writes_done; \ - do { \ - sn_pio_writes_done = (volatile unsigned long) (SH_PIO_WRITE_STATUS_0_WRITES_OK_MASK & HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(get_nasid(), (get_slice() < 2) ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ))); \ - } while (!sn_pio_writes_done); \ - __ia64_mf_a(); \ - } -#else - -/* - * For all ARCHITECTURE type, this is a NOOP. - */ - -#define SN_PIO_WRITE_SYNC - -#endif - -#endif /* _ASM_IA64_SN_SN_PIO_WRITE_SYNC_H */ diff -Nru a/include/asm-ia64/sn/sn_private.h b/include/asm-ia64/sn/sn_private.h --- a/include/asm-ia64/sn/sn_private.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/sn_private.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SN_PRIVATE_H #define _ASM_IA64_SN_SN_PRIVATE_H @@ -14,10 +14,6 @@ #include #include -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) #include -#endif #endif /* _ASM_IA64_SN_SN_PRIVATE_H */ diff -Nru a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h --- a/include/asm-ia64/sn/sn_sal.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sn_sal.h Fri May 16 04:18:19 2003 @@ -8,7 +8,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (c) 2000-2003 Silicon Graphics, Inc. All rights reserved. */ @@ -36,6 +36,8 @@ #define SN_SAL_CONSOLE_POLL 0x02000026 #define SN_SAL_CONSOLE_INTR 0x02000027 #define SN_SAL_CONSOLE_PUTB 0x02000028 +#define SN_SAL_CONSOLE_XMIT_CHARS 0x0200002a +#define SN_SAL_CONSOLE_READC 0x0200002b #define SN_SAL_SYSCTL_MODID_GET 0x02000031 #define SN_SAL_SYSCTL_GET 0x02000032 #define SN_SAL_SYSCTL_IOBRICK_MODULE_GET 0x02000033 @@ -47,17 +49,22 @@ #define SN_SAL_SYSCTL_PARTITION_GET 0x0200003a #define SN_SAL_SYSTEM_POWER_DOWN 0x0200003b #define SN_SAL_GET_MASTER_BASEIO_NASID 0x0200003c +#define SN_SAL_COHERENCE 0x0200003d +#define SN_SAL_SYSCTL_FRU_CAPTURE 0x0200003f /* * Service-specific constants */ -#define SAL_CONSOLE_INTR_IN 0 /* manipulate input interrupts */ -#define SAL_CONSOLE_INTR_OUT 1 /* manipulate output low-water - * interrupts - */ + +/* Console interrupt manipulation */ + /* action codes */ #define SAL_CONSOLE_INTR_OFF 0 /* turn the interrupt off */ #define SAL_CONSOLE_INTR_ON 1 /* turn the interrupt on */ +#define SAL_CONSOLE_INTR_STATUS 2 /* retrieve the interrupt status */ + /* interrupt specification & status return codes */ +#define SAL_CONSOLE_INTR_XMIT 1 /* output interrupt */ +#define SAL_CONSOLE_INTR_RECV 2 /* input interrupt */ /* @@ -103,15 +110,8 @@ * Specify the minimum PROM revsion required for this kernel. * Note that they're stored in hex format... */ -#ifdef CONFIG_IA64_SGI_SN1 -#define SN_SAL_MIN_MAJOR 0x0 -#define SN_SAL_MIN_MINOR 0x03 /* SN1 PROMs are stuck at rev 0.03 */ -#elif defined(CONFIG_IA64_SGI_SN2) -#define SN_SAL_MIN_MAJOR 0x0 -#define SN_SAL_MIN_MINOR 0x11 -#else -#error "must specify which PROM revisions this kernel needs" -#endif /* CONFIG_IA64_SGI_SN1 */ +#define SN_SAL_MIN_MAJOR 0x1 /* SN2 kernels need at least PROM 1.0 */ +#define SN_SAL_MIN_MINOR 0x0 u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr); @@ -124,10 +124,10 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0); if (ret_stuff.status < 0) @@ -146,10 +146,10 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0); if (ret_stuff.status < 0) @@ -166,12 +166,12 @@ extern u64 klgraph_addr[]; int cnodeid; - cnodeid = 0 /* nasid_to_cnodeid(nasid) */; + cnodeid = nasid_to_cnodeid(nasid); if (klgraph_addr[cnodeid] == 0) { - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; SAL_CALL(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, (u64)nasid, 0, 0, 0, 0, 0, 0); /* @@ -195,11 +195,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0); /* character is in 'v0' */ *ch = (int)ret_stuff.v0; @@ -208,6 +208,26 @@ } /* + * Read a character from the SAL console device, after a previous interrupt + * or poll operation has given us to know that a character is available + * to be read. + */ +static inline u64 +ia64_sn_console_readc(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_READC, 0, 0, 0, 0, 0, 0, 0); + + /* character is in 'v0' */ + return ret_stuff.v0; +} + +/* * Sends the given character to the console. */ static inline u64 @@ -215,11 +235,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -228,17 +248,20 @@ * Sends the given buffer to the console. */ static inline u64 -ia64_sn_console_putb(char *buf, int len) +ia64_sn_console_putb(const char *buf, int len) { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0); - return ret_stuff.status; + if ( ret_stuff.status == 0 ) { + return ret_stuff.v0; + } + return (u64)0; } /* @@ -249,11 +272,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -266,11 +289,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -283,11 +306,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - __SAL_CALL(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0); /* result is in 'v0' */ *result = (int)ret_stuff.v0; @@ -296,6 +319,86 @@ } /* + * Checks console interrupt status + */ +static inline u64 +ia64_sn_console_intr_status(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + 0, SAL_CONSOLE_INTR_STATUS, + 0, 0, 0, 0, 0); + + if (ret_stuff.status == 0) { + return ret_stuff.v0; + } + + return 0; +} + +/* + * Enable an interrupt on the SAL console device. + */ +static inline void +ia64_sn_console_intr_enable(uint64_t intr) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + intr, SAL_CONSOLE_INTR_ON, + 0, 0, 0, 0, 0); +} + +/* + * Disable an interrupt on the SAL console device. + */ +static inline void +ia64_sn_console_intr_disable(uint64_t intr) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_INTR, + intr, SAL_CONSOLE_INTR_OFF, + 0, 0, 0, 0, 0); +} + +/* + * Sends a character buffer to the console asynchronously. + */ +static inline u64 +ia64_sn_console_xmit_chars(char *buf, int len) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_XMIT_CHARS, + (uint64_t)buf, (uint64_t)len, + 0, 0, 0, 0, 0); + + if (ret_stuff.status == 0) { + return ret_stuff.v0; + } + + return 0; +} + +/* * Returns the iobrick module Id */ static inline u64 @@ -303,11 +406,11 @@ { struct ia64_sal_retval ret_stuff; - ret_stuff.status = (uint64_t)0; - ret_stuff.v0 = (uint64_t)0; - ret_stuff.v1 = (uint64_t)0; - ret_stuff.v2 = (uint64_t)0; - SAL_CALL(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0); /* result is in 'v0' */ *result = (int)ret_stuff.v0; @@ -339,7 +442,7 @@ ia64_sn_sys_serial_get(char *buf) { struct ia64_sal_retval ret_stuff; - SAL_CALL(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); + SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0); return ret_stuff.status; } @@ -395,7 +498,6 @@ return ((partid_t)ret_stuff.v0); } -#ifdef CONFIG_IA64_SGI_SN2 /* * Returns the partition id of the current processor. */ @@ -411,7 +513,25 @@ } } -#endif /* CONFIG_IA64_SGI_SN2 */ +/* + * Change or query the coherence domain for this partition. Each cpu-based + * nasid is represented by a bit in an array of 64-bit words: + * 0 = not in this partition's coherency domain + * 1 = in this partition's coherency domain + * It is not possible for the local system's nasids to be removed from + * the coherency domain. + * + * new_domain = set the coherence domain to the given nasids + * old_domain = return the current coherence domain + */ +static inline int +sn_change_coherence(u64 *new_domain, u64 *old_domain) +{ + struct ia64_sal_retval ret_stuff; + SAL_CALL(ret_stuff, SN_SAL_COHERENCE, new_domain, old_domain, 0, 0, + 0, 0, 0); + return ret_stuff.status; +} /* * Turns off system power. @@ -425,5 +545,20 @@ /* never returns */ } +/** + * ia64_sn_fru_capture - tell the system controller to capture hw state + * + * This routine will call the SAL which will tell the system controller(s) + * to capture hw mmr information from each SHub in the system. + */ +static inline u64 +ia64_sn_fru_capture(void) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SN_SAL_SYSCTL_FRU_CAPTURE, 0, 0, 0, 0, 0, 0, 0); + if (isrv.status) + return 0; + return isrv.v0; +} #endif /* _ASM_IA64_SN_SN_SAL_H */ diff -Nru a/include/asm-ia64/sn/snconfig.h b/include/asm-ia64/sn/snconfig.h --- a/include/asm-ia64/sn/snconfig.h Sat Mar 9 02:24:41 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,18 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. - */ -#ifndef _ASM_IA64_SN_SNCONFIG_H -#define _ASM_IA64_SN_SNCONFIG_H - -#include - -#if defined(CONFIG_IA64_SGI_SN1) -#include -#elif defined(CONFIG_IA64_SGI_SN2) -#endif - -#endif /* _ASM_IA64_SN_SNCONFIG_H */ diff -Nru a/include/asm-ia64/sn/sndrv.h b/include/asm-ia64/sn/sndrv.h --- a/include/asm-ia64/sn/sndrv.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/sndrv.h Fri May 16 04:18:18 2003 @@ -1,3 +1,35 @@ +/* + * Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + #ifndef _ASM_IA64_SN_SNDRV_H #define _ASM_IA64_SN_SNDRV_H diff -Nru a/include/asm-ia64/sn/sv.h b/include/asm-ia64/sn/sv.h --- a/include/asm-ia64/sn/sv.h Thu Feb 6 07:33:39 2003 +++ b/include/asm-ia64/sn/sv.h Fri May 16 04:18:17 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved + * Copyright (C) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This implemenation of synchronization variables is heavily based on * one done by Steve Lord diff -Nru a/include/asm-ia64/sn/systeminfo.h b/include/asm-ia64/sn/systeminfo.h --- a/include/asm-ia64/sn/systeminfo.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/systeminfo.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_SYSTEMINFO_H #define _ASM_IA64_SN_SYSTEMINFO_H diff -Nru a/include/asm-ia64/sn/types.h b/include/asm-ia64/sn/types.h --- a/include/asm-ia64/sn/types.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/types.h Fri May 16 04:18:18 2003 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 1999 by Ralf Baechle */ #ifndef _ASM_IA64_SN_TYPES_H @@ -13,16 +13,10 @@ #include typedef unsigned long cpuid_t; -typedef unsigned long cpumask_t; typedef signed short nasid_t; /* node id in numa-as-id space */ typedef signed char partid_t; /* partition ID type */ -#ifdef CONFIG_IA64_SGI_SN2 typedef unsigned int moduleid_t; /* user-visible module number type */ typedef unsigned int cmoduleid_t; /* kernel compact module id type */ -#else -typedef signed short moduleid_t; /* user-visible module number type */ -typedef signed short cmoduleid_t; /* kernel compact module id type */ -#endif typedef signed char slabid_t; typedef unsigned char clusterid_t; /* Clusterid of the cell */ @@ -32,5 +26,6 @@ typedef unsigned char uchar_t; typedef unsigned long paddr_t; typedef unsigned long pfn_t; +typedef short cnodeid_t; #endif /* _ASM_IA64_SN_TYPES_H */ diff -Nru a/include/asm-ia64/sn/uart16550.h b/include/asm-ia64/sn/uart16550.h --- a/include/asm-ia64/sn/uart16550.h Fri Mar 8 18:11:41 2002 +++ b/include/asm-ia64/sn/uart16550.h Fri May 16 04:18:17 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_UART16550_H diff -Nru a/include/asm-ia64/sn/vector.h b/include/asm-ia64/sn/vector.h --- a/include/asm-ia64/sn/vector.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/vector.h Fri May 16 04:18:17 2003 @@ -4,29 +4,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. */ #ifndef _ASM_IA64_SN_VECTOR_H #define _ASM_IA64_SN_VECTOR_H #include -#include #define NET_VEC_NULL ((net_vec_t) 0) #define NET_VEC_BAD ((net_vec_t) -1) -#ifdef RTL - -#define VEC_POLLS_W 16 /* Polls before write times out */ -#define VEC_POLLS_R 16 /* Polls before read times out */ -#define VEC_POLLS_X 16 /* Polls before exch times out */ - -#define VEC_RETRIES_W 1 /* Retries before write fails */ -#define VEC_RETRIES_R 1 /* Retries before read fails */ -#define VEC_RETRIES_X 1 /* Retries before exch fails */ - -#else /* RTL */ - #define VEC_POLLS_W 128 /* Polls before write times out */ #define VEC_POLLS_R 128 /* Polls before read times out */ #define VEC_POLLS_X 128 /* Polls before exch times out */ @@ -34,37 +21,6 @@ #define VEC_RETRIES_W 8 /* Retries before write fails */ #define VEC_RETRIES_R 8 /* Retries before read fails */ #define VEC_RETRIES_X 4 /* Retries before exch fails */ - -#endif /* RTL */ - -#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC) -#define VECTOR_PARMS LB_VECTOR_PARMS -#define VECTOR_ROUTE LB_VECTOR_ROUTE -#define VECTOR_DATA LB_VECTOR_DATA -#define VECTOR_STATUS LB_VECTOR_STATUS -#define VECTOR_RETURN LB_VECTOR_RETURN -#define VECTOR_READ_DATA LB_VECTOR_READ_DATA -#define VECTOR_STATUS_CLEAR LB_VECTOR_STATUS_CLEAR -#define VP_PIOID_SHFT LVP_PIOID_SHFT -#define VP_PIOID_MASK LVP_PIOID_MASK -#define VP_WRITEID_SHFT LVP_WRITEID_SHFT -#define VP_WRITEID_MASK LVP_WRITEID_MASK -#define VP_ADDRESS_MASK LVP_ADDRESS_MASK -#define VP_TYPE_SHFT LVP_TYPE_SHFT -#define VP_TYPE_MASK LVP_TYPE_MASK -#define VS_VALID LVS_VALID -#define VS_OVERRUN LVS_OVERRUN -#define VS_TARGET_SHFT LVS_TARGET_SHFT -#define VS_TARGET_MASK LVS_TARGET_MASK -#define VS_PIOID_SHFT LVS_PIOID_SHFT -#define VS_PIOID_MASK LVS_PIOID_MASK -#define VS_WRITEID_SHFT LVS_WRITEID_SHFT -#define VS_WRITEID_MASK LVS_WRITEID_MASK -#define VS_ADDRESS_MASK LVS_ADDRESS_MASK -#define VS_TYPE_SHFT LVS_TYPE_SHFT -#define VS_TYPE_MASK LVS_TYPE_MASK -#define VS_ERROR_MASK LVS_ERROR_MASK -#endif #define NET_ERROR_NONE 0 /* No error */ #define NET_ERROR_HARDWARE (-1) /* Hardware error */ diff -Nru a/include/asm-ia64/sn/xtalk/xbow.h b/include/asm-ia64/sn/xtalk/xbow.h --- a/include/asm-ia64/sn/xtalk/xbow.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/xtalk/xbow.h Fri May 16 04:18:17 2003 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_SN_XTALK_XBOW_H #define _ASM_SN_SN_XTALK_XBOW_H @@ -405,12 +404,6 @@ /* XBOW_WID_ARB_RELOAD */ #define XBOW_WID_ARB_RELOAD_INT 0x3f /* GBR reload interval */ - - -#ifdef CONFIG_IA64_SGI_SN1 -#define nasid_has_xbridge(nasid) \ - (XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM) -#endif #define IS_XBRIDGE_XBOW(wid) \ (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \ diff -Nru a/include/asm-ia64/sn/xtalk/xbow_info.h b/include/asm-ia64/sn/xtalk/xbow_info.h --- a/include/asm-ia64/sn/xtalk/xbow_info.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/xtalk/xbow_info.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XBOW_INFO_H #define _ASM_SN_XTALK_XBOW_INFO_H @@ -48,9 +48,9 @@ volatile uint32_t *xp_perf_reg; } xbow_perf_t; -extern void xbow_update_perf_counters(devfs_handle_t); -extern xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t); -extern int xbow_enable_perf_counter(devfs_handle_t, int, int, int); +extern void xbow_update_perf_counters(vertex_hdl_t); +extern xbow_perf_link_t *xbow_get_perf_counters(vertex_hdl_t); +extern int xbow_enable_perf_counter(vertex_hdl_t, int, int, int); #define XBOWIOC_PERF_ENABLE 1 #define XBOWIOC_PERF_DISABLE 2 diff -Nru a/include/asm-ia64/sn/xtalk/xswitch.h b/include/asm-ia64/sn/xtalk/xswitch.h --- a/include/asm-ia64/sn/xtalk/xswitch.h Fri Mar 8 18:11:40 2002 +++ b/include/asm-ia64/sn/xtalk/xswitch.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XSWITCH_H #define _ASM_SN_XTALK_XSWITCH_H @@ -23,38 +23,35 @@ typedef struct xswitch_info_s *xswitch_info_t; typedef int - xswitch_reset_link_f(devfs_handle_t xconn); + xswitch_reset_link_f(vertex_hdl_t xconn); typedef struct xswitch_provider_s { xswitch_reset_link_f *reset_link; } xswitch_provider_t; -extern void xswitch_provider_register(devfs_handle_t sw_vhdl, xswitch_provider_t * xsw_fns); +extern void xswitch_provider_register(vertex_hdl_t sw_vhdl, xswitch_provider_t * xsw_fns); xswitch_reset_link_f xswitch_reset_link; -extern xswitch_info_t xswitch_info_new(devfs_handle_t vhdl); +extern xswitch_info_t xswitch_info_new(vertex_hdl_t vhdl); extern void xswitch_info_link_is_ok(xswitch_info_t xswitch_info, xwidgetnum_t port); extern void xswitch_info_vhdl_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t xwidget); + vertex_hdl_t xwidget); extern void xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, xwidgetnum_t port, - devfs_handle_t master_vhdl); + vertex_hdl_t master_vhdl); -extern xswitch_info_t xswitch_info_get(devfs_handle_t vhdl); +extern xswitch_info_t xswitch_info_get(vertex_hdl_t vhdl); extern int xswitch_info_link_ok(xswitch_info_t xswitch_info, xwidgetnum_t port); -extern devfs_handle_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, +extern vertex_hdl_t xswitch_info_vhdl_get(xswitch_info_t xswitch_info, xwidgetnum_t port); -extern devfs_handle_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, +extern vertex_hdl_t xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, xwidgetnum_t port); - -extern int xswitch_id_get(devfs_handle_t vhdl); -extern void xswitch_id_set(devfs_handle_t vhdl,int xbow_num); #endif /* __ASSEMBLY__ */ diff -Nru a/include/asm-ia64/sn/xtalk/xtalk.h b/include/asm-ia64/sn/xtalk/xtalk.h --- a/include/asm-ia64/sn/xtalk/xtalk.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/xtalk/xtalk.h Fri May 16 04:18:18 2003 @@ -4,12 +4,15 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_H #define _ASM_SN_XTALK_XTALK_H #include +#include "asm/sn/sgi.h" + + /* * xtalk.h -- platform-independent crosstalk interface */ @@ -85,7 +88,7 @@ /* PIO MANAGEMENT */ typedef xtalk_piomap_t -xtalk_piomap_alloc_f (devfs_handle_t dev, /* set up mapping for this device */ +xtalk_piomap_alloc_f (vertex_hdl_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, @@ -103,14 +106,14 @@ xtalk_piomap_done_f (xtalk_piomap_t xtalk_piomap); typedef caddr_t -xtalk_piotrans_addr_f (devfs_handle_t dev, /* translate for this device */ +xtalk_piotrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ unsigned flags); /* (currently unused) */ extern caddr_t -xtalk_pio_addr (devfs_handle_t dev, /* translate for this device */ +xtalk_pio_addr (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ @@ -122,7 +125,7 @@ typedef struct xtalk_dmamap_s *xtalk_dmamap_t; typedef xtalk_dmamap_t -xtalk_dmamap_alloc_f (devfs_handle_t dev, /* set up mappings for this device */ +xtalk_dmamap_alloc_f (vertex_hdl_t dev, /* set up mappings for this device */ device_desc_t dev_desc, /* device descriptor */ size_t byte_count_max, /* max size of a mapping */ unsigned flags); /* defined in dma.h */ @@ -144,14 +147,14 @@ xtalk_dmamap_done_f (xtalk_dmamap_t dmamap); typedef iopaddr_t -xtalk_dmatrans_addr_f (devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_addr_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ paddr_t paddr, /* system physical address */ size_t byte_count, /* length */ unsigned flags); typedef alenlist_t -xtalk_dmatrans_list_f (devfs_handle_t dev, /* translate for this device */ +xtalk_dmatrans_list_f (vertex_hdl_t dev, /* translate for this device */ device_desc_t dev_desc, /* device descriptor */ alenlist_t palenlist, /* system address/length list */ unsigned flags); @@ -160,12 +163,12 @@ xtalk_dmamap_drain_f (xtalk_dmamap_t map); /* drain this map's channel */ typedef void -xtalk_dmaaddr_drain_f (devfs_handle_t vhdl, /* drain channel from this device */ +xtalk_dmaaddr_drain_f (vertex_hdl_t vhdl, /* drain channel from this device */ paddr_t addr, /* to this physical address */ size_t bytes); /* for this many bytes */ typedef void -xtalk_dmalist_drain_f (devfs_handle_t vhdl, /* drain channel from this device */ +xtalk_dmalist_drain_f (vertex_hdl_t vhdl, /* drain channel from this device */ alenlist_t list); /* for this set of physical blocks */ @@ -196,54 +199,47 @@ xtalk_intr_setfunc_f (xtalk_intr_t intr_hdl); /* interrupt handle */ typedef xtalk_intr_t -xtalk_intr_alloc_f (devfs_handle_t dev, /* which crosstalk device */ +xtalk_intr_alloc_f (vertex_hdl_t dev, /* which crosstalk device */ device_desc_t dev_desc, /* device descriptor */ - devfs_handle_t owner_dev); /* owner of this intr */ + vertex_hdl_t owner_dev); /* owner of this intr */ typedef void xtalk_intr_free_f (xtalk_intr_t intr_hdl); -#ifdef CONFIG_IA64_SGI_SN1 -typedef int -xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ - void *setfunc_arg); /* arg to setfunc */ -#else typedef int xtalk_intr_connect_f (xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ intr_func_t intr_func, /* xtalk intr handler */ void *intr_arg, /* arg to intr handler */ xtalk_intr_setfunc_f *setfunc, /* func to set intr hw */ void *setfunc_arg); /* arg to setfunc */ -#endif typedef void xtalk_intr_disconnect_f (xtalk_intr_t intr_hdl); -typedef devfs_handle_t +typedef vertex_hdl_t xtalk_intr_cpu_get_f (xtalk_intr_t intr_hdl); /* xtalk intr resource handle */ /* CONFIGURATION MANAGEMENT */ typedef void -xtalk_provider_startup_f (devfs_handle_t xtalk_provider); +xtalk_provider_startup_f (vertex_hdl_t xtalk_provider); typedef void -xtalk_provider_shutdown_f (devfs_handle_t xtalk_provider); +xtalk_provider_shutdown_f (vertex_hdl_t xtalk_provider); typedef void -xtalk_widgetdev_enable_f (devfs_handle_t, int); +xtalk_widgetdev_enable_f (vertex_hdl_t, int); typedef void -xtalk_widgetdev_shutdown_f (devfs_handle_t, int); +xtalk_widgetdev_shutdown_f (vertex_hdl_t, int); typedef int -xtalk_dma_enabled_f (devfs_handle_t); +xtalk_dma_enabled_f (vertex_hdl_t); /* Error Management */ typedef int -xtalk_error_devenable_f (devfs_handle_t xconn_vhdl, +xtalk_error_devenable_f (vertex_hdl_t xconn_vhdl, int devnum, int error_code); @@ -285,7 +281,6 @@ xtalk_intr_free_f *intr_free; xtalk_intr_connect_f *intr_connect; xtalk_intr_disconnect_f *intr_disconnect; - xtalk_intr_cpu_get_f *intr_cpu_get; /* CONFIGURATION MANAGEMENT */ xtalk_provider_startup_f *provider_startup; @@ -327,7 +322,7 @@ /* error management */ -extern int xtalk_error_handler(devfs_handle_t, +extern int xtalk_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); @@ -341,33 +336,33 @@ #define XTALK_INTR_VECTOR_NONE (xtalk_intr_vector_t)0 /* Generic crosstalk interrupt interfaces */ -extern devfs_handle_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr); +extern vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t xtalk_intr); extern xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t xtalk_intr); extern xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t xtalk_intr); extern iopaddr_t xtalk_intr_addr_get(xtalk_intr_t xtalk_intr); -extern devfs_handle_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); +extern vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t xtalk_intr); extern void *xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr); /* Generic crosstalk pio interfaces */ -extern devfs_handle_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); +extern vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap); extern xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap); extern iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap); extern size_t xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap); extern caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap); /* Generic crosstalk dma interfaces */ -extern devfs_handle_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap); +extern vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap); extern xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap); /* Register/unregister Crosstalk providers and get implementation handle */ extern void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -extern void xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns); -extern void xtalk_provider_unregister(devfs_handle_t provider); -extern xtalk_provider_t *xtalk_provider_fns_get(devfs_handle_t provider); +extern void xtalk_provider_register(vertex_hdl_t provider, xtalk_provider_t *xtalk_fns); +extern void xtalk_provider_unregister(vertex_hdl_t provider); +extern xtalk_provider_t *xtalk_provider_fns_get(vertex_hdl_t provider); /* Crosstalk Switch generic layer, for use by initialization code */ -extern void xswitch_census(devfs_handle_t xswitchv); -extern void xswitch_init_widgets(devfs_handle_t xswitchv); +extern void xswitch_census(vertex_hdl_t xswitchv); +extern void xswitch_init_widgets(vertex_hdl_t xswitchv); /* early init interrupt management */ @@ -397,7 +392,7 @@ typedef xtalk_intr_setfunc_f *xtalk_intr_setfunc_t; -typedef void xtalk_iter_f(devfs_handle_t vhdl); +typedef void xtalk_iter_f(vertex_hdl_t vhdl); extern void xtalk_iterate(char *prefix, xtalk_iter_f *func); diff -Nru a/include/asm-ia64/sn/xtalk/xtalk_private.h b/include/asm-ia64/sn/xtalk/xtalk_private.h --- a/include/asm-ia64/sn/xtalk/xtalk_private.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/xtalk/xtalk_private.h Fri May 16 04:18:18 2003 @@ -4,7 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALK_PRIVATE_H #define _ASM_SN_XTALK_XTALK_PRIVATE_H @@ -23,7 +23,7 @@ * All Crosstalk providers set up PIO using this information. */ struct xtalk_piomap_s { - devfs_handle_t xp_dev; /* a requestor of this mapping */ + vertex_hdl_t xp_dev; /* a requestor of this mapping */ xwidgetnum_t xp_target; /* target (node's widget number) */ iopaddr_t xp_xtalk_addr; /* which crosstalk addr is mapped */ size_t xp_mapsz; /* size of this mapping */ @@ -34,7 +34,7 @@ * All Crosstalk providers set up DMA using this information. */ struct xtalk_dmamap_s { - devfs_handle_t xd_dev; /* a requestor of this mapping */ + vertex_hdl_t xd_dev; /* a requestor of this mapping */ xwidgetnum_t xd_target; /* target (node's widget number) */ }; @@ -42,7 +42,7 @@ * All Crosstalk providers set up interrupts using this information. */ struct xtalk_intr_s { - devfs_handle_t xi_dev; /* requestor of this intr */ + vertex_hdl_t xi_dev; /* requestor of this intr */ xwidgetnum_t xi_target; /* master's widget number */ xtalk_intr_vector_t xi_vector; /* 8-bit interrupt vector */ iopaddr_t xi_addr; /* xtalk address to generate intr */ @@ -72,10 +72,10 @@ */ struct xwidget_info_s { char *w_fingerprint; - devfs_handle_t w_vertex; /* back pointer to vertex */ + vertex_hdl_t w_vertex; /* back pointer to vertex */ xwidgetnum_t w_id; /* widget id */ struct xwidget_hwid_s w_hwid; /* hardware identification (part/rev/mfg) */ - devfs_handle_t w_master; /* CACHED widget's master */ + vertex_hdl_t w_master; /* CACHED widget's master */ xwidgetnum_t w_masterid; /* CACHED widget's master's widgetnum */ error_handler_f *w_efunc; /* error handling function */ error_handler_arg_t w_einfo; /* first parameter for efunc */ diff -Nru a/include/asm-ia64/sn/xtalk/xtalkaddrs.h b/include/asm-ia64/sn/xtalk/xtalkaddrs.h --- a/include/asm-ia64/sn/xtalk/xtalkaddrs.h Fri Mar 8 18:11:39 2002 +++ b/include/asm-ia64/sn/xtalk/xtalkaddrs.h Fri May 16 04:18:18 2003 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _ASM_SN_XTALK_XTALKADDRS_H #define _ASM_SN_XTALK_XTALKADDRS_H diff -Nru a/include/asm-ia64/sn/xtalk/xwidget.h b/include/asm-ia64/sn/xtalk/xwidget.h --- a/include/asm-ia64/sn/xtalk/xwidget.h Tue Dec 3 10:07:34 2002 +++ b/include/asm-ia64/sn/xtalk/xwidget.h Fri May 16 04:18:17 2003 @@ -4,8 +4,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. - * Copyright (C) 2000 by Colin Ngam + * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef __ASM_SN_XTALK_XWIDGET_H__ #define __ASM_SN_XTALK_XWIDGET_H__ @@ -261,27 +260,26 @@ extern void xwidget_driver_unregister(char *driver_prefix); extern int xwidget_register(struct xwidget_hwid_s *hwid, - devfs_handle_t dev, + vertex_hdl_t dev, xwidgetnum_t id, - devfs_handle_t master, - xwidgetnum_t targetid, - async_attach_t aa); - -extern int xwidget_unregister(devfs_handle_t); - -extern void xwidget_reset(devfs_handle_t xwidget); -extern void xwidget_gfx_reset(devfs_handle_t xwidget); -extern char *xwidget_name_get(devfs_handle_t xwidget); + vertex_hdl_t master, + xwidgetnum_t targetid); + +extern int xwidget_unregister(vertex_hdl_t); + +extern void xwidget_reset(vertex_hdl_t xwidget); +extern void xwidget_gfx_reset(vertex_hdl_t xwidget); +extern char *xwidget_name_get(vertex_hdl_t xwidget); /* Generic crosstalk widget information access interface */ -extern xwidget_info_t xwidget_info_chk(devfs_handle_t widget); -extern xwidget_info_t xwidget_info_get(devfs_handle_t widget); -extern void xwidget_info_set(devfs_handle_t widget, xwidget_info_t widget_info); -extern devfs_handle_t xwidget_info_dev_get(xwidget_info_t xwidget_info); +extern xwidget_info_t xwidget_info_chk(vertex_hdl_t widget); +extern xwidget_info_t xwidget_info_get(vertex_hdl_t widget); +extern void xwidget_info_set(vertex_hdl_t widget, xwidget_info_t widget_info); +extern vertex_hdl_t xwidget_info_dev_get(xwidget_info_t xwidget_info); extern xwidgetnum_t xwidget_info_id_get(xwidget_info_t xwidget_info); extern int xwidget_info_type_get(xwidget_info_t xwidget_info); extern int xwidget_info_state_get(xwidget_info_t xwidget_info); -extern devfs_handle_t xwidget_info_master_get(xwidget_info_t xwidget_info); +extern vertex_hdl_t xwidget_info_master_get(xwidget_info_t xwidget_info); extern xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t xwidget_info); extern xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t xwidget_info); extern xwidget_rev_num_t xwidget_info_rev_num_get(xwidget_info_t xwidget_info); diff -Nru a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h --- a/include/asm-ia64/spinlock.h Tue May 6 10:56:54 2003 +++ b/include/asm-ia64/spinlock.h Fri May 30 19:59:40 2003 @@ -32,7 +32,7 @@ * carefully coded to touch only those registers that spin_lock() marks "clobbered". */ -#define IA64_SPINLOCK_CLOBBERS "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory" +#define IA64_SPINLOCK_CLOBBERS "ar.ccv", "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory" static inline void _raw_spin_lock (spinlock_t *lock) @@ -133,8 +133,7 @@ while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, "acq") < 0)) { \ ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel"); \ while (*(volatile int *)__read_lock_ptr < 0) \ - barrier(); \ - \ + cpu_relax(); \ } \ } while (0) diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h --- a/include/asm-ia64/system.h Sat May 10 02:28:47 2003 +++ b/include/asm-ia64/system.h Thu Jun 12 01:09:19 2003 @@ -19,11 +19,10 @@ #include #include -#define KERNEL_START (PAGE_OFFSET + 68*1024*1024) - -/* 0xa000000000000000 - 0xa000000000000000+PERCPU_MAX_SIZE remain unmapped */ +/* 0xa000000000000000 - 0xa000000000000000+PERCPU_PAGE_SIZE remain unmapped */ #define PERCPU_ADDR (0xa000000000000000 + PERCPU_PAGE_SIZE) #define GATE_ADDR (0xa000000000000000 + 2*PERCPU_PAGE_SIZE) +#define KERNEL_START 0xa000000100000000 #ifndef __ASSEMBLY__ @@ -217,13 +216,11 @@ || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE()) #define __switch_to(prev,next,last) do { \ - struct task_struct *__fpu_owner = ia64_get_fpu_owner(); \ if (IA64_HAS_EXTRA_STATE(prev)) \ ia64_save_extra(prev); \ if (IA64_HAS_EXTRA_STATE(next)) \ ia64_load_extra(next); \ - ia64_psr(ia64_task_regs(next))->dfh = \ - !(__fpu_owner == (next) && ((next)->thread.last_fph_cpu == smp_processor_id())); \ + ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \ (last) = ia64_switch_to((next)); \ } while (0) @@ -239,7 +236,6 @@ ia64_psr(ia64_task_regs(prev))->mfh = 0; \ (prev)->thread.flags |= IA64_THREAD_FPH_VALID; \ __ia64_save_fpu((prev)->thread.fph); \ - (prev)->thread.last_fph_cpu = smp_processor_id(); \ } \ __switch_to(prev, next, last); \ } while (0) @@ -278,6 +274,8 @@ } while (0) #define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock) #define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock)) + +#define ia64_platform_is(x) (strcmp(x, platform_name) == 0) #endif /* __KERNEL__ */ diff -Nru a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h --- a/include/asm-ia64/thread_info.h Thu Mar 6 21:11:46 2003 +++ b/include/asm-ia64/thread_info.h Wed Jun 4 19:22:35 2003 @@ -9,11 +9,13 @@ #include #include -#define TI_EXEC_DOMAIN 0x00 -#define TI_FLAGS 0x08 -#define TI_CPU 0x0c -#define TI_ADDR_LIMIT 0x10 -#define TI_PRE_COUNT 0x18 +#define TI_TASK 0x00 +#define TI_EXEC_DOMAIN 0x08 +#define TI_FLAGS 0x10 +#define TI_CPU 0x14 +#define TI_ADDR_LIMIT 0x18 +#define TI_PRE_COUNT 0x20 +#define TI_RESTART_BLOCK 0x28 #define PREEMPT_ACTIVE_BIT 30 #define PREEMPT_ACTIVE (1 << PREEMPT_ACTIVE_BIT) @@ -26,6 +28,7 @@ * without having to do pointer masking. */ struct thread_info { + struct task_struct *task; /* XXX not really needed, except for dup_task_struct() */ struct exec_domain *exec_domain;/* execution domain */ __u32 flags; /* thread_info flags (see TIF_*) */ __u32 cpu; /* current CPU */ @@ -37,8 +40,9 @@ #define INIT_THREAD_SIZE /* tell sched.h not to declare the thread_union */ #define THREAD_SIZE KERNEL_STACK_SIZE -#define INIT_THREAD_INFO(ti) \ +#define INIT_THREAD_INFO(tsk) \ { \ + .task = &tsk, \ .exec_domain = &default_exec_domain, \ .flags = 0, \ .cpu = 0, \ @@ -50,8 +54,13 @@ } /* how to get the thread information struct from C */ -#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) +#define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) +#define alloc_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE)) #define free_thread_info(ti) /* nothing */ + +#define __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +#define alloc_task_struct() ((task_t *)__get_free_pages(GFP_KERNEL, KERNEL_STACK_SIZE_ORDER)) +#define free_task_struct(tsk) free_pages((unsigned long) (tsk), KERNEL_STACK_SIZE_ORDER) #endif /* !__ASSEMBLY */ diff -Nru a/include/asm-ia64/timex.h b/include/asm-ia64/timex.h --- a/include/asm-ia64/timex.h Sat Jun 14 16:15:58 2003 +++ b/include/asm-ia64/timex.h Tue Jun 17 23:44:15 2003 @@ -2,7 +2,7 @@ #define _ASM_IA64_TIMEX_H /* - * Copyright (C) 1998-2001 Hewlett-Packard Co + * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co * David Mosberger-Tang */ /* diff -Nru a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h --- a/include/asm-ia64/tlb.h Fri Jan 24 11:56:49 2003 +++ b/include/asm-ia64/tlb.h Fri May 23 06:48:36 2003 @@ -63,7 +63,7 @@ }; /* Users of the generic TLB shootdown code must declare this storage space. */ -extern struct mmu_gather mmu_gathers[NR_CPUS]; +DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); /* * Flush the TLB for address range START to END and, if not in fast mode, release the @@ -125,7 +125,7 @@ static inline struct mmu_gather * tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush) { - struct mmu_gather *tlb = &mmu_gathers[smp_processor_id()]; + struct mmu_gather *tlb = &per_cpu(mmu_gathers, smp_processor_id()); tlb->mm = mm; /* diff -Nru a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h --- a/include/asm-ia64/topology.h Mon Mar 3 16:00:00 2003 +++ b/include/asm-ia64/topology.h Fri May 23 03:35:21 2003 @@ -63,4 +63,6 @@ /* Cross-node load balancing interval. */ #define NODE_BALANCE_RATE 10 +void build_cpu_to_node_map(void); + #endif /* _ASM_IA64_TOPOLOGY_H */ diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h Thu Mar 6 14:56:33 2003 +++ b/include/asm-ia64/unistd.h Tue Jun 10 14:00:47 2003 @@ -247,6 +247,10 @@ #define __NR_sys_clock_getres 1255 #define __NR_sys_clock_nanosleep 1256 +#ifdef __KERNEL__ + +#define NR_syscalls 256 /* length of syscall table */ + #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr); @@ -348,10 +352,12 @@ /* * "Conditional" syscalls * - * What we want is __attribute__((weak,alias("sys_ni_syscall"))), - * but it doesn't work on all toolchains, so we just do it by hand + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), but it doesn't work on + * all toolchains, so we just do it by hand. Note, this macro can only be used in the + * file which defines sys_ni_syscall, i.e., in kernel/sys.c. */ #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); #endif /* !__ASSEMBLY__ */ +#endif /* __KERNEL__ */ #endif /* _ASM_IA64_UNISTD_H */ diff -Nru a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h --- a/include/asm-ia64/unwind.h Tue Apr 15 13:16:39 2003 +++ b/include/asm-ia64/unwind.h Thu Jun 12 01:09:19 2003 @@ -26,7 +26,9 @@ UNW_AR_EC, UNW_AR_FPSR, UNW_AR_RSC, - UNW_AR_CCV + UNW_AR_CCV, + UNW_AR_CSD, + UNW_AR_SSD }; /* @@ -95,7 +97,6 @@ * Initialize unwind support. */ extern void unw_init (void); -extern void unw_create_gate_table (void); extern void *unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp, const void *table_start, const void *table_end); diff -Nru a/include/asm-ia64/ustack.h b/include/asm-ia64/ustack.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-ia64/ustack.h Fri Jun 6 22:53:38 2003 @@ -0,0 +1,16 @@ +#ifndef _ASM_IA64_USTACK_H +#define _ASM_IA64_USTACK_H + +/* + * Constants for the user stack size + */ + +#include + +/* The absolute hard limit for stack size is 1/2 of the mappable space in the region */ +#define MAX_USER_STACK_SIZE (RGN_MAP_LIMIT/2) +/* Make a default stack size of 2GB */ +#define DEFAULT_USER_STACK_SIZE (1UL << 31) +#define STACK_TOP (0x6000000000000000UL + RGN_MAP_LIMIT) + +#endif /* _ASM_IA64_USTACK_H */ diff -Nru a/include/asm-ia64/xor.h b/include/asm-ia64/xor.h --- a/include/asm-ia64/xor.h Tue Feb 5 09:39:54 2002 +++ b/include/asm-ia64/xor.h Tue Jun 17 23:50:17 2003 @@ -22,262 +22,12 @@ 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, - do_3: xor_ia64_3, - do_4: xor_ia64_4, - do_5: xor_ia64_5, + .name = "ia64", + .do_2 = xor_ia64_2, + .do_3 = xor_ia64_3, + .do_4 = xor_ia64_4, + .do_5 = xor_ia64_5, }; #define XOR_TRY_TEMPLATES xor_speed(&xor_block_ia64) diff -Nru a/include/asm-sparc/xor.h b/include/asm-sparc/xor.h --- a/include/asm-sparc/xor.h Mon Feb 4 23:53:56 2002 +++ b/include/asm-sparc/xor.h Mon Jun 16 18:31:20 2003 @@ -250,11 +250,11 @@ } static struct xor_block_template xor_block_SPARC = { - name: "SPARC", - do_2: sparc_2, - do_3: sparc_3, - do_4: sparc_4, - do_5: sparc_5, + .name = "SPARC", + .do_2 = sparc_2, + .do_3 = sparc_3, + .do_4 = sparc_4, + .do_5 = sparc_5, }; /* For grins, also test the generic routines. */ diff -Nru a/include/asm-sparc64/xor.h b/include/asm-sparc64/xor.h --- a/include/asm-sparc64/xor.h Mon Feb 4 23:54:46 2002 +++ b/include/asm-sparc64/xor.h Mon Jun 16 18:31:20 2003 @@ -388,11 +388,11 @@ "); static struct xor_block_template xor_block_VIS = { - name: "VIS", - do_2: xor_vis_2, - do_3: xor_vis_3, - do_4: xor_vis_4, - do_5: xor_vis_5, + .name = "VIS", + .do_2 = xor_vis_2, + .do_3 = xor_vis_3, + .do_4 = xor_vis_4, + .do_5 = xor_vis_5, }; #define XOR_TRY_TEMPLATES xor_speed(&xor_block_VIS) diff -Nru a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h --- a/include/asm-v850/hardirq.h Mon May 12 18:59:24 2003 +++ b/include/asm-v850/hardirq.h Mon Jun 16 22:23:12 2003 @@ -80,12 +80,12 @@ # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif -#define irq_exit() \ -do { \ - preempt_count() -= IRQ_EXIT_OFFSET; \ - if (!in_interrupt() && softirq_pending(smp_processor_id())) \ - do_softirq(); \ - preempt_enable_no_resched(); \ +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ } while (0) #ifndef CONFIG_SMP diff -Nru a/include/asm-v850/io.h b/include/asm-v850/io.h --- a/include/asm-v850/io.h Fri Nov 1 08:38:12 2002 +++ b/include/asm-v850/io.h Mon Jun 16 22:23:12 2003 @@ -1,8 +1,8 @@ /* * include/asm-v850/io.h -- Misc I/O operations * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this @@ -29,6 +29,13 @@ (void)((*(volatile unsigned short *) (addr)) = (b)) #define writel(b, addr) \ (void)((*(volatile unsigned int *) (addr)) = (b)) + +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel #define inb(addr) readb (addr) #define inw(addr) readw (addr) diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h --- a/include/linux/acpi.h Wed Jun 11 09:49:14 2003 +++ b/include/linux/acpi.h Tue Jun 17 17:36:43 2003 @@ -403,8 +403,8 @@ struct acpi_pci_driver { struct acpi_pci_driver *next; - int (*add)(acpi_handle *handle); - void (*remove)(acpi_handle *handle); + int (*add)(acpi_handle handle); + void (*remove)(acpi_handle handle); }; int acpi_pci_register_driver(struct acpi_pci_driver *driver); diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h --- a/include/linux/atmdev.h Wed Jun 4 17:57:06 2003 +++ b/include/linux/atmdev.h Tue Jun 17 11:00:05 2003 @@ -452,7 +452,7 @@ int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci); int atm_pcr_goal(struct atm_trafprm *tp); -void atm_async_release_vcc(struct atm_vcc *vcc,int reply); +void vcc_release_async(struct atm_vcc *vcc, int reply); #endif /* __KERNEL__ */ diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h --- a/include/linux/ext3_fs.h Mon May 12 21:23:29 2003 +++ b/include/linux/ext3_fs.h Tue Jun 17 23:04:16 2003 @@ -344,7 +344,9 @@ #endif #define ext3_set_bit ext2_set_bit +#define ext3_set_bit_atomic ext2_set_bit_atomic #define ext3_clear_bit ext2_clear_bit +#define ext3_clear_bit_atomic ext2_clear_bit_atomic #define ext3_test_bit ext2_test_bit #define ext3_find_first_zero_bit ext2_find_first_zero_bit #define ext3_find_next_zero_bit ext2_find_next_zero_bit @@ -733,6 +735,7 @@ extern int ext3_change_inode_journal_flag(struct inode *, int); extern void ext3_truncate (struct inode *); extern void ext3_set_inode_flags(struct inode *); +extern void ext3_set_aops(struct inode *inode); /* ioctl.c */ extern int ext3_ioctl (struct inode *, struct file *, unsigned int, @@ -780,10 +783,6 @@ /* file.c */ extern struct inode_operations ext3_file_inode_operations; extern struct file_operations ext3_file_operations; - -/* inode.c */ -extern struct address_space_operations ext3_aops; -extern struct address_space_operations ext3_writeback_aops; /* namei.c */ extern struct inode_operations ext3_dir_inode_operations; diff -Nru a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h --- a/include/linux/ext3_fs_sb.h Fri Nov 1 17:32:18 2002 +++ b/include/linux/ext3_fs_sb.h Tue Jun 17 23:03:49 2003 @@ -19,6 +19,8 @@ #ifdef __KERNEL__ #include #include +#include +#include #endif /* @@ -50,8 +52,11 @@ u32 s_next_generation; u32 s_hash_seed[4]; int s_def_hash_version; - unsigned long s_dir_count; - u8 *s_debts; + u8 *s_debts; + struct percpu_counter s_freeblocks_counter; + struct percpu_counter s_freeinodes_counter; + struct percpu_counter s_dirs_counter; + struct blockgroup_lock s_blockgroup_lock; /* Journaling */ struct inode * s_journal_inode; diff -Nru a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h --- a/include/linux/ext3_jbd.h Sat Mar 22 22:14:52 2003 +++ b/include/linux/ext3_jbd.h Tue Jun 17 23:04:25 2003 @@ -97,26 +97,33 @@ struct buffer_head *bh, handle_t *handle, int err); static inline int -__ext3_journal_get_undo_access(const char *where, - handle_t *handle, struct buffer_head *bh) +__ext3_journal_get_undo_access(const char *where, handle_t *handle, + struct buffer_head *bh, int *credits) { - int err = journal_get_undo_access(handle, bh); + int err = journal_get_undo_access(handle, bh, credits); if (err) ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline int -__ext3_journal_get_write_access(const char *where, - handle_t *handle, struct buffer_head *bh) +__ext3_journal_get_write_access(const char *where, handle_t *handle, + struct buffer_head *bh, int *credits) { - int err = journal_get_write_access(handle, bh); + int err = journal_get_write_access(handle, bh, credits); if (err) ext3_journal_abort_handle(where, __FUNCTION__, bh, handle,err); return err; } static inline void +ext3_journal_release_buffer(handle_t *handle, struct buffer_head *bh, + int credits) +{ + journal_release_buffer(handle, bh, credits); +} + +static inline void ext3_journal_forget(handle_t *handle, struct buffer_head *bh) { journal_forget(handle, bh); @@ -153,10 +160,12 @@ } -#define ext3_journal_get_undo_access(handle, bh) \ - __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh)) +#define ext3_journal_get_undo_access(handle, bh, credits) \ + __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh), (credits)) #define ext3_journal_get_write_access(handle, bh) \ - __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh)) + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), NULL) +#define ext3_journal_get_write_access_credits(handle, bh, credits) \ + __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh), (credits)) #define ext3_journal_revoke(handle, blocknr, bh) \ __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh)) #define ext3_journal_get_create_access(handle, bh) \ @@ -173,17 +182,6 @@ static inline handle_t *ext3_journal_current_handle(void) { return journal_current_handle(); -} - -static inline void -ext3_log_start_commit(journal_t *journal, transaction_t *transaction) -{ - log_start_commit(journal, transaction); -} - -static inline void ext3_log_wait_commit(journal_t *journal, tid_t tid) -{ - log_wait_commit(journal, tid); } static inline int ext3_journal_extend(handle_t *handle, int nblocks) diff -Nru a/include/linux/firmware.h b/include/linux/firmware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/firmware.h Thu Jun 19 09:44:09 2003 @@ -0,0 +1,19 @@ +#ifndef _LINUX_FIRMWARE_H +#define _LINUX_FIRMWARE_H +#include +#include +#define FIRMWARE_NAME_MAX 30 +struct firmware { + size_t size; + u8 *data; +}; +int request_firmware(const struct firmware **fw, const char *name, + struct device *device); +int request_firmware_nowait( + struct module *module, + const char *name, struct device *device, void *context, + void (*cont)(const struct firmware *fw, void *context)); + +void release_firmware(const struct firmware *fw); +void register_firmware(const char *name, const u8 *data, size_t size); +#endif diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h --- a/include/linux/isdn.h Wed Jun 11 12:32:33 2003 +++ b/include/linux/isdn.h Tue Jun 17 20:25:22 2003 @@ -283,7 +283,7 @@ #endif int mdmcmdl; /* Length of Modem-Commandbuffer */ int pluscount; /* Counter for +++ sequence */ - int lastplus; /* Timestamp of last + */ + unsigned long lastplus; /* Timestamp of last + */ char mdmcmd[255]; /* Modem-Commandbuffer */ unsigned int charge; /* Charge units of current connection */ } atemu; diff -Nru a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h --- a/include/linux/isdn_ppp.h Tue Oct 29 18:17:00 2002 +++ b/include/linux/isdn_ppp.h Wed Jun 18 21:48:01 2003 @@ -95,7 +95,8 @@ * check the original include for more information */ struct isdn_ppp_compressor { - struct isdn_ppp_compressor *next, *prev; + struct module *owner; + struct list_head list; int num; /* CCP compression protocol number */ void *(*alloc) (struct isdn_ppp_comp_data *); diff -Nru a/include/linux/jbd.h b/include/linux/jbd.h --- a/include/linux/jbd.h Thu Apr 3 19:49:43 2003 +++ b/include/linux/jbd.h Tue Jun 17 23:04:25 2003 @@ -178,7 +178,7 @@ __u32 s_blocksize; /* journal device blocksize */ __u32 s_maxlen; /* total blocks in journal file */ __u32 s_first; /* first block of log information */ - + /* 0x0018 */ /* Dynamic information describing the current state of the log */ __u32 s_sequence; /* first commit ID expected in log */ @@ -198,9 +198,9 @@ /* 0x0040 */ __u32 s_nr_users; /* Nr of filesystems sharing log */ - + __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ - + /* 0x0048 */ __u32 s_max_transaction; /* Limit of journal blocks per trans.*/ __u32 s_max_trans_data; /* Limit of data blocks per trans. */ @@ -286,15 +286,18 @@ enum jbd_state_bits { BH_JBD /* Has an attached ext3 journal_head */ - = BH_PrivateStart, + = BH_PrivateStart, BH_JWrite, /* Being written to log (@@@ DEBUGGING) */ BH_Freed, /* Has been freed (truncated) */ BH_Revoked, /* Has been revoked from the log */ BH_RevokeValid, /* Revoked flag is valid */ BH_JBDDirty, /* Is dirty but journaled */ + BH_State, /* Pins most journal_head state */ + BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ }; BUFFER_FNS(JBD, jbd) +BUFFER_FNS(JWrite, jwrite) BUFFER_FNS(JBDDirty, jbddirty) TAS_BUFFER_FNS(JBDDirty, jbddirty) BUFFER_FNS(Freed, freed) @@ -309,6 +312,36 @@ return bh->b_private; } +static inline void jbd_lock_bh_state(struct buffer_head *bh) +{ + bit_spin_lock(BH_State, &bh->b_state); +} + +static inline int jbd_trylock_bh_state(struct buffer_head *bh) +{ + return bit_spin_trylock(BH_State, &bh->b_state); +} + +static inline int jbd_is_locked_bh_state(struct buffer_head *bh) +{ + return bit_spin_is_locked(BH_State, &bh->b_state); +} + +static inline void jbd_unlock_bh_state(struct buffer_head *bh) +{ + bit_spin_unlock(BH_State, &bh->b_state); +} + +static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_lock(BH_JournalHead, &bh->b_state); +} + +static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_unlock(BH_JournalHead, &bh->b_state); +} + #define HAVE_JOURNAL_CALLBACK_STATUS /** * struct journal_callback - Base structure for callback information. @@ -325,7 +358,7 @@ * See journal_callback_set for more information. **/ struct journal_callback { - struct list_head jcb_list; + struct list_head jcb_list; /* t_jcb_lock */ void (*jcb_func)(struct journal_callback *jcb, int error); /* user data goes here */ }; @@ -333,7 +366,8 @@ struct jbd_revoke_table_s; /** - * struct handle_s - The handle_s type is the concrete type associated with handle_t. + * struct handle_s - The handle_s type is the concrete type associated with + * handle_t. * @h_transaction: Which compound transaction is this update a part of? * @h_buffer_credits: Number of remaining buffers we are allowed to dirty. * @h_ref: Reference count on this handle @@ -351,7 +385,7 @@ struct handle_s { /* Which compound transaction is this update a part of? */ - transaction_t * h_transaction; + transaction_t *h_transaction; /* Number of remaining buffers we are allowed to dirty: */ int h_buffer_credits; @@ -363,13 +397,14 @@ /* operations */ int h_err; - /* List of application registered callbacks for this handle. - * The function(s) will be called after the transaction that - * this handle is part of has been committed to disk. + /* + * List of application registered callbacks for this handle. The + * function(s) will be called after the transaction that this handle is + * part of has been committed to disk. [t_jcb_lock] */ struct list_head h_jcb; - /* Flags */ + /* Flags [no locking] */ unsigned int h_sync: 1; /* sync-on-close */ unsigned int h_jdata: 1; /* force data journaling */ unsigned int h_aborted: 1; /* fatal error on handle */ @@ -392,15 +427,42 @@ * flushed to home for finished transactions. */ +/* + * Lock ranking: + * + * j_list_lock + * ->jbd_lock_bh_journal_head() (This is "innermost") + * + * j_state_lock + * ->jbd_lock_bh_state() + * + * jbd_lock_bh_state() + * ->j_list_lock + * + * j_state_lock + * ->t_handle_lock + * + * j_state_lock + * ->j_list_lock (journal_unmap_buffer) + * + * t_handle_lock + * ->t_jcb_lock + */ + struct transaction_s { - /* Pointer to the journal for this transaction. */ - journal_t * t_journal; - - /* Sequence number for this transaction */ + /* Pointer to the journal for this transaction. [no locking] */ + journal_t *t_journal; + + /* Sequence number for this transaction [no locking] */ tid_t t_tid; - - /* Transaction's current state */ + + /* + * Transaction's current state + * [no locking - only kjournald alters this] + * FIXME: needs barriers + * KLUDGE: [use j_state_lock] + */ enum { T_RUNNING, T_LOCKED, @@ -410,87 +472,115 @@ T_FINISHED } t_state; - /* Where in the log does this transaction's commit start? */ + /* + * Where in the log does this transaction's commit start? [no locking] + */ unsigned long t_log_start; - - /* Doubly-linked circular list of all inodes owned by this - transaction */ /* AKPM: unused */ - struct inode * t_ilist; - - /* Number of buffers on the t_buffers list */ + + /* Number of buffers on the t_buffers list [j_list_lock] */ int t_nr_buffers; - - /* Doubly-linked circular list of all buffers reserved but not - yet modified by this transaction */ - struct journal_head * t_reserved_list; - - /* Doubly-linked circular list of all metadata buffers owned by this - transaction */ - struct journal_head * t_buffers; - + + /* + * Doubly-linked circular list of all buffers reserved but not yet + * modified by this transaction [j_list_lock] + */ + struct journal_head *t_reserved_list; + + /* + * Doubly-linked circular list of all metadata buffers owned by this + * transaction [j_list_lock] + */ + struct journal_head *t_buffers; + /* * Doubly-linked circular list of all data buffers still to be - * flushed before this transaction can be committed. - * Protected by journal_datalist_lock. + * flushed before this transaction can be committed [j_list_lock] + */ + struct journal_head *t_sync_datalist; + + /* + * Doubly-linked circular list of all forget buffers (superseded + * buffers which we can un-checkpoint once this transaction commits) + * [j_list_lock] + */ + struct journal_head *t_forget; + + /* + * Doubly-linked circular list of all buffers still to be flushed before + * this transaction can be checkpointed. [j_list_lock] + */ + struct journal_head *t_checkpoint_list; + + /* + * Doubly-linked circular list of temporary buffers currently undergoing + * IO in the log [j_list_lock] + */ + struct journal_head *t_iobuf_list; + + /* + * Doubly-linked circular list of metadata buffers being shadowed by log + * IO. The IO buffers on the iobuf list and the shadow buffers on this + * list match each other one for one at all times. [j_list_lock] + */ + struct journal_head *t_shadow_list; + + /* + * Doubly-linked circular list of control buffers being written to the + * log. [j_list_lock] + */ + struct journal_head *t_log_list; + + /* + * Protects info related to handles + */ + spinlock_t t_handle_lock; + + /* + * Number of outstanding updates running on this transaction + * [t_handle_lock] */ - struct journal_head * t_sync_datalist; - - /* Doubly-linked circular list of all forget buffers (superseded - buffers which we can un-checkpoint once this transaction - commits) */ - struct journal_head * t_forget; - - /* - * Doubly-linked circular list of all buffers still to be - * flushed before this transaction can be checkpointed. - */ - /* Protected by journal_datalist_lock */ - struct journal_head * t_checkpoint_list; - - /* Doubly-linked circular list of temporary buffers currently - undergoing IO in the log */ - struct journal_head * t_iobuf_list; - - /* Doubly-linked circular list of metadata buffers being - shadowed by log IO. The IO buffers on the iobuf list and the - shadow buffers on this list match each other one for one at - all times. */ - struct journal_head * t_shadow_list; - - /* Doubly-linked circular list of control buffers being written - to the log. */ - struct journal_head * t_log_list; - - /* Number of outstanding updates running on this transaction */ int t_updates; - /* Number of buffers reserved for use by all handles in this - * transaction handle but not yet modified. */ + /* + * Number of buffers reserved for use by all handles in this transaction + * handle but not yet modified. [t_handle_lock] + */ int t_outstanding_credits; - + /* - * Forward and backward links for the circular list of all - * transactions awaiting checkpoint. + * Forward and backward links for the circular list of all transactions + * awaiting checkpoint. [j_list_lock] */ - /* Protected by journal_datalist_lock */ transaction_t *t_cpnext, *t_cpprev; - /* When will the transaction expire (become due for commit), in - * jiffies ? */ + /* + * When will the transaction expire (become due for commit), in jiffies? + * [no locking] + */ unsigned long t_expires; - /* How many handles used this transaction? */ + /* + * How many handles used this transaction? [t_handle_lock] + */ int t_handle_count; - /* List of registered callback functions for this transaction. - * Called when the transaction is committed. */ + /* + * Protects the callback list + */ + spinlock_t t_jcb_lock; + /* + * List of registered callback functions for this transaction. + * Called when the transaction is committed. [t_jcb_lock] + */ struct list_head t_jcb; }; /** - * struct journal_s - The journal_s type is the concrete type associated with journal_t. + * struct journal_s - The journal_s type is the concrete type associated with + * journal_t. * @j_flags: General journaling state flags - * @j_errno: Is there an outstanding uncleared error on the journal (from a prior abort)? + * @j_errno: Is there an outstanding uncleared error on the journal (from a + * prior abort)? * @j_sb_buffer: First part of superblock buffer * @j_superblock: Second part of superblock buffer * @j_format_version: Version of the superblock format @@ -498,171 +588,232 @@ * @j_barrier: The barrier lock itself * @j_running_transaction: The current running transaction.. * @j_committing_transaction: the transaction we are pushing to disk - * @j_checkpoint_transactions: a linked circular list of all transactions waiting for checkpointing - * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction to start committing, or for a barrier lock to be released + * @j_checkpoint_transactions: a linked circular list of all transactions + * waiting for checkpointing + * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction + * to start committing, or for a barrier lock to be released * @j_wait_logspace: Wait queue for waiting for checkpointing to complete * @j_wait_done_commit: Wait queue for waiting for commit to complete * @j_wait_checkpoint: Wait queue to trigger checkpointing * @j_wait_commit: Wait queue to trigger commit * @j_wait_updates: Wait queue to wait for updates to complete * @j_checkpoint_sem: Semaphore for locking against concurrent checkpoints - * @j_sem: The main journal lock, used by lock_journal() * @j_head: Journal head - identifies the first unused block in the journal - * @j_tail: Journal tail - identifies the oldest still-used block in the journal. + * @j_tail: Journal tail - identifies the oldest still-used block in the + * journal. * @j_free: Journal free - how many free blocks are there in the journal? * @j_first: The block number of the first usable block * @j_last: The block number one beyond the last usable block * @j_dev: Device where we store the journal * @j_blocksize: blocksize for the location where we store the journal. - * @j_blk_offset: starting block offset for into the device where we store the journal - * @j_fs_dev: Device which holds the client fs. For internal journal this will be equal to j_dev + * @j_blk_offset: starting block offset for into the device where we store the + * journal + * @j_fs_dev: Device which holds the client fs. For internal journal this will + * be equal to j_dev * @j_maxlen: Total maximum capacity of the journal region on disk. - * @j_inode: Optional inode where we store the journal. If present, all journal block numbers are mapped into this inode via bmap(). + * @j_inode: Optional inode where we store the journal. If present, all journal + * block numbers are mapped into this inode via bmap(). * @j_tail_sequence: Sequence number of the oldest transaction in the log * @j_transaction_sequence: Sequence number of the next transaction to grant - * @j_commit_sequence: Sequence number of the most recently committed transaction - * @j_commit_request: Sequence number of the most recent transaction wanting commit + * @j_commit_sequence: Sequence number of the most recently committed + * transaction + * @j_commit_request: Sequence number of the most recent transaction wanting + * commit * @j_uuid: Uuid of client object. * @j_task: Pointer to the current commit thread for this journal - * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a single compound commit transaction - * @j_commit_interval: What is the maximum transaction lifetime before we begin a commit? + * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a + * single compound commit transaction + * @j_commit_interval: What is the maximum transaction lifetime before we begin + * a commit? * @j_commit_timer: The timer used to wakeup the commit thread - * @j_commit_timer_active: Timer flag - * @j_all_journals: Link all journals together - system-wide - * @j_revoke: The revoke table - maintains the list of revoked blocks in the current transaction. - **/ + * @j_revoke: The revoke table - maintains the list of revoked blocks in the + * current transaction. + */ struct journal_s { - /* General journaling state flags */ + /* General journaling state flags [j_state_lock] */ unsigned long j_flags; - /* Is there an outstanding uncleared error on the journal (from */ - /* a prior abort)? */ + /* + * Is there an outstanding uncleared error on the journal (from a prior + * abort)? [j_state_lock] + */ int j_errno; - + /* The superblock buffer */ - struct buffer_head * j_sb_buffer; - journal_superblock_t * j_superblock; + struct buffer_head *j_sb_buffer; + journal_superblock_t *j_superblock; /* Version of the superblock format */ int j_format_version; - /* Number of processes waiting to create a barrier lock */ + /* + * Protect the various scalars in the journal + */ + spinlock_t j_state_lock; + + /* + * Number of processes waiting to create a barrier lock [j_state_lock] + */ int j_barrier_count; - + /* The barrier lock itself */ struct semaphore j_barrier; - - /* Transactions: The current running transaction... */ - transaction_t * j_running_transaction; - - /* ... the transaction we are pushing to disk ... */ - transaction_t * j_committing_transaction; - - /* ... and a linked circular list of all transactions waiting */ - /* for checkpointing. */ - /* Protected by journal_datalist_lock */ - transaction_t * j_checkpoint_transactions; - /* Wait queue for waiting for a locked transaction to start */ - /* committing, or for a barrier lock to be released */ + /* + * Transactions: The current running transaction... + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_running_transaction; + + /* + * the transaction we are pushing to disk + * [j_state_lock] [caller holding open handle] + */ + transaction_t *j_committing_transaction; + + /* + * ... and a linked circular list of all transactions waiting for + * checkpointing. [j_list_lock] + */ + transaction_t *j_checkpoint_transactions; + + /* + * Wait queue for waiting for a locked transaction to start committing, + * or for a barrier lock to be released + */ wait_queue_head_t j_wait_transaction_locked; - + /* Wait queue for waiting for checkpointing to complete */ wait_queue_head_t j_wait_logspace; - + /* Wait queue for waiting for commit to complete */ wait_queue_head_t j_wait_done_commit; - + /* Wait queue to trigger checkpointing */ wait_queue_head_t j_wait_checkpoint; - + /* Wait queue to trigger commit */ wait_queue_head_t j_wait_commit; - + /* Wait queue to wait for updates to complete */ wait_queue_head_t j_wait_updates; /* Semaphore for locking against concurrent checkpoints */ struct semaphore j_checkpoint_sem; - /* The main journal lock, used by lock_journal() */ - struct semaphore j_sem; - - /* Journal head: identifies the first unused block in the journal. */ + /* + * Journal head: identifies the first unused block in the journal. + * [j_state_lock] + */ unsigned long j_head; - - /* Journal tail: identifies the oldest still-used block in the */ - /* journal. */ + + /* + * Journal tail: identifies the oldest still-used block in the journal. + * [j_state_lock] + */ unsigned long j_tail; - /* Journal free: how many free blocks are there in the journal? */ + /* + * Journal free: how many free blocks are there in the journal? + * [j_state_lock] + */ unsigned long j_free; - /* Journal start and end: the block numbers of the first usable */ - /* block and one beyond the last usable block in the journal. */ - unsigned long j_first, j_last; - - /* Device, blocksize and starting block offset for the location */ - /* where we store the journal. */ - struct block_device * j_dev; + /* + * Journal start and end: the block numbers of the first usable block + * and one beyond the last usable block in the journal. [j_state_lock] + */ + unsigned long j_first; + unsigned long j_last; + + /* + * Device, blocksize and starting block offset for the location where we + * store the journal. + */ + struct block_device *j_dev; int j_blocksize; unsigned int j_blk_offset; - /* Device which holds the client fs. For internal journal this */ - /* will be equal to j_dev. */ - struct block_device * j_fs_dev; + /* + * Device which holds the client fs. For internal journal this will be + * equal to j_dev. + */ + struct block_device *j_fs_dev; /* Total maximum capacity of the journal region on disk. */ unsigned int j_maxlen; + /* + * Protects the buffer lists and internal buffer state. + */ + spinlock_t j_list_lock; + /* Optional inode where we store the journal. If present, all */ /* journal block numbers are mapped into this inode via */ /* bmap(). */ - struct inode * j_inode; + struct inode *j_inode; - /* Sequence number of the oldest transaction in the log */ + /* + * Sequence number of the oldest transaction in the log [j_state_lock] + */ tid_t j_tail_sequence; - /* Sequence number of the next transaction to grant */ + + /* + * Sequence number of the next transaction to grant [j_state_lock] + */ tid_t j_transaction_sequence; - /* Sequence number of the most recently committed transaction */ + + /* + * Sequence number of the most recently committed transaction + * [j_state_lock]. + */ tid_t j_commit_sequence; - /* Sequence number of the most recent transaction wanting commit */ - tid_t j_commit_request; - /* Journal uuid: identifies the object (filesystem, LVM volume */ - /* etc) backed by this journal. This will eventually be */ - /* replaced by an array of uuids, allowing us to index multiple */ - /* devices within a single journal and to perform atomic updates */ - /* across them. */ + /* + * Sequence number of the most recent transaction wanting commit + * [j_state_lock] + */ + tid_t j_commit_request; + /* + * Journal uuid: identifies the object (filesystem, LVM volume etc) + * backed by this journal. This will eventually be replaced by an array + * of uuids, allowing us to index multiple devices within a single + * journal and to perform atomic updates across them. + */ __u8 j_uuid[16]; /* Pointer to the current commit thread for this journal */ - struct task_struct * j_task; + struct task_struct *j_task; - /* Maximum number of metadata buffers to allow in a single */ - /* compound commit transaction */ + /* + * Maximum number of metadata buffers to allow in a single compound + * commit transaction + */ int j_max_transaction_buffers; - /* What is the maximum transaction lifetime before we begin a */ - /* commit? */ + /* + * What is the maximum transaction lifetime before we begin a commit? + */ unsigned long j_commit_interval; /* The timer used to wakeup the commit thread: */ - struct timer_list * j_commit_timer; - int j_commit_timer_active; + struct timer_list *j_commit_timer; - /* Link all journals together - system-wide */ - struct list_head j_all_journals; - - /* The revoke table: maintains the list of revoked blocks in the */ - /* current transaction. */ + /* + * The revoke table: maintains the list of revoked blocks in the + * current transaction. [j_revoke_lock] + */ + spinlock_t j_revoke_lock; struct jbd_revoke_table_s *j_revoke; + struct jbd_revoke_table_s *j_revoke_table[2]; - /* An opaque pointer to fs-private information. ext3 puts its - * superblock pointer here */ + /* + * An opaque pointer to fs-private information. ext3 puts its + * superblock pointer here + */ void *j_private; }; @@ -681,10 +832,10 @@ */ /* Filing buffers */ +extern void journal_unfile_buffer(journal_t *, struct journal_head *); extern void __journal_unfile_buffer(struct journal_head *); -extern void journal_unfile_buffer(struct journal_head *); extern void __journal_refile_buffer(struct journal_head *); -extern void journal_refile_buffer(struct journal_head *); +extern void journal_refile_buffer(journal_t *, struct journal_head *); extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); extern void __journal_free_buffer(struct journal_head *bh); extern void journal_file_buffer(struct journal_head *, transaction_t *, int); @@ -699,10 +850,8 @@ /* Checkpoint list management */ int __journal_clean_checkpoint_list(journal_t *journal); -extern void journal_remove_checkpoint(struct journal_head *); -extern void __journal_remove_checkpoint(struct journal_head *); -extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); -extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); +void __journal_remove_checkpoint(struct journal_head *); +void __journal_insert_checkpoint(struct journal_head *, transaction_t *); /* Buffer IO */ extern int @@ -717,34 +866,14 @@ /* * Journal locking. * - * We need to lock the journal during transaction state changes so that - * nobody ever tries to take a handle on the running transaction while - * we are in the middle of moving it to the commit phase. + * We need to lock the journal during transaction state changes so that nobody + * ever tries to take a handle on the running transaction while we are in the + * middle of moving it to the commit phase. j_state_lock does this. * * Note that the locking is completely interrupt unsafe. We never touch * journal structures from interrupts. - * - * In 2.2, the BKL was required for lock_journal. This is no longer - * the case. */ -static inline void lock_journal(journal_t *journal) -{ - down(&journal->j_sem); -} - -/* This returns zero if we acquired the semaphore */ -static inline int try_lock_journal(journal_t * journal) -{ - return down_trylock(&journal->j_sem); -} - -static inline void unlock_journal(journal_t * journal) -{ - up(&journal->j_sem); -} - - static inline handle_t *journal_current_handle(void) { return current->journal_info; @@ -759,12 +888,15 @@ extern handle_t *journal_start(journal_t *, int nblocks); extern int journal_restart (handle_t *, int nblocks); extern int journal_extend (handle_t *, int nblocks); -extern int journal_get_write_access (handle_t *, struct buffer_head *); +extern int journal_get_write_access(handle_t *, struct buffer_head *, + int *credits); extern int journal_get_create_access (handle_t *, struct buffer_head *); -extern int journal_get_undo_access (handle_t *, struct buffer_head *); +extern int journal_get_undo_access(handle_t *, struct buffer_head *, + int *credits); extern int journal_dirty_data (handle_t *, struct buffer_head *); extern int journal_dirty_metadata (handle_t *, struct buffer_head *); -extern void journal_release_buffer (handle_t *, struct buffer_head *); +extern void journal_release_buffer (handle_t *, struct buffer_head *, + int credits); extern void journal_forget (handle_t *, struct buffer_head *); extern void journal_sync_buffer (struct buffer_head *); extern int journal_invalidatepage(journal_t *, @@ -809,11 +941,10 @@ /* * journal_head management */ -extern struct journal_head - *journal_add_journal_head(struct buffer_head *bh); -extern void journal_remove_journal_head(struct buffer_head *bh); -extern void __journal_remove_journal_head(struct buffer_head *bh); -extern void journal_unlock_journal_head(struct journal_head *jh); +struct journal_head *journal_add_journal_head(struct buffer_head *bh); +struct journal_head *journal_grab_journal_head(struct buffer_head *bh); +void journal_remove_journal_head(struct buffer_head *bh); +void journal_put_journal_head(struct journal_head *jh); /* * handle management @@ -843,29 +974,30 @@ extern void journal_write_revoke_records(journal_t *, transaction_t *); /* Recovery revoke support */ -extern int journal_set_revoke(journal_t *, unsigned long, tid_t); -extern int journal_test_revoke(journal_t *, unsigned long, tid_t); -extern void journal_clear_revoke(journal_t *); -extern void journal_brelse_array(struct buffer_head *b[], int n); +extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +extern void journal_clear_revoke(journal_t *); +extern void journal_brelse_array(struct buffer_head *b[], int n); +extern void journal_switch_revoke_table(journal_t *journal); -/* The log thread user interface: +/* + * The log thread user interface: * * Request space in the current transaction, and force transaction commit * transitions on demand. */ -extern int log_space_left (journal_t *); /* Called with journal locked */ -extern tid_t log_start_commit (journal_t *, transaction_t *); -extern int log_wait_commit (journal_t *, tid_t); -extern int log_do_checkpoint (journal_t *, int); +int __log_space_left(journal_t *); /* Called with journal locked */ +int log_start_commit(journal_t *journal, tid_t tid); +int __log_start_commit(journal_t *journal, tid_t tid); +int journal_start_commit(journal_t *journal, tid_t *tid); +int log_wait_commit(journal_t *journal, tid_t tid); +int log_do_checkpoint(journal_t *journal, int nblocks); -extern void log_wait_for_space(journal_t *, int nblocks); +void __log_wait_for_space(journal_t *journal, int nblocks); extern void __journal_drop_transaction(journal_t *, transaction_t *); extern int cleanup_journal_tail(journal_t *); -/* Reduce journal memory usage by flushing */ -extern void shrink_journal_memory(void); - /* Debugging code only: */ #define jbd_ENOSYS() \ @@ -940,50 +1072,6 @@ #ifdef __KERNEL__ -extern spinlock_t jh_splice_lock; -/* - * Once `expr1' has been found true, take jh_splice_lock - * and then reevaluate everything. - */ -#define SPLICE_LOCK(expr1, expr2) \ - ({ \ - int ret = (expr1); \ - if (ret) { \ - spin_lock(&jh_splice_lock); \ - ret = (expr1) && (expr2); \ - spin_unlock(&jh_splice_lock); \ - } \ - ret; \ - }) - -/* - * A number of buffer state predicates. They test for - * buffer_jbd() because they are used in core kernel code. - * - * These will be racy on SMP unless we're *sure* that the - * buffer won't be detached from the journalling system - * in parallel. - */ - -/* Return true if the buffer is on journal list `list' */ -static inline int buffer_jlist_eq(struct buffer_head *bh, int list) -{ - return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list); -} - -/* Return true if this bufer is dirty wrt the journal */ -static inline int buffer_jdirty(struct buffer_head *bh) -{ - return buffer_jbd(bh) && buffer_jbddirty(bh); -} - -/* Return true if it's a data buffer which journalling is managing */ -static inline int buffer_jbd_data(struct buffer_head *bh) -{ - return SPLICE_LOCK(buffer_jbd(bh), - bh2jh(bh)->b_jlist == BJ_SyncData); -} - #ifdef CONFIG_SMP #define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock)) #else @@ -1011,7 +1099,6 @@ #define J_ASSERT(expr) do {} while (0) #define J_ASSERT_BH(bh, expr) do {} while (0) #define buffer_jbd(bh) 0 -#define buffer_jlist_eq(bh, val) 0 #define journal_buffer_journal_lru(bh) 0 #endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */ diff -Nru a/include/linux/journal-head.h b/include/linux/journal-head.h --- a/include/linux/journal-head.h Tue Feb 5 12:32:38 2002 +++ b/include/linux/journal-head.h Tue Jun 17 23:04:00 2003 @@ -3,7 +3,7 @@ * * buffer_head fields for JBD * - * 27 May 2001 ANdrew Morton + * 27 May 2001 Andrew Morton * Created - pulled out of fs.h */ @@ -15,55 +15,70 @@ struct buffer_head; struct journal_head { -#ifndef CONFIG_JBD_UNIFIED_BUFFERS - /* Points back to our buffer_head. */ + /* + * Points back to our buffer_head. [jbd_lock_bh_journal_head()] + */ struct buffer_head *b_bh; -#endif - /* Reference count - see description in journal.c */ + /* + * Reference count - see description in journal.c + * [jbd_lock_bh_journal_head()] + */ int b_jcount; - /* Journaling list for this buffer */ + /* + * Journalling list for this buffer [jbd_lock_bh_state()] + */ unsigned b_jlist; - /* Copy of the buffer data frozen for writing to the log. */ - char * b_frozen_data; + /* + * Copy of the buffer data frozen for writing to the log. + * [jbd_lock_bh_state()] + */ + char *b_frozen_data; + + /* + * Pointer to a saved copy of the buffer containing no uncommitted + * deallocation references, so that allocations can avoid overwriting + * uncommitted deletes. [jbd_lock_bh_state()] + */ + char *b_committed_data; + + /* + * Pointer to the compound transaction which owns this buffer's + * metadata: either the running transaction or the committing + * transaction (if there is one). Only applies to buffers on a + * transaction's data or metadata journaling list. + * [j_list_lock] [jbd_lock_bh_state()] + */ + transaction_t *b_transaction; + + /* + * Pointer to the running compound transaction which is currently + * modifying the buffer's metadata, if there was already a transaction + * committing it when the new transaction touched it. + * [t_list_lock] [jbd_lock_bh_state()] + */ + transaction_t *b_next_transaction; - /* Pointer to a saved copy of the buffer containing no - uncommitted deallocation references, so that allocations can - avoid overwriting uncommitted deletes. */ - char * b_committed_data; - - /* Pointer to the compound transaction which owns this buffer's - metadata: either the running transaction or the committing - transaction (if there is one). Only applies to buffers on a - transaction's data or metadata journaling list. */ - /* Protected by journal_datalist_lock */ - transaction_t * b_transaction; - - /* Pointer to the running compound transaction which is - currently modifying the buffer's metadata, if there was - already a transaction committing it when the new transaction - touched it. */ - transaction_t * b_next_transaction; - - /* Doubly-linked list of buffers on a transaction's data, - metadata or forget queue. */ - /* Protected by journal_datalist_lock */ + /* + * Doubly-linked list of buffers on a transaction's data, metadata or + * forget queue. [t_list_lock] [jbd_lock_bh_state()] + */ struct journal_head *b_tnext, *b_tprev; /* * Pointer to the compound transaction against which this buffer * is checkpointed. Only dirty buffers can be checkpointed. + * [j_list_lock] */ - /* Protected by journal_datalist_lock */ - transaction_t * b_cp_transaction; - + transaction_t *b_cp_transaction; + /* * Doubly-linked list of buffers still remaining to be flushed * before an old transaction can be checkpointed. + * [j_list_lock] */ - /* Protected by journal_datalist_lock */ struct journal_head *b_cpnext, *b_cpprev; }; diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Sun Jun 15 01:21:45 2003 +++ b/include/linux/netdevice.h Thu Jun 19 14:25:16 2003 @@ -195,8 +195,14 @@ int hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); rwlock_t hh_lock; + /* cached hardware header; allow for machine alignment needs. */ - unsigned long hh_data[16/sizeof(unsigned long)]; +#define HH_DATA_MOD 16 +#define HH_DATA_OFF(__len) \ + (HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1))) +#define HH_DATA_ALIGN(__len) \ + (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) + unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER)]; }; /* These flag bits are private to the generic network queueing diff -Nru a/include/linux/netfilter_arp.h b/include/linux/netfilter_arp.h --- a/include/linux/netfilter_arp.h Fri Mar 15 02:12:06 2002 +++ b/include/linux/netfilter_arp.h Thu Jun 19 12:42:06 2003 @@ -14,6 +14,7 @@ /* ARP Hooks */ #define NF_ARP_IN 0 #define NF_ARP_OUT 1 -#define NF_ARP_NUMHOOKS 2 +#define NF_ARP_FORWARD 2 +#define NF_ARP_NUMHOOKS 3 #endif /* __LINUX_ARP_NETFILTER_H */ diff -Nru a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h --- a/include/linux/nfsd/nfsd.h Mon May 19 23:34:37 2003 +++ b/include/linux/nfsd/nfsd.h Tue Jun 17 16:30:53 2003 @@ -69,6 +69,8 @@ int fh_lock_parent(struct svc_fh *, struct dentry *); int nfsd_racache_init(int); void nfsd_racache_shutdown(void); +int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); int nfsd_lookup(struct svc_rqst *, struct svc_fh *, const char *, int, struct svc_fh *); int nfsd_setattr(struct svc_rqst *, struct svc_fh *, @@ -226,6 +228,7 @@ #define COMPOUND_ERR_SLACK_SPACE 12 /* OP_SETATTR */ #define NFSD_LEASE_TIME 60 /* seconds */ +#define NFSD_LAUNDROMAT_MINTIMEOUT 10 /* seconds */ /* * The following attributes are currently not supported by the NFSv4 server: diff -Nru a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h --- a/include/linux/nfsd/state.h Mon May 19 23:34:37 2003 +++ b/include/linux/nfsd/state.h Tue Jun 17 16:30:53 2003 @@ -73,13 +73,18 @@ struct list_head cl_idhash; /* hash by cl_clientid.id */ struct list_head cl_strhash; /* hash by cl_name */ struct list_head cl_perclient; /* list: stateowners */ + struct list_head cl_lru; /* tail queue */ struct xdr_netobj cl_name; /* id generated by client */ nfs4_verifier cl_verifier; /* generated by client */ + time_t cl_time; /* time of last lease renewal */ u32 cl_addr; /* client ipaddress */ struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ }; + +extern time_t nfs4_laundromat(void); +int nfsd4_renew(clientid_t *clid); static inline void update_stateid(stateid_t *stateid) diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Tue Jun 10 23:33:25 2003 +++ b/include/linux/page-flags.h Tue Jun 17 23:04:16 2003 @@ -200,6 +200,7 @@ #define PageChecked(page) test_bit(PG_checked, &(page)->flags) #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) +#define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags) #define PageReserved(page) test_bit(PG_reserved, &(page)->flags) #define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Fri Jun 13 01:03:43 2003 +++ b/include/linux/pci_ids.h Wed Jun 18 06:32:49 2003 @@ -602,6 +602,8 @@ #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A #define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B +#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0 +#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 #define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b #define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 #define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 diff -Nru a/include/linux/pnp.h b/include/linux/pnp.h --- a/include/linux/pnp.h Thu Apr 10 06:38:19 2003 +++ b/include/linux/pnp.h Wed Jun 18 15:22:43 2003 @@ -102,22 +102,13 @@ #define PNP_RES_PRIORITY_FUNCTIONAL 2 #define PNP_RES_PRIORITY_INVALID 65535 -struct pnp_resources { +struct pnp_option { unsigned short priority; /* priority */ struct pnp_port *port; /* first port */ struct pnp_irq *irq; /* first IRQ */ struct pnp_dma *dma; /* first DMA */ struct pnp_mem *mem; /* first memory resource */ - struct pnp_dev *dev; /* parent */ - struct pnp_resources *dep; /* dependent resources */ -}; - -struct pnp_rule_table { - int depnum; - struct pnp_port *port[PNP_MAX_PORT]; - struct pnp_irq *irq[PNP_MAX_IRQ]; - struct pnp_dma *dma[PNP_MAX_DMA]; - struct pnp_mem *mem[PNP_MAX_MEM]; + struct pnp_option *next; /* used to chain dependent resources */ }; struct pnp_resource_table { @@ -187,8 +178,6 @@ struct pnp_dev { struct device dev; /* Driver Model device interface */ unsigned char number; /* used as an index, must be unique */ - int active; - int capabilities; int status; struct list_head global_list; /* node in global list of devices */ @@ -201,11 +190,13 @@ struct pnp_driver * driver; struct pnp_card_link * card_link; - struct pnp_id * id; /* supported EISA IDs*/ - struct pnp_resource_table res; /* contains the currently chosen resources */ - struct pnp_resources * possible; /* a list of possible resources */ - struct pnp_rule_table * rule; /* the current possible resource set */ - int config_mode; /* flags that determine how the device's resources should be configured */ + struct pnp_id * id; /* supported EISA IDs*/ + + int active; + int capabilities; + struct pnp_option * independent; + struct pnp_option * dependent; + struct pnp_resource_table res; void * protocol_data; /* Used to store protocol specific data */ unsigned short regs; /* ISAPnP: supported registers */ @@ -252,11 +243,9 @@ void (*quirk_function)(struct pnp_dev *dev); /* fixup function */ }; -/* config modes */ -#define PNP_CONFIG_AUTO 0x0001 /* Use the Resource Configuration Engine to determine resource settings */ -#define PNP_CONFIG_MANUAL 0x0002 /* the config has been manually specified */ -#define PNP_CONFIG_FORCE 0x0004 /* disables validity checking */ -#define PNP_CONFIG_INVALID 0x0008 /* If this flag is set, the pnp layer will refuse to activate the device */ +/* config parameters */ +#define PNP_CONFIG_NORMAL 0x0001 +#define PNP_CONFIG_FORCE 0x0002 /* disables validity checking */ /* capabilities */ #define PNP_READ 0x0001 @@ -271,7 +260,7 @@ ((dev)->capabilities & PNP_WRITE)) #define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \ ((dev)->capabilities & PNP_DISABLE)) -#define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->config_mode & PNP_CONFIG_AUTO) && \ +#define pnp_can_configure(dev) ((!(dev)->active) && \ ((dev)->capabilities & PNP_CONFIGURABLE)) #ifdef CONFIG_ISAPNP @@ -383,7 +372,7 @@ #if defined(CONFIG_PNP) -/* core */ +/* device management */ int pnp_register_protocol(struct pnp_protocol *protocol); void pnp_unregister_protocol(struct pnp_protocol *protocol); int pnp_add_device(struct pnp_dev *dev); @@ -392,7 +381,7 @@ void pnp_device_detach(struct pnp_dev *pnp_dev); extern struct list_head pnp_global; -/* card */ +/* multidevice card support */ int pnp_add_card(struct pnp_card *card); void pnp_remove_card(struct pnp_card *card); int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); @@ -404,41 +393,35 @@ void pnp_unregister_card_driver(struct pnp_card_driver * drv); extern struct list_head pnp_cards; -/* resource */ -struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent); -struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum); -int pnp_get_max_depnum(struct pnp_dev *dev); -int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data); -int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data); -int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data); -int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data); -void pnp_init_resource_table(struct pnp_resource_table *table); -int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule); - -/* manager */ +/* resource management */ +struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev); +struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority); +int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data); +int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data); +int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data); +int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data); +void pnp_init_resources(struct pnp_resource_table *table); +int pnp_assign_resources(struct pnp_dev *dev, int depnum); +int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); +int pnp_auto_config_dev(struct pnp_dev *dev); +int pnp_validate_config(struct pnp_dev *dev); int pnp_activate_dev(struct pnp_dev *dev); int pnp_disable_dev(struct pnp_dev *dev); void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size); -int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode); -int pnp_auto_config_dev(struct pnp_dev *dev); - -/* driver */ -int compare_pnp_id(struct pnp_id * pos, const char * id); -int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); -int pnp_register_driver(struct pnp_driver *drv); -void pnp_unregister_driver(struct pnp_driver *drv); -/* support */ +/* protocol helpers */ int pnp_is_active(struct pnp_dev * dev); unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev); unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res); +int compare_pnp_id(struct pnp_id * pos, const char * id); +int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev); +int pnp_register_driver(struct pnp_driver *drv); +void pnp_unregister_driver(struct pnp_driver *drv); #else -/* just in case anyone decides to call these without PnP Support Enabled */ - -/* core */ +/* device management */ static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; } static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } @@ -447,7 +430,7 @@ static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; } -/* card */ +/* multidevice card support */ static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; } static inline void pnp_remove_card(struct pnp_card *card) { ; } static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; } @@ -458,35 +441,31 @@ static inline int pnp_register_card_driver(struct pnp_card_driver * drv) { return -ENODEV; } static inline void pnp_unregister_card_driver(struct pnp_card_driver * drv) { ; } -/* resource */ -static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; } -static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; } -static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; } -static inline void pnp_init_resource_table(struct pnp_resource_table *table) { ; } -static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { return -ENODEV; } - -/* manager */ -static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; } +/* resource management */ +static inline struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { return NULL; } +static inline struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; } +static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; } +static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; } +static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; } +static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; } +static inline void pnp_init_resources(struct pnp_resource_table *table) { } +static inline int pnp_assign_resources(struct pnp_dev *dev, int depnum) { return -ENODEV; } static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; } static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; } +static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { } -/* driver */ -static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; } -static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } -static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } -static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } - -/* support */ -static inline int pnp_is_active(struct pnp_dev * dev) { return -ENODEV; } +/* protocol helpers */ +static inline int pnp_is_active(struct pnp_dev * dev) { return 0; } static inline unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } static inline unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev) { return NULL; } static inline unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; } +static inline int compare_pnp_id(struct pnp_id * pos, const char * id) { return -ENODEV; } +static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; } +static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; } +static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; } #endif /* CONFIG_PNP */ diff -Nru a/include/linux/rmap-locking.h b/include/linux/rmap-locking.h --- a/include/linux/rmap-locking.h Sun Jan 5 07:28:46 2003 +++ b/include/linux/rmap-locking.h Tue Jun 17 23:03:51 2003 @@ -10,32 +10,8 @@ struct pte_chain; extern kmem_cache_t *pte_chain_cache; -static inline void pte_chain_lock(struct page *page) -{ - /* - * Assuming the lock is uncontended, this never enters - * the body of the outer loop. If it is contended, then - * within the inner loop a non-atomic test is used to - * busywait with less bus contention for a good time to - * attempt to acquire the lock bit. - */ - preempt_disable(); -#ifdef CONFIG_SMP - while (test_and_set_bit(PG_chainlock, &page->flags)) { - while (test_bit(PG_chainlock, &page->flags)) - cpu_relax(); - } -#endif -} - -static inline void pte_chain_unlock(struct page *page) -{ -#ifdef CONFIG_SMP - smp_mb__before_clear_bit(); - clear_bit(PG_chainlock, &page->flags); -#endif - preempt_enable(); -} +#define pte_chain_lock(page) bit_spin_lock(PG_chainlock, &page->flags) +#define pte_chain_unlock(page) bit_spin_unlock(PG_chainlock, &page->flags) struct pte_chain *pte_chain_alloc(int gfp_flags); void __pte_chain_free(struct pte_chain *pte_chain); diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h --- a/include/linux/skbuff.h Sun May 25 21:37:30 2003 +++ b/include/linux/skbuff.h Thu Jun 19 12:40:53 2003 @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -802,12 +803,9 @@ skb_shinfo(skb)->nr_frags = i+1; } -#define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \ - BUG(); } while (0) -#define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \ - BUG(); } while (0) -#define SKB_LINEAR_ASSERT(skb) do { if (skb_is_nonlinear(skb)) \ - BUG(); } while (0) +#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) +#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_shinfo(skb)->frag_list) +#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) /* * Add data to an sk_buff @@ -836,7 +834,7 @@ SKB_LINEAR_ASSERT(skb); skb->tail += len; skb->len += len; - if (skb->tail>skb->end) + if (unlikely(skb->tail>skb->end)) skb_over_panic(skb, len, current_text_addr()); return tmp; } @@ -861,7 +859,7 @@ { skb->data -= len; skb->len += len; - if (skb->datahead) + if (unlikely(skb->datahead)) skb_under_panic(skb, len, current_text_addr()); return skb->data; } @@ -869,8 +867,7 @@ static inline char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; - if (skb->len < skb->data_len) - BUG(); + BUG_ON(skb->len < skb->data_len); return skb->data += len; } @@ -1127,13 +1124,16 @@ * If there is no free memory -ENOMEM is returned, otherwise zero * is returned and the old skb data released. */ -int skb_linearize(struct sk_buff *skb, int gfp); +extern int __skb_linearize(struct sk_buff *skb, int gfp); +static inline int __deprecated skb_linearize(struct sk_buff *skb, int gfp) +{ + return __skb_linearize(skb, gfp); +} static inline void *kmap_skb_frag(const skb_frag_t *frag) { #ifdef CONFIG_HIGHMEM - if (in_irq()) - BUG(); + BUG_ON(in_irq()); local_bh_disable(); #endif @@ -1149,9 +1149,9 @@ } #define skb_queue_walk(queue, skb) \ - for (skb = (queue)->next; \ + for (skb = (queue)->next, prefetch(skb->next); \ (skb != (struct sk_buff *)(queue)); \ - skb = skb->next) + skb = skb->next, prefetch(skb->next)) extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h --- a/include/linux/spinlock.h Sat Jun 7 05:39:11 2003 +++ b/include/linux/spinlock.h Tue Jun 17 23:03:51 2003 @@ -395,4 +395,74 @@ extern int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #endif +/* + * bit-based spin_lock() + * + * Don't use this unless you really need to: spin_lock() and spin_unlock() + * are significantly faster. + */ +static inline void bit_spin_lock(int bitnum, unsigned long *addr) +{ + /* + * Assuming the lock is uncontended, this never enters + * the body of the outer loop. If it is contended, then + * within the inner loop a non-atomic test is used to + * busywait with less bus contention for a good time to + * attempt to acquire the lock bit. + */ + preempt_disable(); +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + while (test_and_set_bit(bitnum, addr)) { + while (test_bit(bitnum, addr)) + cpu_relax(); + } +#endif +} + +/* + * Return true if it was acquired + */ +static inline int bit_spin_trylock(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + int ret; + + preempt_disable(); + ret = !test_and_set_bit(bitnum, addr); + if (!ret) + preempt_enable(); + return ret; +#else + preempt_disable(); + return 1; +#endif +} + +/* + * bit-based spin_unlock() + */ +static inline void bit_spin_unlock(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + BUG_ON(!test_bit(bitnum, addr)); + smp_mb__before_clear_bit(); + clear_bit(bitnum, addr); +#endif + preempt_enable(); +} + +/* + * Return true if the lock is held. + */ +static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) +{ +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) + return test_bit(bitnum, addr); +#elif defined CONFIG_PREEMPT + return preempt_count(); +#else + return 1; +#endif +} + #endif /* __LINUX_SPINLOCK_H */ diff -Nru a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h --- a/include/linux/sunrpc/cache.h Tue Mar 11 20:03:48 2003 +++ b/include/linux/sunrpc/cache.h Tue Jun 17 16:18:16 2003 @@ -115,6 +115,8 @@ struct list_head recent; /* on fifo */ struct cache_head *item; /* cache item we wait on */ time_t recv_time; + void *owner; /* we might need to discard all defered requests + * owned by someone */ void (*revisit)(struct cache_deferred_req *req, int too_many); }; @@ -168,12 +170,14 @@ tmp = container_of(*hp, RTN, MEMBER); \ if (TEST) { /* found a match */ \ \ + if (set == 1 && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \ + break; \ + \ atomic_inc(&tmp->MEMBER.refcnt); \ if (set) { \ - if (set!= 2 && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ + if (set == 1 && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\ { /* need to swap in new */ \ RTN *t2; \ - if (!new) break; \ \ new->MEMBER.next = tmp->MEMBER.next; \ *hp = &new->MEMBER; \ @@ -242,6 +246,7 @@ extern void cache_defer_req(struct cache_req *req, struct cache_head *item); extern void cache_revisit_request(struct cache_head *item); +extern void cache_clean_deferred(void *owner); static inline struct cache_head *cache_get(struct cache_head *h) { diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h --- a/include/linux/sunrpc/svc.h Tue May 6 07:20:53 2003 +++ b/include/linux/sunrpc/svc.h Tue Jun 17 16:31:29 2003 @@ -125,7 +125,6 @@ u32 rq_proc; /* procedure number */ u32 rq_prot; /* IP protocol */ unsigned short - rq_userset : 1, /* auth->setuser OK */ rq_secure : 1; /* secure port */ @@ -196,14 +195,14 @@ static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp) { - while (rqstp->rq_resused) { + while (rqstp->rq_resused && + rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) { + if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) { rqstp->rq_argpages[rqstp->rq_arghi++] = rqstp->rq_respages[rqstp->rq_resused]; rqstp->rq_respages[rqstp->rq_resused] = NULL; } - if (rqstp->rq_res.pages == &rqstp->rq_respages[rqstp->rq_resused]) - break; } } @@ -218,7 +217,6 @@ } struct svc_deferred_req { - struct svc_serv *serv; u32 prot; /* protocol (UDP or TCP) */ struct sockaddr_in addr; struct svc_sock *svsk; /* where reply must go */ diff -Nru a/include/linux/sysdev.h b/include/linux/sysdev.h --- a/include/linux/sysdev.h Wed Jun 11 15:42:05 2003 +++ b/include/linux/sysdev.h Mon Jun 16 10:07:04 2003 @@ -72,7 +72,6 @@ u32 id; struct sysdev_class * cls; struct kobject kobj; - struct list_head entry; }; extern int sys_device_register(struct sys_device *); diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h --- a/include/linux/tcp.h Fri Jun 6 07:22:29 2003 +++ b/include/linux/tcp.h Tue Jun 17 09:35:27 2003 @@ -219,7 +219,7 @@ __u32 snd_sml; /* Last byte of the most recently transmitted small packet */ __u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ __u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ - + struct tcp_bind_bucket *bind_hash; /* Delayed ACK control data */ struct { __u8 pending; /* ACK is pending */ diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Tue Jun 10 09:36:13 2003 +++ b/include/linux/usb.h Thu Jun 12 07:28:01 2003 @@ -492,8 +492,9 @@ */ #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */ #define URB_ISO_ASAP 0x0002 /* iso-only, urb->start_frame ignored */ -#define URB_NO_DMA_MAP 0x0004 /* urb->*_dma are valid on submit */ -#define URB_ASYNC_UNLINK 0x0008 /* usb_unlink_urb() returns asap */ +#define URB_NO_TRANSFER_DMA_MAP 0x0004 /* urb->transfer_dma valid on submit */ +#define URB_NO_SETUP_DMA_MAP 0x0008 /* urb->setup_dma valid on submit */ +#define URB_ASYNC_UNLINK 0x0010 /* usb_unlink_urb() returns asap */ #define URB_NO_FSBR 0x0020 /* UHCI-specific */ #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUTs with short packet */ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */ @@ -531,14 +532,15 @@ * submission, unlinking, or operation are handled. Different * kinds of URB can use different flags. * @transfer_buffer: This identifies the buffer to (or from) which - * the I/O request will be performed (unless URB_NO_DMA_MAP is set). - * This buffer must be suitable for DMA; allocate it with kmalloc() - * or equivalent. For transfers to "in" endpoints, contents of - * this buffer will be modified. This buffer is used for data + * the I/O request will be performed (unless URB_NO_TRANSFER_DMA_MAP + * is set). This buffer must be suitable for DMA; allocate it with + * kmalloc() or equivalent. For transfers to "in" endpoints, contents + * of this buffer will be modified. This buffer is used for data * phases of control transfers. - * @transfer_dma: When transfer_flags includes URB_NO_DMA_MAP, the device - * driver is saying that it provided this DMA address, which the host - * controller driver should use instead of the transfer_buffer. + * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, + * the device driver is saying that it provided this DMA address, + * which the host controller driver should use in preference to the + * transfer_buffer. * @transfer_buffer_length: How big is transfer_buffer. The transfer may * be broken up into chunks according to the current maximum packet * size for the endpoint, which is a function of the configuration @@ -553,11 +555,10 @@ * @setup_packet: Only used for control transfers, this points to eight bytes * of setup data. Control transfers always start by sending this data * to the device. Then transfer_buffer is read or written, if needed. - * (Not used when URB_NO_DMA_MAP is set.) - * @setup_dma: For control transfers with URB_NO_DMA_MAP set, the device - * driver has provided this DMA address for the setup packet. The - * host controller driver should use this instead of setup_buffer. - * If there is a data phase, its buffer is identified by transfer_dma. + * @setup_dma: For control transfers with URB_NO_SETUP_DMA_MAP set, the + * device driver has provided this DMA address for the setup packet. + * The host controller driver should use this in preference to + * setup_packet. * @start_frame: Returns the initial frame for interrupt or isochronous * transfers. * @number_of_packets: Lists the number of ISO transfer buffers. @@ -589,13 +590,15 @@ * bounce buffer or talking to an IOMMU), * although they're cheap on commodity x86 and ppc hardware. * - * Alternatively, drivers may pass the URB_NO_DMA_MAP transfer flag, which - * tells the host controller driver that no such mapping is needed since - * the device driver is DMA-aware. For example, they might allocate a DMA - * buffer with usb_buffer_alloc(), or call usb_buffer_map(). - * When this transfer flag is provided, host controller drivers will use the - * dma addresses found in the transfer_dma and/or setup_dma fields rather than - * determing a dma address themselves. + * Alternatively, drivers may pass the URB_NO_xxx_DMA_MAP transfer flags, + * which tell the host controller driver that no such mapping is needed since + * the device driver is DMA-aware. For example, a device driver might + * allocate a DMA buffer with usb_buffer_alloc() or call usb_buffer_map(). + * When these transfer flags are provided, host controller drivers will + * attempt to use the dma addresses found in the transfer_dma and/or + * setup_dma fields rather than determining a dma address themselves. (Note + * that transfer_buffer and setup_packet must still be set because not all + * host controllers use DMA, nor do virtual root hubs). * * Initialization: * @@ -614,7 +617,11 @@ * should always terminate with a short packet, even if it means adding an * extra zero length packet. * - * Control URBs must provide a setup_packet. + * Control URBs must provide a setup_packet. The setup_packet and + * transfer_buffer may each be mapped for DMA or not, independently of + * the other. The transfer_flags bits URB_NO_TRANSFER_DMA_MAP and + * URB_NO_SETUP_DMA_MAP indicate which buffers have already been mapped. + * URB_NO_SETUP_DMA_MAP is ignored for non-control URBs. * * Interrupt UBS must provide an interval, saying how often (in milliseconds * or, for highspeed devices, 125 microsecond units) diff -Nru a/include/net/llc_pdu.h b/include/net/llc_pdu.h --- a/include/net/llc_pdu.h Wed Sep 11 09:46:42 2002 +++ b/include/net/llc_pdu.h Wed Jun 18 19:15:16 2003 @@ -39,8 +39,8 @@ #define LLC_PDU_CMD_RSP_MASK 0x01 #define LLC_PDU_CMD 0 #define LLC_PDU_RSP 1 -#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) -#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) +#define LLC_PDU_IS_CMD(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1) +#define LLC_PDU_IS_RSP(pdu) ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0) /* Get PDU type from 2 lowest-order bits of control field first byte */ #define LLC_PDU_TYPE_I_MASK 0x01 /* 16-bit control field */ @@ -53,18 +53,18 @@ #define LLC_PDU_TYPE_U 3 /* first two bits */ #define LLC_PDU_TYPE_IS_I(pdu) \ - ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 0 : 1) + ((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 1 : 0) #define LLC_PDU_TYPE_IS_U(pdu) \ - (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 0 : 1) + (((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 1 : 0) #define LLC_PDU_TYPE_IS_S(pdu) \ - (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 0 : 1) + (((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 1 : 0) /* U-format PDU control field masks */ #define LLC_U_PF_BIT_MASK 0x10 /* P/F bit mask */ -#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 0 : 1) -#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 0 : 1) +#define LLC_U_PF_IS_1(pdu) ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 1 : 0) +#define LLC_U_PF_IS_0(pdu) ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 1 : 0) #define LLC_U_PDU_CMD_MASK 0xEC /* cmd/rsp mask */ #define LLC_U_PDU_CMD(pdu) (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK) @@ -119,8 +119,8 @@ #define LLC_I_PF_BIT_MASK 0x01 -#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 0 : 1) -#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 0 : 1) +#define LLC_I_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 1 : 0) +#define LLC_I_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 1 : 0) /* S-PDU supervisory commands and responses */ @@ -136,8 +136,8 @@ #define LLC_2_PDU_RSP_RNR 0x04 /* rx not ready rsp */ #define LLC_S_PF_BIT_MASK 0x01 -#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 0 : 1) -#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 0 : 1) +#define LLC_S_PF_IS_0(pdu) ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 1 : 0) +#define LLC_S_PF_IS_1(pdu) ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 1 : 0) #define PDU_SUPV_GET_Nr(pdu) ((pdu->ctrl_2 & 0xFE) >> 1) #define PDU_GET_NEXT_Vr(sn) (++sn & ~LLC_2_SEQ_NBR_MODULO) diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h --- a/include/net/sctp/structs.h Mon Jun 16 08:11:36 2003 +++ b/include/net/sctp/structs.h Tue Jun 17 09:35:27 2003 @@ -313,6 +313,7 @@ /* What is our base endpointer? */ struct sctp_endpoint *ep; + struct sctp_bind_bucket *bind_hash; /* Various Socket Options. */ __u16 default_stream; __u32 default_ppid; diff -Nru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h Mon Jun 16 08:11:36 2003 +++ b/include/net/sock.h Wed Jun 18 13:59:01 2003 @@ -133,7 +133,6 @@ * @sk_forward_alloc - space allocated forward * @sk_allocation - allocation mode * @sk_sndbuf - size of send buffer in bytes - * @sk_prev - pointer to previous sock in the list this sock is in * @sk_flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings * @sk_no_check - %SO_NO_CHECK setting, wether or not checkup packets * @sk_debug - %SO_DEBUG setting @@ -206,7 +205,6 @@ int sk_forward_alloc; unsigned int sk_allocation; int sk_sndbuf; - struct sock *sk_prev; unsigned long sk_flags; char sk_no_check; unsigned char sk_debug; @@ -291,19 +289,51 @@ node->pprev = NULL; } -static __inline__ int sk_del_node_init(struct sock *sk) +static __inline__ void __sk_del_node(struct sock *sk) +{ + __hlist_del(&sk->sk_node); +} + +static __inline__ int __sk_del_node_init(struct sock *sk) { if (sk_hashed(sk)) { - __hlist_del(&sk->sk_node); + __sk_del_node(sk); sk_node_init(&sk->sk_node); return 1; } return 0; } -static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) +static inline void __sock_put(struct sock *sk); + +static __inline__ int sk_del_node_init(struct sock *sk) +{ + int rc = __sk_del_node_init(sk); + + if (rc) { + /* paranoid for a while -acme */ + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + return rc; +} + +static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list) { hlist_add_head(&sk->sk_node, list); +} + +static inline void sock_hold(struct sock *sk); + +static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) +{ + sock_hold(sk); + __sk_add_node(sk, list); +} + +static __inline__ void __sk_del_bind_node(struct sock *sk) +{ + __hlist_del(&sk->sk_bind_node); } static __inline__ void sk_add_bind_node(struct sock *sk, diff -Nru a/include/net/syncppp.h b/include/net/syncppp.h --- a/include/net/syncppp.h Mon Feb 4 23:40:24 2002 +++ b/include/net/syncppp.h Fri May 30 12:35:20 2003 @@ -48,6 +48,7 @@ struct timer_list pp_timer; struct net_device *pp_if; char pp_link_state; /* Link status */ + spinlock_t lock; }; struct ppp_device diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Mon Jun 16 11:44:09 2003 +++ b/include/net/tcp.h Tue Jun 17 09:35:27 2003 @@ -1475,7 +1475,8 @@ TCP_INC_STATS(TcpEstabResets); sk->sk_prot->unhash(sk); - if (sk->sk_prev && !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) + if (tcp_sk(sk)->bind_hash && + !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) tcp_put_port(sk); /* fall through */ default: diff -Nru a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_cmnd.h Sun Jun 8 12:19:25 2003 @@ -0,0 +1,164 @@ +#ifndef _SCSI_SCSI_CMND_H +#define _SCSI_SCSI_CMND_H + +#include +#include + +struct request; +struct scatterlist; +struct scsi_device; +struct scsi_request; + + +/* embedded in scsi_cmnd */ +struct scsi_pointer { + char *ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + dma_addr_t dma_handle; + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; +}; + +struct scsi_cmnd { + int sc_magic; + + struct scsi_device *device; + unsigned short state; + unsigned short owner; + struct scsi_request *sc_request; + + struct list_head list; /* scsi_cmnd participates in queue lists */ + + struct list_head eh_entry; /* entry for the host eh_cmd_q */ + int eh_state; /* Used for state tracking in error handlr */ + int eh_eflags; /* Used by error handlr */ + void (*done) (struct scsi_cmnd *); /* Mid-level done function */ + + /* + * A SCSI Command is assigned a nonzero serial_number when internal_cmnd + * passes it to the driver's queue command function. The serial_number + * is cleared when scsi_done is entered indicating that the command has + * been completed. If a timeout occurs, the serial number at the moment + * of timeout is copied into serial_number_at_timeout. By subsequently + * comparing the serial_number and serial_number_at_timeout fields + * during abort or reset processing, we can detect whether the command + * has already completed. This also detects cases where the command has + * completed and the SCSI Command structure has already being reused + * for another command, so that we can avoid incorrectly aborting or + * resetting the new command. + */ + unsigned long serial_number; + unsigned long serial_number_at_timeout; + + int retries; + int allowed; + int timeout_per_command; + int timeout_total; + int timeout; + + /* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + unsigned volatile char internal_timeout; + + unsigned char cmd_len; + unsigned char old_cmd_len; + unsigned char sc_data_direction; + unsigned char sc_old_data_direction; + + /* These elements define the operation we are about to perform */ +#define MAX_COMMAND_SIZE 16 + unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned request_bufflen; /* Actual request size */ + + struct timer_list eh_timeout; /* Used to time out the command. */ + void *request_buffer; /* Actual requested buffer */ + + /* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[MAX_COMMAND_SIZE]; + unsigned short old_use_sg; /* We save use_sg here when requesting + * sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned short abort_reason; /* If the mid-level code requests an + * abort, this is the reason. */ + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than + this amount is transferred */ + unsigned old_underflow; /* save underflow here when reusing the + * command for error handling */ + + unsigned transfersize; /* How much we are guaranteed to + transfer with each SCSI transfer + (ie, between disconnect / + reconnects. Probably == sector + size */ + + int resid; /* Number of bytes requested to be + transferred less actual number + transferred (0 if not supported) */ + + struct request *request; /* The command we are + working on */ + +#define SCSI_SENSE_BUFFERSIZE 64 + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + unsigned flags; + + /* Low-level done function - can be used by low-level driver to point + * to completion function. Not used by mid/upper level code. */ + void (*scsi_done) (struct scsi_cmnd *); + + /* + * The following fields can be written to by the host specific code. + * Everything else should be left alone. + */ + struct scsi_pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char *host_scribble; /* The host adapter is allowed to + * call scsi_malloc and get some memory + * and hang it here. The host adapter + * is also expected to call scsi_free + * to release this memory. (The memory + * obtained by scsi_malloc is guaranteed + * to be at an address < 16Mb). */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + unsigned long pid; /* Process ID, starts at 0 */ +}; + +/* + * These are the values that scsi_cmd->state can take. + */ +#define SCSI_STATE_TIMEOUT 0x1000 +#define SCSI_STATE_FINISHED 0x1001 +#define SCSI_STATE_FAILED 0x1002 +#define SCSI_STATE_QUEUED 0x1003 +#define SCSI_STATE_UNUSED 0x1006 +#define SCSI_STATE_DISCONNECTING 0x1008 +#define SCSI_STATE_INITIALIZING 0x1009 +#define SCSI_STATE_BHQUEUE 0x100a +#define SCSI_STATE_MLQUEUE 0x100b + + +extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, int); +extern void scsi_put_command(struct scsi_cmnd *); +extern void scsi_io_completion(struct scsi_cmnd *, int, int); + +#endif /* _SCSI_SCSI_CMND_H */ diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_device.h Sun Jun 8 12:19:25 2003 @@ -0,0 +1,106 @@ +#ifndef _SCSI_SCSI_DEVICE_H +#define _SCSI_SCSI_DEVICE_H + +#include +#include +#include + +struct request_queue; +struct scsi_cmnd; + + +struct scsi_device { + struct class_device sdev_classdev; + + struct list_head siblings; /* list of all devices on this host */ + struct list_head same_target_siblings; /* just the devices sharing same target id */ + struct Scsi_Host *host; + struct request_queue *request_queue; + volatile unsigned short device_busy; /* commands actually active on low-level */ + spinlock_t sdev_lock; /* also the request queue_lock */ + spinlock_t list_lock; + struct list_head cmd_list; /* queue of in use SCSI Command structures */ + struct list_head starved_entry; + struct scsi_cmnd *current_cmnd; /* currently active command */ + unsigned short queue_depth; /* How deep of a queue we want */ + unsigned short last_queue_full_depth; /* These two are used by */ + unsigned short last_queue_full_count; /* scsi_track_queue_full() */ + unsigned long last_queue_full_time;/* don't let QUEUE_FULLs on the same + jiffie count on our counter, they + could all be from the same event. */ + + unsigned int id, lun, channel; + + unsigned int manufacturer; /* Manufacturer of device, for using + * vendor-specific cmd's */ + unsigned sector_size; /* size in bytes */ + + int access_count; /* Count of open channels/mounts */ + + void *hostdata; /* available to low-level driver */ + char devfs_name[256]; /* devfs junk */ + char type; + char scsi_level; + unsigned char inquiry_len; /* valid bytes in 'inquiry' */ + unsigned char * inquiry; /* INQUIRY response data */ + char * vendor; /* [back_compat] point into 'inquiry' ... */ + char * model; /* ... after scan; point to static string */ + char * rev; /* ... "nullnullnullnull" before scan */ + unsigned char current_tag; /* current tag */ + struct scsi_target *sdev_target; /* used only for single_lun */ + + unsigned online:1; + + unsigned writeable:1; + unsigned removable:1; + unsigned changed:1; /* Data invalid due to media change */ + unsigned busy:1; /* Used to prevent races */ + unsigned lockable:1; /* Able to prevent media removal */ + unsigned locked:1; /* Media removal disabled */ + unsigned borken:1; /* Tell the Seagate driver to be + * painfully slow on this device */ + unsigned disconnect:1; /* can disconnect */ + unsigned soft_reset:1; /* Uses soft reset option */ + unsigned sdtr:1; /* Device supports SDTR messages */ + unsigned wdtr:1; /* Device supports WDTR messages */ + unsigned ppr:1; /* Device supports PPR messages */ + unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ + unsigned tagged_queue:1;/* This is going away!!!! Look at simple_tags + instead!!! Please fix your driver now!! */ + unsigned simple_tags:1; /* simple queue tag messages are enabled */ + unsigned ordered_tags:1;/* ordered queue tag messages are enabled */ + unsigned single_lun:1; /* Indicates we should only allow I/O to + * one of the luns for the device at a + * time. */ + unsigned was_reset:1; /* There was a bus reset on the bus for + * this device */ + unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN + * because we did a bus reset. */ + unsigned use_10_for_rw:1; /* first try 10-byte read / write */ + unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ + unsigned no_start_on_add:1; /* do not issue start on add */ + + unsigned int device_blocked; /* Device returned QUEUE_FULL. */ + + unsigned int max_device_blocked; /* what device_blocked counts down from */ +#define SCSI_DEFAULT_DEVICE_BLOCKED 3 + + struct device sdev_driverfs_dev; +}; +#define to_scsi_device(d) \ + container_of(d, struct scsi_device, sdev_driverfs_dev) + +extern struct scsi_device *scsi_add_device(struct Scsi_Host *, + uint, uint, uint); +extern int scsi_remove_device(struct scsi_device *); +extern void scsi_set_device_offline(struct scsi_device *); + +extern int scsi_device_get(struct scsi_device *); +extern void scsi_device_put(struct scsi_device *); + +extern void scsi_adjust_queue_depth(struct scsi_device *, int, int); +extern int scsi_track_queue_full(struct scsi_device *, int); + +extern int scsi_set_medium_removal(struct scsi_device *, char); + +#endif /* _SCSI_SCSI_DEVICE_H */ diff -Nru a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_eh.h Sun Jun 8 15:03:00 2003 @@ -0,0 +1,21 @@ +#ifndef _SCSI_SCSI_EH_H +#define _SCSI_SCSI_EH_H + +extern void scsi_add_timer(struct scsi_cmnd *, int, + void (*)(struct scsi_cmnd *)); +extern int scsi_delete_timer(struct scsi_cmnd *); +extern void scsi_report_bus_reset(struct Scsi_Host *, int); +extern void scsi_report_device_reset(struct Scsi_Host *, int, int); +extern int scsi_block_when_processing_errors(struct scsi_device *); +extern void scsi_sleep(int); + +/* + * Reset request from external source + */ +#define SCSI_TRY_RESET_DEVICE 1 +#define SCSI_TRY_RESET_BUS 2 +#define SCSI_TRY_RESET_HOST 3 + +extern int scsi_reset_provider(struct scsi_device *, int); + +#endif /* _SCSI_SCSI_EH_H */ diff -Nru a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_host.h Sun Jun 8 13:31:57 2003 @@ -0,0 +1,525 @@ +#ifndef _SCSI_SCSI_HOST_H +#define _SCSI_SCSI_HOST_H + +#include +#include +#include + +struct block_device; +struct module; +struct scsi_cmnd; +struct scsi_device; +struct Scsi_Host; +struct scsi_host_cmd_pool; + + +/* + * The various choices mean: + * NONE: Self evident. Host adapter is not capable of scatter-gather. + * ALL: Means that the host adapter module can do scatter-gather, + * and that there is no limit to the size of the table to which + * we scatter/gather data. + * Anything else: Indicates the maximum number of chains that can be + * used in one scatter-gather request. + */ +#define SG_NONE 0 +#define SG_ALL 0xff + + +#define DISABLE_CLUSTERING 0 +#define ENABLE_CLUSTERING 1 + + +struct scsi_host_template { + struct module *module; + const char *name; + + /* + * Used to initialize old-style drivers. For new-style drivers + * just perform all work in your module initialization function. + * + * Status: OBSOLETE + */ + int (* detect)(struct scsi_host_template *); + + /* + * Used as unload callback for hosts with old-style drivers. + * + * Status: OBSOLETE + */ + int (* release)(struct Scsi_Host *); + + /* + * The info function will return whatever useful information the + * developer sees fit. If not provided, then the name field will + * be used instead. + * + * Status: OPTIONAL + */ + const char *(* info)(struct Scsi_Host *); + + /* + * Ioctl interface + * + * Status: OPTIONAL + */ + int (* ioctl)(struct scsi_device *dev, int cmd, void *arg); + + /* + * The queuecommand function is used to queue up a scsi + * command block to the LLDD. When the driver finished + * processing the command the done callback is invoked. + * + * If queuecommand returns 0, then the HBA has accepted the + * command. The done() function must be called on the command + * when the driver has finished with it. (you may call done on the + * command before queuecommand returns, but in this case you + * *must* return 0 from queuecommand). + * + * Queuecommand may also reject the command, in which case it may + * not touch the command and must not call done() for it. + * + * There are two possible rejection returns: + * + * SCSI_MLQUEUE_DEVICE_BUSY: Block this device temporarily, but + * allow commands to other devices serviced by this host. + * + * SCSI_MLQUEUE_HOST_BUSY: Block all devices served by this + * host temporarily. + * + * For compatibility, any other non-zero return is treated the + * same as SCSI_MLQUEUE_HOST_BUSY. + * + * NOTE: "temporarily" means either until the next command for# + * this device/host completes, or a period of time determined by + * I/O pressure in the system if there are no other outstanding + * commands. + * + * STATUS: REQUIRED + */ + int (* queuecommand)(struct scsi_cmnd *, + void (*done)(struct scsi_cmnd *)); + + /* + * This is an error handling strategy routine. You don't need to + * define one of these if you don't want to - there is a default + * routine that is present that should work in most cases. For those + * driver authors that have the inclination and ability to write their + * own strategy routine, this is where it is specified. Note - the + * strategy routine is *ALWAYS* run in the context of the kernel eh + * thread. Thus you are guaranteed to *NOT* be in an interrupt + * handler when you execute this, and you are also guaranteed to + * *NOT* have any other commands being queued while you are in the + * strategy routine. When you return from this function, operations + * return to normal. + * + * See scsi_error.c scsi_unjam_host for additional comments about + * what this function should and should not be attempting to do. + * + * Status: REQUIRED (at least one of them) + */ + int (* eh_strategy_handler)(struct Scsi_Host *); + int (* eh_abort_handler)(struct scsi_cmnd *); + int (* eh_device_reset_handler)(struct scsi_cmnd *); + int (* eh_bus_reset_handler)(struct scsi_cmnd *); + int (* eh_host_reset_handler)(struct scsi_cmnd *); + + /* + * Old EH handlers, no longer used. Make them warn the user of old + * drivers by using a wrong type + * + * Status: MORE THAN OBSOLETE + */ + int (* abort)(int); + int (* reset)(int, int); + + /* + * Before the mid layer attempts to scan for a new device where none + * currently exists, it will call this entry in your driver. Should + * your driver need to allocate any structs or perform any other init + * items in order to send commands to a currently unused target/lun + * combo, then this is where you can perform those allocations. This + * is specifically so that drivers won't have to perform any kind of + * "is this a new device" checks in their queuecommand routine, + * thereby making the hot path a bit quicker. + * + * Return values: 0 on success, non-0 on failure + * + * Deallocation: If we didn't find any devices at this ID, you will + * get an immediate call to slave_destroy(). If we find something + * here then you will get a call to slave_configure(), then the + * device will be used for however long it is kept around, then when + * the device is removed from the system (or * possibly at reboot + * time), you will then get a call to slave_detach(). This is + * assuming you implement slave_configure and slave_destroy. + * However, if you allocate memory and hang it off the device struct, + * then you must implement the slave_destroy() routine at a minimum + * in order to avoid leaking memory + * each time a device is tore down. + * + * Status: OPTIONAL + */ + int (* slave_alloc)(struct scsi_device *); + + /* + * Once the device has responded to an INQUIRY and we know the + * device is online, we call into the low level driver with the + * struct scsi_device *. If the low level device driver implements + * this function, it *must* perform the task of setting the queue + * depth on the device. All other tasks are optional and depend + * on what the driver supports and various implementation details. + * + * Things currently recommended to be handled at this time include: + * + * 1. Setting the device queue depth. Proper setting of this is + * described in the comments for scsi_adjust_queue_depth. + * 2. Determining if the device supports the various synchronous + * negotiation protocols. The device struct will already have + * responded to INQUIRY and the results of the standard items + * will have been shoved into the various device flag bits, eg. + * device->sdtr will be true if the device supports SDTR messages. + * 3. Allocating command structs that the device will need. + * 4. Setting the default timeout on this device (if needed). + * 5. Anything else the low level driver might want to do on a device + * specific setup basis... + * 6. Return 0 on success, non-0 on error. The device will be marked + * as offline on error so that no access will occur. If you return + * non-0, your slave_detach routine will never get called for this + * device, so don't leave any loose memory hanging around, clean + * up after yourself before returning non-0 + * + * Status: OPTIONAL + */ + int (* slave_configure)(struct scsi_device *); + + /* + * Immediately prior to deallocating the device and after all activity + * has ceased the mid layer calls this point so that the low level + * driver may completely detach itself from the scsi device and vice + * versa. The low level driver is responsible for freeing any memory + * it allocated in the slave_alloc or slave_configure calls. + * + * Status: OPTIONAL + */ + void (* slave_destroy)(struct scsi_device *); + + /* + * This function determines the bios parameters for a given + * harddisk. These tend to be numbers that are made up by + * the host adapter. Parameters: + * size, device, list (heads, sectors, cylinders) + * + * Status: OPTIONAL + */ + int (* bios_param)(struct scsi_device *, struct block_device *, + sector_t, int []); + + /* + * Can be used to export driver statistics and other infos to the + * world outside the kernel ie. userspace and it also provides an + * interface to feed the driver with information. + * + * Status: OBSOLETE + */ + int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); + + /* + * Name of proc directory + */ + char *proc_name; + + /* + * Used to store the procfs directory if a driver implements the + * proc_info method. + */ + struct proc_dir_entry *proc_dir; + + /* + * This determines if we will use a non-interrupt driven + * or an interrupt driven scheme, It is set to the maximum number + * of simultaneous commands a given host adapter will accept. + */ + int can_queue; + + /* + * In many instances, especially where disconnect / reconnect are + * supported, our host also has an ID on the SCSI bus. If this is + * the case, then it must be reserved. Please set this_id to -1 if + * your setup is in single initiator mode, and the host lacks an + * ID. + */ + int this_id; + + /* + * This determines the degree to which the host adapter is capable + * of scatter-gather. + */ + unsigned short sg_tablesize; + + /* + * If the host adapter has limitations beside segment count + */ + unsigned short max_sectors; + + /* + * This specifies "machine infinity" for host templates which don't + * limit the transfer size. Note this limit represents an absolute + * maximum, and may be over the transfer limits allowed for + * individual devices (e.g. 256 for SCSI-1) + */ +#define SCSI_DEFAULT_MAX_SECTORS 1024 + + /* + * True if this host adapter can make good use of linked commands. + * This will allow more than one command to be queued to a given + * unit on a given host. Set this to the maximum number of command + * blocks to be provided for each device. Set this to 1 for one + * command block per lun, 2 for two, etc. Do not set this to 0. + * You should make sure that the host adapter will do the right thing + * before you try setting this above 1. + */ + short cmd_per_lun; + + /* + * present contains counter indicating how many boards of this + * type were found when we did the scan. + */ + unsigned char present; + + /* + * true if this host adapter uses unchecked DMA onto an ISA bus. + */ + unsigned unchecked_isa_dma:1; + + /* + * true if this host adapter can make good use of clustering. + * I originally thought that if the tablesize was large that it + * was a waste of CPU cycles to prepare a cluster list, but + * it works out that the Buslogic is faster if you use a smaller + * number of segments (i.e. use clustering). I guess it is + * inefficient. + */ + unsigned use_clustering:1; + + /* + * True for emulated SCSI host adapters (e.g. ATAPI) + */ + unsigned emulated:1; + + unsigned highmem_io:1; + + /* + * True if the driver wishes to use the generic block layer + * tag queueing functions + */ + unsigned use_blk_tcq:1; + + /* + * Countdown for host blocking with no commands outstanding + */ + unsigned int max_host_blocked; + + /* + * Default value for the blocking. If the queue is empty, + * host_blocked counts down in the request_fn until it restarts + * host operations as zero is reached. + * + * FIXME: This should probably be a value in the template + */ +#define SCSI_DEFAULT_HOST_BLOCKED 7 + + /* + * Pointer to the sysfs class properties for this host + */ + struct class_device_attribute **shost_attrs; + + /* + * Pointer to the SCSI device properties for this host + */ + struct device_attribute **sdev_attrs; + + /* + * List of hosts per template. + * + * This is only for use by scsi_module.c for legacy templates. + * For these access to it is synchronized implicitly by + * module_init/module_exit. + */ + struct list_head legacy_hosts; +}; + +struct Scsi_Host { + struct list_head my_devices; + struct scsi_host_cmd_pool *cmd_pool; + spinlock_t free_list_lock; + struct list_head free_list; /* backup store of cmd structs */ + struct list_head starved_list; + + spinlock_t default_lock; + spinlock_t *host_lock; + + struct list_head eh_cmd_q; + struct task_struct * ehandler; /* Error recovery thread. */ + struct semaphore * eh_wait; /* The error recovery thread waits on + this. */ + struct completion * eh_notify; /* wait for eh to begin or end */ + struct semaphore * eh_action; /* Wait for specific actions on the + host. */ + unsigned int eh_active:1; /* Indicates the eh thread is awake and active if + this is true. */ + unsigned int eh_kill:1; /* set when killing the eh thread */ + wait_queue_head_t host_wait; + struct scsi_host_template *hostt; + volatile unsigned short host_busy; /* commands actually active on low-level */ + volatile unsigned short host_failed; /* commands that failed. */ + + unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ + int resetting; /* if set, it means that last_reset is a valid value */ + unsigned long last_reset; + + /* + * These three parameters can be used to allow for wide scsi, + * and for host adapters that support multiple busses + * The first two should be set to 1 more than the actual max id + * or lun (i.e. 8 for normal systems). + */ + unsigned int max_id; + unsigned int max_lun; + unsigned int max_channel; + + /* + * This is a unique identifier that must be assigned so that we + * have some way of identifying each detected host adapter properly + * and uniquely. For hosts that do not support more than one card + * in the system at one time, this does not need to be set. It is + * initialized to 0 in scsi_register. + */ + unsigned int unique_id; + + /* + * The maximum length of SCSI commands that this host can accept. + * Probably 12 for most host adapters, but could be 16 for others. + * For drivers that don't set this field, a value of 12 is + * assumed. I am leaving this as a number rather than a bit + * because you never know what subsequent SCSI standards might do + * (i.e. could there be a 20 byte or a 24-byte command a few years + * down the road?). + */ + unsigned char max_cmd_len; + + int this_id; + int can_queue; + short cmd_per_lun; + short unsigned int sg_tablesize; + short unsigned int max_sectors; + + unsigned in_recovery:1; + unsigned unchecked_isa_dma:1; + unsigned use_clustering:1; + unsigned highmem_io:1; + unsigned use_blk_tcq:1; + + /* + * Host has requested that no further requests come through for the + * time being. + */ + unsigned host_self_blocked:1; + + /* + * Host uses correct SCSI ordering not PC ordering. The bit is + * set for the minority of drivers whose authors actually read + * the spec ;) + */ + unsigned reverse_ordering:1; + + /* + * Host has rejected a command because it was busy. + */ + unsigned int host_blocked; + + /* + * Value host_blocked counts down from + */ + unsigned int max_host_blocked; + + /* + * Support for sysfs + */ + struct device host_gendev; + struct class_device class_dev; + + /* legacy crap */ + unsigned long base; + unsigned long io_port; + unsigned char n_io_port; + unsigned char dma_channel; + unsigned int irq; + + + /* + * List of hosts per template. + * + * This is only for use by scsi_module.c for legacy templates. + * For these access to it is synchronized implicitly by + * module_init/module_exit. + */ + struct list_head sht_legacy_list; + + /* + * We should ensure that this is aligned, both for better performance + * and also because some compilers (m68k) don't automatically force + * alignment to a long boundary. + */ + unsigned long hostdata[0] /* Used for storage of host specific stuff */ + __attribute__ ((aligned (sizeof(unsigned long)))); +}; +#define dev_to_shost(d) \ + container_of(d, struct Scsi_Host, host_gendev) +#define class_to_shost(d) \ + container_of(d, struct Scsi_Host, class_dev) + +extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); +extern int scsi_add_host(struct Scsi_Host *, struct device *); +extern int scsi_remove_host(struct Scsi_Host *); +extern void scsi_host_get(struct Scsi_Host *); +extern void scsi_host_put(struct Scsi_Host *t); +extern struct Scsi_Host *scsi_host_lookup(unsigned short); + +extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); + +static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock) +{ + shost->host_lock = lock; +} + +static inline void scsi_set_device(struct Scsi_Host *shost, + struct device *dev) +{ + shost->host_gendev.parent = dev; +} + +static inline struct device *scsi_get_device(struct Scsi_Host *shost) +{ + return shost->host_gendev.parent; +} + +extern void scsi_sysfs_release_attributes(struct scsi_host_template *); + +extern void scsi_unblock_requests(struct Scsi_Host *); +extern void scsi_block_requests(struct Scsi_Host *); + +/* + * These two functions are used to allocate and free a pseudo device + * which will connect to the host adapter itself rather than any + * physical device. You must deallocate when you are done with the + * thing. This physical pseudo-device isn't real and won't be available + * from any high-level drivers. + */ +extern void scsi_free_host_dev(struct scsi_device *); +extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); + +/* legacy interfaces */ +extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int); +extern void scsi_unregister(struct Scsi_Host *); + +#endif /* _SCSI_SCSI_HOST_H */ diff -Nru a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_request.h Sun Jun 8 15:03:00 2003 @@ -0,0 +1,58 @@ +#ifndef _SCSI_SCSI_REQUEST_H +#define _SCSI_SCSI_REQUEST_H + +#include + +struct request; +struct scsi_cmnd; +struct scsi_device; +struct Scsi_Host; + + +/* + * This is essentially a slimmed down version of Scsi_Cmnd. The point of + * having this is that requests that are injected into the queue as result + * of things like ioctls and character devices shouldn't be using a + * Scsi_Cmnd until such a time that the command is actually at the head + * of the queue and being sent to the driver. + */ +struct scsi_request { + int sr_magic; + int sr_result; /* Status code from lower level driver */ + unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + struct Scsi_Host *sr_host; + struct scsi_device *sr_device; + struct scsi_cmnd *sr_command; + struct request *sr_request; /* A copy of the command we are + working on */ + unsigned sr_bufflen; /* Size of data buffer */ + void *sr_buffer; /* Data buffer */ + int sr_allowed; + unsigned char sr_data_direction; + unsigned char sr_cmd_len; + unsigned char sr_cmnd[MAX_COMMAND_SIZE]; + void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ + int sr_timeout_per_command; + unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ + unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ + unsigned sr_underflow; /* Return error if less than + this amount is transferred */ + void *upper_private_data; /* reserved for owner (usually upper + level driver) of this request */ +}; + +extern struct scsi_request *scsi_allocate_request(struct scsi_device *); +extern void scsi_release_request(struct scsi_request *); +extern void scsi_wait_req(struct scsi_request *, const void *cmnd, + void *buffer, unsigned bufflen, + int timeout, int retries); +extern void scsi_do_req(struct scsi_request *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done) (struct scsi_cmnd *), + int timeout, int retries); + +#endif /* _SCSI_SCSI_REQUEST_H */ diff -Nru a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_tcq.h Sun Jun 8 15:03:00 2003 @@ -0,0 +1,94 @@ +#ifndef _SCSI_SCSI_TCQ_H +#define _SCSI_SCSI_TCQ_H + +#include +#include +#include + + +#define MSG_SIMPLE_TAG 0x20 +#define MSG_HEAD_TAG 0x21 +#define MSG_ORDERED_TAG 0x22 + +#define SCSI_NO_TAG (-1) /* identify no tag in use */ + + +/** + * scsi_activate_tcq - turn on tag command queueing + * @SDpnt: device to turn on TCQ for + * @depth: queue depth + * + * Notes: + * Eventually, I hope depth would be the maximum depth + * the device could cope with and the real queue depth + * would be adjustable from 0 to depth. + **/ +static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth) +{ + if (sdev->tagged_supported) { + if (!blk_queue_tagged(sdev->request_queue)) + blk_queue_init_tags(sdev->request_queue, depth); + scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); + } +} + +/** + * scsi_deactivate_tcq - turn off tag command queueing + * @SDpnt: device to turn off TCQ for + **/ +static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) +{ + if (blk_queue_tagged(sdev->request_queue)) + blk_queue_free_tags(sdev->request_queue); + scsi_adjust_queue_depth(sdev, 0, depth); +} + +/** + * scsi_populate_tag_msg - place a tag message in a buffer + * @SCpnt: pointer to the Scsi_Cmnd for the tag + * @msg: pointer to the area to place the tag + * + * Notes: + * designed to create the correct type of tag message for the + * particular request. Returns the size of the tag message. + * May return 0 if TCQ is disabled for this device. + **/ +static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) +{ + struct request *req = cmd->request; + + if (blk_rq_tagged(req)) { + if (req->flags & REQ_HARDBARRIER) + *msg++ = MSG_ORDERED_TAG; + else + *msg++ = MSG_SIMPLE_TAG; + *msg++ = req->tag; + return 2; + } + + return 0; +} + +/** + * scsi_find_tag - find a tagged command by device + * @SDpnt: pointer to the ScSI device + * @tag: the tag number + * + * Notes: + * Only works with tags allocated by the generic blk layer. + **/ +static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag) +{ + + struct request *req; + + if (tag != SCSI_NO_TAG) { + req = blk_queue_find_tag(sdev->request_queue, tag); + return req ? (struct scsi_cmnd *)req->special : NULL; + } + + /* single command, look in space */ + return sdev->current_cmnd; +} + +#endif /* _SCSI_SCSI_TCQ_H */ diff -Nru a/kernel/compat.c b/kernel/compat.c --- a/kernel/compat.c Sun Jun 15 05:27:20 2003 +++ b/kernel/compat.c Tue Jun 17 05:37:03 2003 @@ -354,6 +354,8 @@ if (put_compat_rusage(ru, &r)) return -EFAULT; + + return 0; } asmlinkage long diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Wed Jun 11 19:53:38 2003 +++ b/kernel/ksyms.c Thu Jun 19 05:46:35 2003 @@ -592,7 +592,6 @@ /* init task, for moving kthread roots - ought to export a function ?? */ EXPORT_SYMBOL(init_task); -EXPORT_SYMBOL(init_thread_union); EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(find_task_by_pid); @@ -604,5 +603,6 @@ /* debug */ EXPORT_SYMBOL(dump_stack); EXPORT_SYMBOL(ptrace_notify); +EXPORT_SYMBOL(console_printk); -EXPORT_SYMBOL(current_kernel_time); +EXPORT_SYMBOL(current_kernel_time); diff -Nru a/lib/kobject.c b/lib/kobject.c --- a/lib/kobject.c Wed Jun 11 12:06:06 2003 +++ b/lib/kobject.c Mon Jun 16 09:02:18 2003 @@ -100,6 +100,9 @@ #define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define NUM_ENVP 32 /* number of env pointers */ +static unsigned long sequence_num; +static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED; + static void kset_hotplug(const char *action, struct kset *kset, struct kobject *kobj) { @@ -112,6 +115,7 @@ int kobj_path_length; char *kobj_path = NULL; char *name = NULL; + unsigned long seq; /* If the kset has a filter operation, call it. If it returns failure, no hotplug event is required. */ @@ -151,6 +155,13 @@ envp [i++] = scratch; scratch += sprintf(scratch, "ACTION=%s", action) + 1; + + spin_lock(&sequence_lock); + seq = sequence_num++; + spin_unlock(&sequence_lock); + + envp [i++] = scratch; + scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1; kobj_path_length = get_kobj_path_length (kset, kobj); kobj_path = kmalloc (kobj_path_length, GFP_KERNEL); diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c Wed Jun 4 17:57:07 2003 +++ b/net/atm/clip.c Tue Jun 17 11:00:05 2003 @@ -140,8 +140,8 @@ DPRINTK("releasing vcc %p->%p of " "entry %p\n",clip_vcc,clip_vcc->vcc, entry); - atm_async_release_vcc(clip_vcc->vcc, - -ETIMEDOUT); + vcc_release_async(clip_vcc->vcc, + -ETIMEDOUT); } if (entry->vccs || time_before(jiffies, entry->expires)) { diff -Nru a/net/atm/common.c b/net/atm/common.c --- a/net/atm/common.c Wed Jun 4 17:57:07 2003 +++ b/net/atm/common.c Tue Jun 17 11:00:05 2003 @@ -239,15 +239,16 @@ } -void atm_async_release_vcc(struct atm_vcc *vcc,int reply) +void vcc_release_async(struct atm_vcc *vcc, int reply) { - set_bit(ATM_VF_CLOSE,&vcc->flags); + set_bit(ATM_VF_CLOSE, &vcc->flags); vcc->reply = reply; + vcc->sk->sk_err = -reply; wake_up(&vcc->sleep); } -EXPORT_SYMBOL(atm_async_release_vcc); +EXPORT_SYMBOL(vcc_release_async); static int adjust_tp(struct atm_trafprm *tp,unsigned char aal) @@ -276,8 +277,8 @@ } -static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi, - int vci) +static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, int vpi, + int vci) { int error; @@ -334,29 +335,26 @@ } -static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci) +int vcc_connect(struct socket *sock, int itf, short vpi, int vci) { struct atm_dev *dev; - int return_val; - - dev = atm_dev_lookup(itf); - if (!dev) - return_val = -ENODEV; - else { - return_val = atm_do_connect_dev(vcc,dev,vpi,vci); - if (return_val) atm_dev_release(dev); - } - - return return_val; -} + struct atm_vcc *vcc = ATM_SD(sock); + int error; + DPRINTK("vcc_connect (vpi %d, vci %d)\n",vpi,vci); + if (sock->state == SS_CONNECTED) + return -EISCONN; + if (sock->state != SS_UNCONNECTED) + return -EINVAL; + if (!(vpi || vci)) + return -EINVAL; -int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci) -{ if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC) clear_bit(ATM_VF_PARTIAL,&vcc->flags); - else if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) return -EINVAL; - DPRINTK("atm_connect (TX: cl %d,bw %d-%d,sdu %d; " + else + if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) + return -EINVAL; + DPRINTK("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; " "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n", vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu, @@ -364,141 +362,135 @@ vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu, vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal); - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) + return -EBADFD; if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) return -EINVAL; if (itf != ATM_ITF_ANY) { - int error; - - error = atm_do_connect(vcc,itf,vpi,vci); - if (error) return error; - } - else { - struct atm_dev *dev = NULL; + dev = atm_dev_lookup(itf); + error = __vcc_connect(vcc, dev, vpi, vci); + if (error) { + atm_dev_release(dev); + return error; + } + } else { struct list_head *p, *next; + dev = NULL; spin_lock(&atm_dev_lock); list_for_each_safe(p, next, &atm_devs) { dev = list_entry(p, struct atm_dev, dev_list); atm_dev_hold(dev); spin_unlock(&atm_dev_lock); - if (!atm_do_connect_dev(vcc,dev,vpi,vci)) + if (!__vcc_connect(vcc, dev, vpi, vci)) break; atm_dev_release(dev); dev = NULL; spin_lock(&atm_dev_lock); } spin_unlock(&atm_dev_lock); - if (!dev) return -ENODEV; + if (!dev) + return -ENODEV; } if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) set_bit(ATM_VF_PARTIAL,&vcc->flags); - return 0; -} - - -int atm_connect(struct socket *sock,int itf,short vpi,int vci) -{ - int error; - - DPRINTK("atm_connect (vpi %d, vci %d)\n",vpi,vci); - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state != SS_UNCONNECTED) return -EINVAL; - if (!(vpi || vci)) return -EINVAL; - error = atm_connect_vcc(ATM_SD(sock),itf,vpi,vci); - if (error) return error; if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags)) sock->state = SS_CONNECTED; return 0; } -int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - int total_len, int flags) +int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + int size, int flags) { - DECLARE_WAITQUEUE(wait,current); + struct sock *sk = sock->sk; struct atm_vcc *vcc; struct sk_buff *skb; - int eff_len,error; - void *buff; - int size; + int copied, error = -EINVAL; - if (sock->state != SS_CONNECTED) return -ENOTCONN; - if (flags & ~MSG_DONTWAIT) return -EOPNOTSUPP; - if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ - buff = m->msg_iov->iov_base; - size = m->msg_iov->iov_len; + if (sock->state != SS_CONNECTED) + return -ENOTCONN; + if (flags & ~MSG_DONTWAIT) /* only handle MSG_DONTWAIT */ + return -EOPNOTSUPP; vcc = ATM_SD(sock); - add_wait_queue(&vcc->sleep,&wait); - set_current_state(TASK_INTERRUPTIBLE); - error = 1; /* <= 0 is error */ - while (!(skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags)) { - error = vcc->reply; - break; - } - if (!test_bit(ATM_VF_READY,&vcc->flags)) { - error = 0; - break; - } - if (flags & MSG_DONTWAIT) { - error = -EAGAIN; - break; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - error = -ERESTARTSYS; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&vcc->sleep,&wait); - if (error <= 0) return error; - sock_recv_timestamp(m, vcc->sk, skb); - eff_len = skb->len > size ? size : skb->len; - if (skb->len > size) /* Not fit ? Report it... */ - m->msg_flags |= MSG_TRUNC; - if (vcc->dev->ops->feedback) - vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, - (unsigned long) buff,eff_len); - DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->sk_rmem_alloc), - skb->truesize); - atm_return(vcc,skb->truesize); - error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; - kfree_skb(skb); - return error ? error : eff_len; + if (test_bit(ATM_VF_RELEASED,&vcc->flags) || + test_bit(ATM_VF_CLOSE,&vcc->flags)) + return vcc->reply; + if (!test_bit(ATM_VF_READY, &vcc->flags)) + return 0; + + skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &error); + if (!skb) + return error; + + copied = skb->len; + if (copied > size) { + copied = size; + msg->msg_flags |= MSG_TRUNC; + } + + error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + if (error) + return error; + sock_recv_timestamp(msg, sk, skb); + if (vcc->dev->ops->feedback) + vcc->dev->ops->feedback(vcc, skb, (unsigned long) skb->data, + (unsigned long) msg->msg_iov->iov_base, copied); + DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->rmem_alloc), skb->truesize); + atm_return(vcc, skb->truesize); + skb_free_datagram(sk, skb); + return copied; } -int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, +int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len) { - DECLARE_WAITQUEUE(wait,current); + struct sock *sk = sock->sk; + DEFINE_WAIT(wait); struct atm_vcc *vcc; struct sk_buff *skb; int eff,error; const void *buff; int size; - if (sock->state != SS_CONNECTED) return -ENOTCONN; - if (m->msg_name) return -EISCONN; - if (m->msg_iovlen != 1) return -ENOSYS; /* fix this later @@@ */ + lock_sock(sk); + if (sock->state != SS_CONNECTED) { + error = -ENOTCONN; + goto out; + } + if (m->msg_name) { + error = -EISCONN; + goto out; + } + if (m->msg_iovlen != 1) { + error = -ENOSYS; /* fix this later @@@ */ + goto out; + } buff = m->msg_iov->iov_base; size = m->msg_iov->iov_len; vcc = ATM_SD(sock); - if (test_bit(ATM_VF_RELEASED,&vcc->flags) || - test_bit(ATM_VF_CLOSE,&vcc->flags)) - return vcc->reply; - if (!test_bit(ATM_VF_READY,&vcc->flags)) return -EPIPE; - if (!size) return 0; - if (size < 0 || size > vcc->qos.txtp.max_sdu) return -EMSGSIZE; + if (test_bit(ATM_VF_RELEASED, &vcc->flags) || + test_bit(ATM_VF_CLOSE, &vcc->flags)) { + error = vcc->reply; + goto out; + } + if (!test_bit(ATM_VF_READY, &vcc->flags)) { + error = -EPIPE; + goto out; + } + if (!size) { + error = 0; + goto out; + } + if (size < 0 || size > vcc->qos.txtp.max_sdu) { + error = -EMSGSIZE; + goto out; + } /* verify_area is done by net/socket.c */ eff = (size+3) & ~3; /* align to word boundary */ - add_wait_queue(&vcc->sleep,&wait); - set_current_state(TASK_INTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); error = 0; while (!(skb = alloc_tx(vcc,eff))) { if (m->msg_flags & MSG_DONTWAIT) { @@ -506,7 +498,6 @@ break; } schedule(); - set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { error = -ERESTARTSYS; break; @@ -520,19 +511,24 @@ error = -EPIPE; break; } + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); } - set_current_state(TASK_RUNNING); - remove_wait_queue(&vcc->sleep,&wait); - if (error) return error; + finish_wait(&vcc->sleep, &wait); + if (error) + goto out; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; if (copy_from_user(skb_put(skb,size),buff,size)) { kfree_skb(skb); - return -EFAULT; + error = -EFAULT; + goto out; } if (eff != size) memset(skb->data+size,0,eff-size); error = vcc->dev->ops->send(vcc,skb); - return error ? error : size; + error = error ? error : size; +out: + release_sock(sk); + return error; } @@ -563,129 +559,51 @@ } -static void copy_aal_stats(struct k_atm_aal_stats *from, - struct atm_aal_stats *to) -{ -#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) - __AAL_STAT_ITEMS -#undef __HANDLE_ITEM -} - - -static void subtract_aal_stats(struct k_atm_aal_stats *from, - struct atm_aal_stats *to) -{ -#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i) - __AAL_STAT_ITEMS -#undef __HANDLE_ITEM -} - - -static int fetch_stats(struct atm_dev *dev,struct atm_dev_stats *arg,int zero) +int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct atm_dev_stats tmp; - int error = 0; - - copy_aal_stats(&dev->stats.aal0,&tmp.aal0); - copy_aal_stats(&dev->stats.aal34,&tmp.aal34); - copy_aal_stats(&dev->stats.aal5,&tmp.aal5); - if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); - if (zero && !error) { - subtract_aal_stats(&dev->stats.aal0,&tmp.aal0); - subtract_aal_stats(&dev->stats.aal34,&tmp.aal34); - subtract_aal_stats(&dev->stats.aal5,&tmp.aal5); - } - return error ? -EFAULT : 0; -} - - -int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg) -{ - struct atm_dev *dev; - struct list_head *p; struct atm_vcc *vcc; - int *tmp_buf, *tmp_p; - void *buf; - int error,len,size,number, ret_val; + int error; - ret_val = 0; vcc = ATM_SD(sock); switch (cmd) { case SIOCOUTQ: if (sock->state != SS_CONNECTED || - !test_bit(ATM_VF_READY,&vcc->flags)) { - ret_val = -EINVAL; + !test_bit(ATM_VF_READY, &vcc->flags)) { + error = -EINVAL; goto done; } - ret_val = put_user(vcc->sk->sk_sndbuf - - atomic_read(&vcc->sk->sk_wmem_alloc), - (int *) arg) ? -EFAULT : 0; + error = put_user(vcc->sk->sk_sndbuf - + atomic_read(&vcc->sk->sk_wmem_alloc), + (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: { struct sk_buff *skb; if (sock->state != SS_CONNECTED) { - ret_val = -EINVAL; + error = -EINVAL; goto done; } skb = skb_peek(&vcc->sk->sk_receive_queue); - ret_val = put_user(skb ? skb->len : 0,(int *) arg) - ? -EFAULT : 0; + error = put_user(skb ? skb->len : 0, + (int *) arg) ? -EFAULT : 0; goto done; } - case ATM_GETNAMES: - if (get_user(buf, - &((struct atm_iobuf *) arg)->buffer)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(len, - &((struct atm_iobuf *) arg)->length)) { - ret_val = -EFAULT; - goto done; - } - size = 0; - spin_lock(&atm_dev_lock); - list_for_each(p, &atm_devs) - size += sizeof(int); - if (size > len) { - spin_unlock(&atm_dev_lock); - ret_val = -E2BIG; - goto done; - } - tmp_buf = kmalloc(size, GFP_ATOMIC); - if (!tmp_buf) { - spin_unlock(&atm_dev_lock); - ret_val = -ENOMEM; - goto done; - } - tmp_p = tmp_buf; - list_for_each(p, &atm_devs) { - dev = list_entry(p, struct atm_dev, dev_list); - *tmp_p++ = dev->number; - } - spin_unlock(&atm_dev_lock); - ret_val = ((copy_to_user(buf, tmp_buf, size)) || - put_user(size, &((struct atm_iobuf *) arg)->length) - ) ? -EFAULT : 0; - kfree(tmp_buf); - goto done; case SIOCGSTAMP: /* borrowed from IP */ if (!vcc->sk->sk_stamp.tv_sec) { - ret_val = -ENOENT; + error = -ENOENT; goto done; } - ret_val = copy_to_user((void *)arg, &vcc->sk->sk_stamp, - sizeof(struct timeval)) ? -EFAULT : 0; + error = copy_to_user((void *)arg, &vcc->sk->sk_stamp, + sizeof(struct timeval)) ? -EFAULT : 0; goto done; case ATM_SETSC: printk(KERN_WARNING "ATM_SETSC is obsolete\n"); - ret_val = 0; + error = 0; goto done; case ATMSIGD_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } /* @@ -696,28 +614,28 @@ * have the same privledges that /proc/kcore needs */ if (!capable(CAP_SYS_RAWIO)) { - ret_val = -EPERM; + error = -EPERM; goto done; } error = sigd_attach(vcc); - if (!error) sock->state = SS_CONNECTED; - ret_val = error; + if (!error) + sock->state = SS_CONNECTED; goto done; #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) case SIOCMKCLIP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_create(arg); + error = atm_clip_ops->clip_create(arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARPD_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_CLIP_MODULE) @@ -728,48 +646,47 @@ error = atm_clip_ops->atm_init_atmarp(vcc); if (!error) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_MKIP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_mkip(vcc, arg); + error = atm_clip_ops->clip_mkip(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_SETENTRY: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_setentry(vcc, arg); + error = atm_clip_ops->clip_setentry(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMARP_ENCAP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_clip_ops()) { - ret_val = atm_clip_ops->clip_encap(vcc, arg); + error = atm_clip_ops->clip_encap(vcc, arg); module_put(atm_clip_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) case ATMLEC_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_LANE_MODULE) @@ -781,37 +698,36 @@ module_put(atm_lane_ops->owner); if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMLEC_MCAST: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_lane_ops()) { - ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg); + error = atm_lane_ops->mcast_attach(vcc, (int) arg); module_put(atm_lane_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMLEC_DATA: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_lane_ops()) { - ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg); + error = atm_lane_ops->vcc_attach(vcc, (void *) arg); module_put(atm_lane_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) case ATMMPC_CTRL: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } #if defined(CONFIG_ATM_MPOA_MODULE) @@ -823,63 +739,62 @@ module_put(atm_mpoa_ops->owner); if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; case ATMMPC_DATA: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (try_atm_mpoa_ops()) { - ret_val = atm_mpoa_ops->vcc_attach(vcc, arg); + error = atm_mpoa_ops->vcc_attach(vcc, arg); module_put(atm_mpoa_ops->owner); } else - ret_val = -ENOSYS; + error = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) case SIOCSIFATMTCP: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.attach) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } - fops_get (&atm_tcp_ops); - error = atm_tcp_ops.attach(vcc,(int) arg); - if (error >= 0) sock->state = SS_CONNECTED; - else fops_put (&atm_tcp_ops); - ret_val = error; + fops_get(&atm_tcp_ops); + error = atm_tcp_ops.attach(vcc, (int) arg); + if (error >= 0) + sock->state = SS_CONNECTED; + else + fops_put (&atm_tcp_ops); goto done; case ATMTCP_CREATE: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.create_persistent) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } error = atm_tcp_ops.create_persistent((int) arg); - if (error < 0) fops_put (&atm_tcp_ops); - ret_val = error; + if (error < 0) + fops_put (&atm_tcp_ops); goto done; case ATMTCP_REMOVE: if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; + error = -EPERM; goto done; } if (!atm_tcp_ops.remove_persistent) { - ret_val = -ENOPKG; + error = -ENOPKG; goto done; } error = atm_tcp_ops.remove_persistent((int) arg); - fops_put (&atm_tcp_ops); - ret_val = error; + fops_put(&atm_tcp_ops); goto done; #endif default: @@ -887,182 +802,23 @@ } #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE) if (pppoatm_ioctl_hook) { - ret_val = pppoatm_ioctl_hook(vcc, cmd, arg); - if (ret_val != -ENOIOCTLCMD) + error = pppoatm_ioctl_hook(vcc, cmd, arg); + if (error != -ENOIOCTLCMD) goto done; } #endif #if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) if (br2684_ioctl_hook) { - ret_val = br2684_ioctl_hook(vcc, cmd, arg); - if (ret_val != -ENOIOCTLCMD) + error = br2684_ioctl_hook(vcc, cmd, arg); + if (error != -ENOIOCTLCMD) goto done; } #endif - if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(len,&((struct atmif_sioc *) arg)->length)) { - ret_val = -EFAULT; - goto done; - } - if (get_user(number,&((struct atmif_sioc *) arg)->number)) { - ret_val = -EFAULT; - goto done; - } - if (!(dev = atm_dev_lookup(number))) { - ret_val = -ENODEV; - goto done; - } - - size = 0; - switch (cmd) { - case ATM_GETTYPE: - size = strlen(dev->type)+1; - if (copy_to_user(buf,dev->type,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_GETESI: - size = ESI_LEN; - if (copy_to_user(buf,dev->esi,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_SETESI: - { - int i; - for (i = 0; i < ESI_LEN; i++) - if (dev->esi[i]) { - ret_val = -EEXIST; - goto done_release; - } - } - /* fall through */ - case ATM_SETESIF: - { - unsigned char esi[ESI_LEN]; - - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - if (copy_from_user(esi,buf,ESI_LEN)) { - ret_val = -EFAULT; - goto done_release; - } - memcpy(dev->esi,esi,ESI_LEN); - ret_val = ESI_LEN; - goto done_release; - } - case ATM_GETSTATZ: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - /* fall through */ - case ATM_GETSTAT: - size = sizeof(struct atm_dev_stats); - error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ); - if (error) { - ret_val = error; - goto done_release; - } - break; - case ATM_GETCIRANGE: - size = sizeof(struct atm_cirange); - if (copy_to_user(buf,&dev->ci_range,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_GETLINKRATE: - size = sizeof(int); - if (copy_to_user(buf,&dev->link_rate,size)) { - ret_val = -EFAULT; - goto done_release; - } - break; - case ATM_RSTADDR: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - atm_reset_addr(dev); - break; - case ATM_ADDADDR: - case ATM_DELADDR: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - { - struct sockaddr_atmsvc addr; - - if (copy_from_user(&addr,buf,sizeof(addr))) { - ret_val = -EFAULT; - goto done_release; - } - if (cmd == ATM_ADDADDR) - ret_val = atm_add_addr(dev,&addr); - else - ret_val = atm_del_addr(dev,&addr); - goto done_release; - } - case ATM_GETADDR: - size = atm_get_addr(dev,buf,len); - if (size < 0) - ret_val = size; - else - /* may return 0, but later on size == 0 means "don't - write the length" */ - ret_val = put_user(size, - &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0; - goto done_release; - case ATM_SETLOOP: - if (__ATM_LM_XTRMT((int) (long) buf) && - __ATM_LM_XTLOC((int) (long) buf) > - __ATM_LM_XTRMT((int) (long) buf)) { - ret_val = -EINVAL; - goto done_release; - } - /* fall through */ - case ATM_SETCIRANGE: - case SONET_GETSTATZ: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - if (!capable(CAP_NET_ADMIN)) { - ret_val = -EPERM; - goto done_release; - } - /* fall through */ - default: - if (!dev->ops->ioctl) { - ret_val = -EINVAL; - goto done_release; - } - size = dev->ops->ioctl(dev,cmd,buf); - if (size < 0) { - ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size); - goto done_release; - } - } - - if (size) - ret_val = put_user(size,&((struct atmif_sioc *) arg)->length) ? - -EFAULT : 0; - else - ret_val = 0; -done_release: - atm_dev_release(dev); + error = atm_dev_ioctl(cmd, arg); done: - return ret_val; + return error; } @@ -1120,14 +876,16 @@ return check_tp(&qos->rxtp); } - -static int atm_do_setsockopt(struct socket *sock,int level,int optname, - void *optval,int optlen) +int vcc_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) { struct atm_vcc *vcc; unsigned long value; int error; + if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) + return -EINVAL; + vcc = ATM_SD(sock); switch (optname) { case SO_ATMQOS: @@ -1161,10 +919,16 @@ } -static int atm_do_getsockopt(struct socket *sock,int level,int optname, - void *optval,int optlen) +int vcc_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) { struct atm_vcc *vcc; + int len; + + if (get_user(len, optlen)) + return -EFAULT; + if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) + return -EINVAL; vcc = ATM_SD(sock); switch (optname) { @@ -1195,28 +959,7 @@ break; } if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; - return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); -} - - -int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, - int optlen) -{ - if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname)) - return -EINVAL; - return atm_do_setsockopt(sock,level,optname,optval,optlen); -} - - -int atm_getsockopt(struct socket *sock,int level,int optname, - char *optval,int *optlen) -{ - int len; - - if (get_user(len,optlen)) return -EFAULT; - if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname)) - return -EINVAL; - return atm_do_getsockopt(sock,level,optname,optval,len); + return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len); } diff -Nru a/net/atm/common.h b/net/atm/common.h --- a/net/atm/common.h Thu May 15 21:12:28 2003 +++ b/net/atm/common.h Tue Jun 17 11:00:05 2003 @@ -12,19 +12,18 @@ int atm_create(struct socket *sock,int protocol,int family); int atm_release(struct socket *sock); -int atm_connect(struct socket *sock,int itf,short vpi,int vci); -int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, - int total_len, int flags); -int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, +int vcc_connect(struct socket *sock, int itf, short vpi, int vci); +int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, + int size, int flags); +int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len); unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait); -int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg); -int atm_setsockopt(struct socket *sock,int level,int optname,char *optval, - int optlen); -int atm_getsockopt(struct socket *sock,int level,int optname,char *optval, - int *optlen); +int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +int vcc_setsockopt(struct socket *sock, int level, int optname, char *optval, + int optlen); +int vcc_getsockopt(struct socket *sock, int level, int optname, char *optval, + int *optlen); -int atm_connect_vcc(struct atm_vcc *vcc,int itf,short vpi,int vci); void atm_release_vcc_sk(struct sock *sk,int free_sk); void atm_shutdown_dev(struct atm_dev *dev); diff -Nru a/net/atm/lec.c b/net/atm/lec.c --- a/net/atm/lec.c Wed Jun 4 17:57:07 2003 +++ b/net/atm/lec.c Tue Jun 17 11:00:06 2003 @@ -1079,7 +1079,7 @@ clear_bit(ATM_VF_READY,&entry->vcc->flags); entry->vcc->push(entry->vcc, NULL); #endif - atm_async_release_vcc(entry->vcc, -EPIPE); + vcc_release_async(entry->vcc, -EPIPE); entry->vcc = NULL; } if (entry->recv_vcc) { @@ -1089,7 +1089,7 @@ clear_bit(ATM_VF_READY,&entry->recv_vcc->flags); entry->recv_vcc->push(entry->recv_vcc, NULL); #endif - atm_async_release_vcc(entry->recv_vcc, -EPIPE); + vcc_release_async(entry->recv_vcc, -EPIPE); entry->recv_vcc = NULL; } } diff -Nru a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c --- a/net/atm/mpoa_caches.c Tue Feb 5 09:40:00 2002 +++ b/net/atm/mpoa_caches.c Tue Jun 17 10:32:43 2003 @@ -212,7 +212,7 @@ client->eg_ops->put(eg_entry); return; } - atm_async_release_vcc(vcc, -EPIPE); + vcc_release_async(vcc, -EPIPE); } return; @@ -447,7 +447,7 @@ client->in_ops->put(in_entry); return; } - atm_async_release_vcc(vcc, -EPIPE); + vcc_release_async(vcc, -EPIPE); } return; diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c --- a/net/atm/pvc.c Thu May 15 21:54:16 2003 +++ b/net/atm/pvc.c Tue Jun 17 11:00:06 2003 @@ -31,20 +31,29 @@ static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len) { + struct sock *sk = sock->sk; struct sockaddr_atmpvc *addr; struct atm_vcc *vcc; + int error; if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL; addr = (struct sockaddr_atmpvc *) sockaddr; if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT; + lock_sock(sk); vcc = ATM_SD(sock); - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { + error = -EBADFD; + goto out; + } if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) { if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi; if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci; } - return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi, - addr->sap_addr.vci); + error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi, + addr->sap_addr.vci); +out: + release_sock(sk); + return error; } @@ -54,6 +63,31 @@ return pvc_bind(sock,sockaddr,sockaddr_len); } +static int pvc_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = sock->sk; + int error; + + lock_sock(sk); + error = vcc_setsockopt(sock, level, optname, optval, optlen); + release_sock(sk); + return error; +} + + +static int pvc_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + int error; + + lock_sock(sk); + error = vcc_getsockopt(sock, level, optname, optval, optlen); + release_sock(sk); + return error; +} + static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr, int *sockaddr_len,int peer) @@ -72,7 +106,7 @@ } -static struct proto_ops SOCKOPS_WRAPPED(pvc_proto_ops) = { +static struct proto_ops pvc_proto_ops = { .family = PF_ATMPVC, .release = atm_release, @@ -82,20 +116,16 @@ .accept = sock_no_accept, .getname = pvc_getname, .poll = atm_poll, - .ioctl = atm_ioctl, + .ioctl = vcc_ioctl, .listen = sock_no_listen, .shutdown = pvc_shutdown, - .setsockopt = atm_setsockopt, - .getsockopt = atm_getsockopt, - .sendmsg = atm_sendmsg, - .recvmsg = atm_recvmsg, + .setsockopt = pvc_setsockopt, + .getsockopt = pvc_getsockopt, + .sendmsg = vcc_sendmsg, + .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; - - -#include -SOCKOPS_WRAP(pvc_proto, PF_ATMPVC); static int pvc_create(struct socket *sock,int protocol) diff -Nru a/net/atm/resources.c b/net/atm/resources.c --- a/net/atm/resources.c Thu May 15 17:20:17 2003 +++ b/net/atm/resources.c Tue Jun 17 11:00:06 2003 @@ -12,6 +12,7 @@ #include #include #include +#include #include /* for barrier */ #include #include @@ -19,6 +20,7 @@ #include "common.h" #include "resources.h" +#include "addr.h" #ifndef NULL @@ -170,6 +172,240 @@ dev->ops->dev_close(dev); atm_dev_deregister(dev); } + + +static void copy_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) +{ +#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} + + +static void subtract_aal_stats(struct k_atm_aal_stats *from, + struct atm_aal_stats *to) +{ +#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) + __AAL_STAT_ITEMS +#undef __HANDLE_ITEM +} + + +static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats *arg, int zero) +{ + struct atm_dev_stats tmp; + int error = 0; + + copy_aal_stats(&dev->stats.aal0, &tmp.aal0); + copy_aal_stats(&dev->stats.aal34, &tmp.aal34); + copy_aal_stats(&dev->stats.aal5, &tmp.aal5); + if (arg) + error = copy_to_user(arg, &tmp, sizeof(tmp)); + if (zero && !error) { + subtract_aal_stats(&dev->stats.aal0, &tmp.aal0); + subtract_aal_stats(&dev->stats.aal34, &tmp.aal34); + subtract_aal_stats(&dev->stats.aal5, &tmp.aal5); + } + return error ? -EFAULT : 0; +} + + +int atm_dev_ioctl(unsigned int cmd, unsigned long arg) +{ + void *buf; + int error, len, number, size = 0; + struct atm_dev *dev; + struct list_head *p; + int *tmp_buf, *tmp_p; + + switch (cmd) { + case ATM_GETNAMES: + if (get_user(buf, &((struct atm_iobuf *) arg)->buffer)) + return -EFAULT; + if (get_user(len, &((struct atm_iobuf *) arg)->length)) + return -EFAULT; + spin_lock(&atm_dev_lock); + list_for_each(p, &atm_devs) + size += sizeof(int); + if (size > len) { + spin_unlock(&atm_dev_lock); + return -E2BIG; + } + tmp_buf = kmalloc(size, GFP_ATOMIC); + if (!tmp_buf) { + spin_unlock(&atm_dev_lock); + return -ENOMEM; + } + tmp_p = tmp_buf; + list_for_each(p, &atm_devs) { + dev = list_entry(p, struct atm_dev, dev_list); + *tmp_p++ = dev->number; + } + spin_unlock(&atm_dev_lock); + error = ((copy_to_user(buf, tmp_buf, size)) || + put_user(size, &((struct atm_iobuf *) arg)->length)) + ? -EFAULT : 0; + kfree(tmp_buf); + return error; + default: + break; + } + + if (get_user(buf, &((struct atmif_sioc *) arg)->arg)) + return -EFAULT; + if (get_user(len, &((struct atmif_sioc *) arg)->length)) + return -EFAULT; + if (get_user(number, &((struct atmif_sioc *) arg)->number)) + return -EFAULT; + + if (!(dev = atm_dev_lookup(number))) + return -ENODEV; + + switch (cmd) { + case ATM_GETTYPE: + size = strlen(dev->type) + 1; + if (copy_to_user(buf, dev->type, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETESI: + size = ESI_LEN; + if (copy_to_user(buf, dev->esi, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_SETESI: + { + int i; + + for (i = 0; i < ESI_LEN; i++) + if (dev->esi[i]) { + error = -EEXIST; + goto done; + } + } + /* fall through */ + case ATM_SETESIF: + { + unsigned char esi[ESI_LEN]; + + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + if (copy_from_user(esi, buf, ESI_LEN)) { + error = -EFAULT; + goto done; + } + memcpy(dev->esi, esi, ESI_LEN); + error = ESI_LEN; + goto done; + } + case ATM_GETSTATZ: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + case ATM_GETSTAT: + size = sizeof(struct atm_dev_stats); + error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); + if (error) + goto done; + break; + case ATM_GETCIRANGE: + size = sizeof(struct atm_cirange); + if (copy_to_user(buf, &dev->ci_range, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_GETLINKRATE: + size = sizeof(int); + if (copy_to_user(buf, &dev->link_rate, size)) { + error = -EFAULT; + goto done; + } + break; + case ATM_RSTADDR: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + atm_reset_addr(dev); + break; + case ATM_ADDADDR: + case ATM_DELADDR: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + { + struct sockaddr_atmsvc addr; + + if (copy_from_user(&addr, buf, sizeof(addr))) { + error = -EFAULT; + goto done; + } + if (cmd == ATM_ADDADDR) + error = atm_add_addr(dev, &addr); + else + error = atm_del_addr(dev, &addr); + goto done; + } + case ATM_GETADDR: + error = atm_get_addr(dev, buf, len); + if (error < 0) + goto done; + size = error; + /* may return 0, but later on size == 0 means "don't + write the length" */ + error = put_user(size, &((struct atmif_sioc *) arg)->length) + ? -EFAULT : 0; + goto done; + case ATM_SETLOOP: + if (__ATM_LM_XTRMT((int) (long) buf) && + __ATM_LM_XTLOC((int) (long) buf) > + __ATM_LM_XTRMT((int) (long) buf)) { + error = -EINVAL; + goto done; + } + /* fall through */ + case ATM_SETCIRANGE: + case SONET_GETSTATZ: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + if (!capable(CAP_NET_ADMIN)) { + error = -EPERM; + goto done; + } + /* fall through */ + default: + if (!dev->ops->ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->ioctl(dev, cmd, buf); + if (size < 0) { + error = (size == -ENOIOCTLCMD ? -EINVAL : size); + goto done; + } + } + + if (size) + error = put_user(size, &((struct atmif_sioc *) arg)->length) + ? -EFAULT : 0; + else + error = 0; +done: + atm_dev_release(dev); + return error; +} + struct sock *alloc_atm_vcc_sk(int family) { diff -Nru a/net/atm/resources.h b/net/atm/resources.h --- a/net/atm/resources.h Thu May 15 17:20:17 2003 +++ b/net/atm/resources.h Tue Jun 17 11:00:06 2003 @@ -16,6 +16,7 @@ struct sock *alloc_atm_vcc_sk(int family); void free_atm_vcc_sk(struct sock *sk); +int atm_dev_ioctl(unsigned int cmd, unsigned long arg); #ifdef CONFIG_PROC_FS diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c --- a/net/atm/signaling.c Wed Jun 4 17:57:07 2003 +++ b/net/atm/signaling.c Tue Jun 17 11:00:06 2003 @@ -124,14 +124,16 @@ clear_bit(ATM_VF_REGIS,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; + vcc->sk->sk_err = -msg->reply; break; case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; DPRINTK("as_indicate!!!\n"); + lock_sock(vcc->sk); if (vcc->sk->sk_ack_backlog == vcc->sk->sk_max_ack_backlog) { sigd_enq(0,as_reject,vcc,NULL,NULL); - return 0; + goto as_indicate_complete; } vcc->sk->sk_ack_backlog++; skb_queue_tail(&vcc->sk->sk_receive_queue, skb); @@ -140,11 +142,14 @@ &vcc->sleep); vcc->callback(vcc); } +as_indicate_complete: + release_sock(vcc->sk); return 0; case as_close: set_bit(ATM_VF_RELEASED,&vcc->flags); clear_bit(ATM_VF_READY,&vcc->flags); vcc->reply = msg->reply; + vcc->sk->sk_err = -msg->reply; break; case as_modify: modify_qos(vcc,msg); @@ -202,6 +207,7 @@ !test_bit(ATM_VF_META,&vcc->flags)) { set_bit(ATM_VF_RELEASED,&vcc->flags); vcc->reply = -EUNATCH; + vcc->sk->sk_err = EUNATCH; wake_up(&vcc->sleep); } vcc = vcc->next; diff -Nru a/net/atm/svc.c b/net/atm/svc.c --- a/net/atm/svc.c Wed Jun 4 17:57:07 2003 +++ b/net/atm/svc.c Tue Jun 17 11:00:06 2003 @@ -59,18 +59,18 @@ static void svc_disconnect(struct atm_vcc *vcc) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); struct sk_buff *skb; DPRINTK("svc_disconnect %p\n",vcc); if (test_bit(ATM_VF_REGIS,&vcc->flags)) { - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_close,NULL,NULL,NULL); while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ @@ -107,80 +107,138 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct sockaddr_atmsvc *addr; struct atm_vcc *vcc; + int error; - if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state != SS_UNCONNECTED) return -EINVAL; + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) + return -EINVAL; + lock_sock(sk); + if (sock->state == SS_CONNECTED) { + error = -EISCONN; + goto out; + } + if (sock->state != SS_UNCONNECTED) { + error = -EINVAL; + goto out; + } vcc = ATM_SD(sock); - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + if (test_bit(ATM_VF_SESSION, &vcc->flags)) { + error = -EINVAL; + goto out; + } addr = (struct sockaddr_atmsvc *) sockaddr; - if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; + if (addr->sas_family != AF_ATMSVC) { + error = -EAFNOSUPPORT; + goto out; + } clear_bit(ATM_VF_BOUND,&vcc->flags); /* failing rebind will kill old binding */ /* @@@ check memory (de)allocation on rebind */ - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) { + error = -EBADFD; + goto out; + } vcc->local = *addr; vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */ - if (!sigd) return -EUNATCH; - if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags); - return vcc->reply; + if (!sigd) { + error = -EUNATCH; + goto out; + } + if (!vcc->reply) + set_bit(ATM_VF_BOUND,&vcc->flags); + error = vcc->reply; +out: + release_sock(sk); + return error; } static int svc_connect(struct socket *sock,struct sockaddr *sockaddr, int sockaddr_len,int flags) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct sockaddr_atmsvc *addr; struct atm_vcc *vcc = ATM_SD(sock); int error; DPRINTK("svc_connect %p\n",vcc); - if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL; - if (sock->state == SS_CONNECTED) return -EISCONN; - if (sock->state == SS_CONNECTING) { - if (vcc->reply == WAITING) return -EALREADY; - sock->state = SS_UNCONNECTED; - if (vcc->reply) return vcc->reply; + lock_sock(sk); + if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { + error = -EINVAL; + goto out; } - else { - int error; - if (sock->state != SS_UNCONNECTED) return -EINVAL; - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + switch (sock->state) { + default: + error = -EINVAL; + goto out; + case SS_CONNECTED: + error = -EISCONN; + goto out; + case SS_CONNECTING: + if (vcc->reply == WAITING) { + error = -EALREADY; + goto out; + } + sock->state = SS_UNCONNECTED; + if (vcc->reply) { + error = vcc->reply; + goto out; + } + break; + case SS_UNCONNECTED: + if (test_bit(ATM_VF_SESSION, &vcc->flags)) { + error = -EINVAL; + goto out; + } addr = (struct sockaddr_atmsvc *) sockaddr; - if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; - if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD; + if (addr->sas_family != AF_ATMSVC) { + error = -EAFNOSUPPORT; + goto out; + } + if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { + error = -EBADFD; + goto out; + } if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || - vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) - return -EINVAL; + vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { + error = -EINVAL; + goto out; + } if (!vcc->qos.txtp.traffic_class && - !vcc->qos.rxtp.traffic_class) return -EINVAL; + !vcc->qos.rxtp.traffic_class) { + error = -EINVAL; + goto out; + } vcc->remote = *addr; vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote); if (flags & O_NONBLOCK) { - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); sock->state = SS_CONNECTING; - return -EINPROGRESS; + error = -EINPROGRESS; + goto out; } error = 0; while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_INTERRUPTIBLE); schedule(); - if (!signal_pending(current)) continue; + if (!signal_pending(current)) { + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); + continue; + } DPRINTK("*ABORT*\n"); /* * This is tricky: @@ -196,13 +254,13 @@ */ sigd_enq(vcc,as_close,NULL,NULL,NULL); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } if (!vcc->reply) while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + prepare_to_wait(&vcc->sleep, &wait, TASK_INTERRUPTIBLE); schedule(); } clear_bit(ATM_VF_REGIS,&vcc->flags); @@ -212,10 +270,17 @@ error = -EINTR; break; } - remove_wait_queue(&vcc->sleep,&wait); - if (error) return error; - if (!sigd) return -EUNATCH; - if (vcc->reply) return vcc->reply; + finish_wait(&vcc->sleep, &wait); + if (error) + goto out; + if (!sigd) { + error = -EUNATCH; + goto out; + } + if (vcc->reply) { + error = vcc->reply; + goto out; + } } /* * Not supported yet @@ -228,56 +293,73 @@ /* * #endif */ - if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci))) + if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci))) sock->state = SS_CONNECTED; else (void) svc_disconnect(vcc); +out: + release_sock(sk); return error; } static int svc_listen(struct socket *sock,int backlog) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); + struct sock *sk = sock->sk; struct atm_vcc *vcc = ATM_SD(sock); + int error; DPRINTK("svc_listen %p\n",vcc); + lock_sock(sk); /* let server handle listen on unbound sockets */ - if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL; + if (test_bit(ATM_VF_SESSION,&vcc->flags)) { + error = -EINVAL; + goto out; + } vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local); while (vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); + } + finish_wait(&vcc->sleep, &wait); + if (!sigd) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&vcc->sleep,&wait); - if (!sigd) return -EUNATCH; set_bit(ATM_VF_LISTEN,&vcc->flags); vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; - return vcc->reply; + error = vcc->reply; +out: + release_sock(sk); + return error; } static int svc_accept(struct socket *sock,struct socket *newsock,int flags) { + struct sock *sk = sock->sk; struct sk_buff *skb; struct atmsvc_msg *msg; struct atm_vcc *old_vcc = ATM_SD(sock); struct atm_vcc *new_vcc; int error; + lock_sock(sk); + error = svc_create(newsock,0); if (error) - return error; + goto out; new_vcc = ATM_SD(newsock); DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc); while (1) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); - add_wait_queue(&old_vcc->sleep,&wait); + prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE); while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) && sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; @@ -289,46 +371,63 @@ error = -EAGAIN; break; } - set_current_state(TASK_INTERRUPTIBLE); + release_sock(sk); schedule(); + lock_sock(sk); if (signal_pending(current)) { error = -ERESTARTSYS; break; } + prepare_to_wait(&old_vcc->sleep, &wait, TASK_INTERRUPTIBLE); + } + finish_wait(&old_vcc->sleep, &wait); + if (error) + goto out; + if (!skb) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&old_vcc->sleep,&wait); - if (error) return error; - if (!skb) return -EUNATCH; msg = (struct atmsvc_msg *) skb->data; new_vcc->qos = msg->qos; set_bit(ATM_VF_HASQOS,&new_vcc->flags); new_vcc->remote = msg->svc; new_vcc->local = msg->local; new_vcc->sap = msg->sap; - error = atm_connect(newsock,msg->pvc.sap_addr.itf, - msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); + error = vcc_connect(newsock, msg->pvc.sap_addr.itf, + msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci); dev_kfree_skb(skb); old_vcc->sk->sk_ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); - return error == -EAGAIN ? -EBUSY : error; + error = error == -EAGAIN ? -EBUSY : error; + goto out; } /* wait should be short, so we ignore the non-blocking flag */ new_vcc->reply = WAITING; - add_wait_queue(&new_vcc->sleep,&wait); + prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL); while (new_vcc->reply == WAITING && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); + release_sock(sk); schedule(); + lock_sock(sk); + prepare_to_wait(&new_vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); + } + finish_wait(&new_vcc->sleep, &wait); + if (!sigd) { + error = -EUNATCH; + goto out; } - remove_wait_queue(&new_vcc->sleep,&wait); - if (!sigd) return -EUNATCH; if (!new_vcc->reply) break; - if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; + if (new_vcc->reply != -ERESTARTSYS) { + error = new_vcc->reply; + goto out; + } } newsock->state = SS_CONNECTED; - return 0; +out: + release_sock(sk); + return error; } @@ -347,17 +446,17 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) { - DECLARE_WAITQUEUE(wait,current); + DEFINE_WAIT(wait); vcc->reply = WAITING; - add_wait_queue(&vcc->sleep,&wait); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0); while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) { - set_current_state(TASK_UNINTERRUPTIBLE); schedule(); + prepare_to_wait(&vcc->sleep, &wait, TASK_UNINTERRUPTIBLE); } - remove_wait_queue(&vcc->sleep,&wait); + finish_wait(&vcc->sleep, &wait); if (!sigd) return -EUNATCH; return vcc->reply; } @@ -366,33 +465,57 @@ static int svc_setsockopt(struct socket *sock,int level,int optname, char *optval,int optlen) { + struct sock *sk = sock->sk; struct atm_vcc *vcc; + int error = 0; if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP || - optlen != sizeof(struct atm_sap)) - return atm_setsockopt(sock,level,optname,optval,optlen); + optlen != sizeof(struct atm_sap)) { + error = vcc_setsockopt(sock, level, optname, optval, optlen); + goto out; + } vcc = ATM_SD(sock); - if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT; - set_bit(ATM_VF_HASSAP,&vcc->flags); - return 0; + if (copy_from_user(&vcc->sap, optval, optlen)) { + error = -EFAULT; + goto out; + } + set_bit(ATM_VF_HASSAP, &vcc->flags); +out: + release_sock(sk); + return error; } static int svc_getsockopt(struct socket *sock,int level,int optname, char *optval,int *optlen) { - int len; + struct sock *sk = sock->sk; + int error = 0, len; - if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) - return atm_getsockopt(sock,level,optname,optval,optlen); - if (get_user(len,optlen)) return -EFAULT; - if (len != sizeof(struct atm_sap)) return -EINVAL; - return copy_to_user(optval,&ATM_SD(sock)->sap,sizeof(struct atm_sap)) ? - -EFAULT : 0; + lock_sock(sk); + if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) { + error = vcc_getsockopt(sock, level, optname, optval, optlen); + goto out; + } + if (get_user(len, optlen)) { + error = -EFAULT; + goto out; + } + if (len != sizeof(struct atm_sap)) { + error = -EINVAL; + goto out; + } + if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) { + error = -EFAULT; + goto out; + } +out: + release_sock(sk); + return error; } -static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = { +static struct proto_ops svc_proto_ops = { .family = PF_ATMSVC, .release = svc_release, @@ -402,20 +525,17 @@ .accept = svc_accept, .getname = svc_getname, .poll = atm_poll, - .ioctl = atm_ioctl, + .ioctl = vcc_ioctl, .listen = svc_listen, .shutdown = svc_shutdown, .setsockopt = svc_setsockopt, .getsockopt = svc_getsockopt, - .sendmsg = atm_sendmsg, - .recvmsg = atm_recvmsg, + .sendmsg = vcc_sendmsg, + .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; - -#include -SOCKOPS_WRAP(svc_proto, PF_ATMSVC); static int svc_create(struct socket *sock,int protocol) { diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c --- a/net/bluetooth/af_bluetooth.c Mon Jun 16 08:11:36 2003 +++ b/net/bluetooth/af_bluetooth.c Wed Jun 18 13:59:01 2003 @@ -143,15 +143,13 @@ { write_lock_bh(&l->lock); sk_add_node(sk, &l->head); - sock_hold(sk); write_unlock_bh(&l->lock); } void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk) { write_lock_bh(&l->lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&l->lock); } diff -Nru a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c --- a/net/bridge/br_netfilter.c Thu Jun 12 01:09:19 2003 +++ b/net/bridge/br_netfilter.c Thu Jun 19 12:42:06 2003 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -304,31 +305,36 @@ return NF_ACCEPT; } - /* PF_BRIDGE/FORWARD *************************************************/ static int br_nf_forward_finish(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct net_device *in; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif - if (nf_bridge->mask & BRNF_PKT_TYPE) { - skb->pkt_type = PACKET_OTHERHOST; - nf_bridge->mask ^= BRNF_PKT_TYPE; + if (skb->protocol == __constant_htons(ETH_P_IP)) { + in = nf_bridge->physindev; + if (nf_bridge->mask & BRNF_PKT_TYPE) { + skb->pkt_type = PACKET_OTHERHOST; + nf_bridge->mask ^= BRNF_PKT_TYPE; + } + } else { + in = *((struct net_device **)(skb->cb)); } - NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, nf_bridge->physindev, + NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, skb->dev, br_forward_finish, 1); - return 0; } -/* This is the 'purely bridged' case. We pass the packet to +/* This is the 'purely bridged' case. For IP, we pass the packet to * netfilter with indev and outdev set to the bridge device, * but we are still able to filter on the 'real' indev/outdev - * because of the ipt_physdev.c module. + * because of the ipt_physdev.c module. For ARP, indev and outdev are the + * bridge ports. */ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, @@ -337,24 +343,33 @@ struct sk_buff *skb = *pskb; struct nf_bridge_info *nf_bridge; - if (skb->protocol != __constant_htons(ETH_P_IP)) + if (skb->protocol != __constant_htons(ETH_P_IP) && + skb->protocol != __constant_htons(ETH_P_ARP)) return NF_ACCEPT; #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug ^= (1 << NF_BR_FORWARD); #endif + if (skb->protocol == __constant_htons(ETH_P_IP)) { + nf_bridge = skb->nf_bridge; + if (skb->pkt_type == PACKET_OTHERHOST) { + skb->pkt_type = PACKET_HOST; + nf_bridge->mask |= BRNF_PKT_TYPE; + } - nf_bridge = skb->nf_bridge; - if (skb->pkt_type == PACKET_OTHERHOST) { - skb->pkt_type = PACKET_HOST; - nf_bridge->mask |= BRNF_PKT_TYPE; - } + /* The physdev module checks on this */ + nf_bridge->mask |= BRNF_BRIDGED; + nf_bridge->physoutdev = skb->dev; - nf_bridge->mask |= BRNF_BRIDGED; /* The physdev module checks on this */ - nf_bridge->physoutdev = skb->dev; + NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(in), + bridge_parent(out), br_nf_forward_finish); + } else { + struct net_device **d = (struct net_device **)(skb->cb); - NF_HOOK(PF_INET, NF_IP_FORWARD, skb, bridge_parent(nf_bridge->physindev), - bridge_parent(skb->dev), br_nf_forward_finish); + *d = (struct net_device *)in; + NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in, + (struct net_device *)out, br_nf_forward_finish); + } return NF_STOLEN; } diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Sun Jun 15 01:21:46 2003 +++ b/net/core/dev.c Wed Jun 18 17:58:00 2003 @@ -1018,6 +1018,66 @@ #define illegal_highdma(dev, skb) (0) #endif +extern void skb_release_data(struct sk_buff *); + +/* Keep head the same: replace data */ +int __skb_linearize(struct sk_buff *skb, int gfp_mask) +{ + unsigned int size; + u8 *data; + long offset; + struct skb_shared_info *ninfo; + int headerlen = skb->data - skb->head; + int expand = (skb->tail + skb->data_len) - skb->end; + + if (skb_shared(skb)) + BUG(); + + if (expand <= 0) + expand = 0; + + size = skb->end - skb->head + expand; + size = SKB_DATA_ALIGN(size); + data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + if (!data) + return -ENOMEM; + + /* Copy entire thing */ + if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) + BUG(); + + /* Set up shinfo */ + ninfo = (struct skb_shared_info*)(data + size); + atomic_set(&ninfo->dataref, 1); + ninfo->tso_size = skb_shinfo(skb)->tso_size; + ninfo->tso_segs = skb_shinfo(skb)->tso_segs; + ninfo->nr_frags = 0; + ninfo->frag_list = NULL; + + /* Offset between the two in bytes */ + offset = data - skb->head; + + /* Free old data. */ + skb_release_data(skb); + + skb->head = data; + skb->end = data + size; + + /* Set up new pointers */ + skb->h.raw += offset; + skb->nh.raw += offset; + skb->mac.raw += offset; + skb->tail += offset; + skb->data += offset; + + /* We are no longer a clone, even if we were. */ + skb->cloned = 0; + + skb->tail += skb->data_len; + skb->data_len = 0; + return 0; +} + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1039,7 +1099,7 @@ if (skb_shinfo(skb)->frag_list && !(dev->features & NETIF_F_FRAGLIST) && - skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* Fragmented skb is linearized if device does not support SG, @@ -1048,7 +1108,7 @@ */ if (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) && - skb_linearize(skb, GFP_ATOMIC)) + __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; /* If packet is not checksummed and device does not support @@ -1356,7 +1416,7 @@ if (!skb) goto out; } - if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC)) + if (skb_is_nonlinear(skb) && __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree; #ifdef CONFIG_SMP diff -Nru a/net/core/flow.c b/net/core/flow.c --- a/net/core/flow.c Sun Jun 15 06:46:08 2003 +++ b/net/core/flow.c Thu Jun 19 18:50:15 2003 @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -301,7 +300,8 @@ local_bh_disable(); smp_call_function(flow_cache_flush_per_cpu, &info, 1, 0); - flow_cache_flush_tasklet((unsigned long)&info); + if (test_bit(smp_processor_id(), &info.cpumap)) + flow_cache_flush_tasklet((unsigned long)&info); local_bh_enable(); wait_for_completion(&info.completion); @@ -309,13 +309,11 @@ up(&flow_flush_sem); } -static void __devinit flow_cache_cpu_online(int cpu) +static int __devinit flow_cache_cpu_prepare(int cpu) { struct tasklet_struct *tasklet; unsigned long order; - flow_hash_rnd_recalc(cpu) = 1; - for (order = 0; (PAGE_SIZE << order) < (sizeof(struct flow_cache_entry *)*flow_hash_size); @@ -325,15 +323,28 @@ flow_table(cpu) = (struct flow_cache_entry **) __get_free_pages(GFP_KERNEL, order); + if (!flow_table(cpu)) + return NOTIFY_BAD; + memset(flow_table(cpu), 0, PAGE_SIZE << order); + flow_hash_rnd_recalc(cpu) = 1; + flow_count(cpu) = 0; + tasklet = flow_flush_tasklet(cpu); tasklet_init(tasklet, flow_cache_flush_tasklet, 0); + return NOTIFY_OK; +} + +static int __devinit flow_cache_cpu_online(int cpu) +{ down(&flow_cache_cpu_sem); set_bit(cpu, &flow_cache_cpu_map); flow_cache_cpu_count++; up(&flow_cache_cpu_sem); + + return NOTIFY_OK; } static int __devinit flow_cache_cpu_notify(struct notifier_block *self, @@ -342,7 +353,10 @@ unsigned long cpu = (unsigned long)cpu; switch (action) { case CPU_UP_PREPARE: - flow_cache_cpu_online(cpu); + return flow_cache_cpu_prepare(cpu); + break; + case CPU_ONLINE: + return flow_cache_cpu_online(cpu); break; } return NOTIFY_OK; @@ -354,6 +368,8 @@ static int __init flow_cache_init(void) { + int i; + flow_cachep = kmem_cache_create("flow_cache", sizeof(struct flow_cache_entry), 0, SLAB_HWCACHE_ALIGN, @@ -371,8 +387,15 @@ flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; add_timer(&flow_hash_rnd_timer); - flow_cache_cpu_online(smp_processor_id()); register_cpu_notifier(&flow_cache_cpu_nb); + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (flow_cache_cpu_prepare(i) == NOTIFY_OK && + flow_cache_cpu_online(i) == NOTIFY_OK) + continue; + panic("NET: failed to initialise flow cache hash table\n"); + } return 0; } diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c --- a/net/core/skbuff.c Sun May 25 21:37:30 2003 +++ b/net/core/skbuff.c Wed Jun 18 17:58:01 2003 @@ -181,7 +181,7 @@ skb_get(list); } -static void skb_release_data(struct sk_buff *skb) +void skb_release_data(struct sk_buff *skb) { if (!skb->cloned || atomic_dec_and_test(&(skb_shinfo(skb)->dataref))) { @@ -410,64 +410,6 @@ copy_skb_header(n, skb); return n; -} - -/* Keep head the same: replace data */ -int skb_linearize(struct sk_buff *skb, int gfp_mask) -{ - unsigned int size; - u8 *data; - long offset; - struct skb_shared_info *ninfo; - int headerlen = skb->data - skb->head; - int expand = (skb->tail + skb->data_len) - skb->end; - - if (skb_shared(skb)) - BUG(); - - if (expand <= 0) - expand = 0; - - size = skb->end - skb->head + expand; - size = SKB_DATA_ALIGN(size); - data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); - if (!data) - return -ENOMEM; - - /* Copy entire thing */ - if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len)) - BUG(); - - /* Set up shinfo */ - ninfo = (struct skb_shared_info*)(data + size); - atomic_set(&ninfo->dataref, 1); - ninfo->tso_size = skb_shinfo(skb)->tso_size; - ninfo->tso_segs = skb_shinfo(skb)->tso_segs; - ninfo->nr_frags = 0; - ninfo->frag_list = NULL; - - /* Offset between the two in bytes */ - offset = data - skb->head; - - /* Free old data. */ - skb_release_data(skb); - - skb->head = data; - skb->end = data + size; - - /* Set up new pointers */ - skb->h.raw += offset; - skb->nh.raw += offset; - skb->mac.raw += offset; - skb->tail += offset; - skb->data += offset; - - /* We are no longer a clone, even if we were. */ - skb->cloned = 0; - - skb->tail += skb->data_len; - skb->data_len = 0; - return 0; } diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c --- a/net/decnet/af_decnet.c Mon Jun 16 08:11:36 2003 +++ b/net/decnet/af_decnet.c Wed Jun 18 13:59:01 2003 @@ -276,7 +276,7 @@ return; write_lock_bh(&dn_hash_lock); - hlist_del(&sk->sk_node); + sk_del_node_init(sk); DN_SK(sk)->addrloc = 0; list = listen_hash(&DN_SK(sk)->addr); sk_add_node(sk, list); diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c --- a/net/econet/af_econet.c Mon Jun 16 08:11:36 2003 +++ b/net/econet/af_econet.c Wed Jun 18 13:59:01 2003 @@ -96,8 +96,7 @@ static void econet_remove_socket(struct hlist_head *list, struct sock *sk) { write_lock_bh(&econet_lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&econet_lock); } @@ -105,7 +104,6 @@ { write_lock_bh(&econet_lock); sk_add_node(sk, list); - sock_hold(sk); write_unlock_bh(&econet_lock); } diff -Nru a/net/ethernet/eth.c b/net/ethernet/eth.c --- a/net/ethernet/eth.c Sun Sep 29 11:08:17 2002 +++ b/net/ethernet/eth.c Thu Jun 19 14:25:16 2003 @@ -216,9 +216,12 @@ int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh) { unsigned short type = hh->hh_type; - struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2); + struct ethhdr *eth; struct net_device *dev = neigh->dev; + eth = (struct ethhdr*) + (((u8*)hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); + if (type == __constant_htons(ETH_P_802_3)) return -1; @@ -235,5 +238,6 @@ void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr) { - memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len); + memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), + haddr, dev->addr_len); } diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c --- a/net/ipv4/arp.c Sun May 25 19:36:24 2003 +++ b/net/ipv4/arp.c Thu Jun 19 19:36:00 2003 @@ -623,15 +623,20 @@ int addr_type; struct neighbour *n; - /* arp_rcv below verifies the ARP header, verifies the device - * is ARP'able, and linearizes the SKB (if needed). + /* arp_rcv below verifies the ARP header and verifies the device + * is ARP'able. */ if (in_dev == NULL) goto out; + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * dev->addr_len) + + (2 * sizeof(u32))))) + goto out; + arp = skb->nh.arph; - arp_ptr= (unsigned char *)(arp+1); switch (dev_type) { default: @@ -693,6 +698,7 @@ /* * Extract fields */ + arp_ptr= (unsigned char *)(arp+1); sha = arp_ptr; arp_ptr += dev->addr_len; memcpy(&sip, arp_ptr, 4); @@ -840,11 +846,6 @@ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) goto out_of_mem; - - if (skb_is_nonlinear(skb)) { - if (skb_linearize(skb, GFP_ATOMIC) != 0) - goto freeskb; - } return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process); diff -Nru a/net/ipv4/igmp.c b/net/ipv4/igmp.c --- a/net/ipv4/igmp.c Mon May 19 23:22:52 2003 +++ b/net/ipv4/igmp.c Wed Jun 18 18:00:57 2003 @@ -178,7 +178,7 @@ in_dev->mr_gq_running = 1; if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2)) - atomic_inc(&in_dev->refcnt); + in_dev_hold(in_dev); } static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) @@ -186,7 +186,7 @@ int tv = net_random() % delay; if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2)) - atomic_inc(&in_dev->refcnt); + in_dev_hold(in_dev); } static void igmp_mod_timer(struct ip_mc_list *im, int max_delay) @@ -387,8 +387,17 @@ if (type == IGMPV3_ALLOW_NEW_SOURCES || type == IGMPV3_BLOCK_OLD_SOURCES) return skb; - if (pmc->crcount || isquery) + if (pmc->crcount || isquery) { + /* make sure we have room for group header and at + * least one source. + */ + if (skb && AVAILABLE(skb) < sizeof(struct igmpv3_grec)+ + sizeof(__u32)) { + igmpv3_sendpack(skb); + skb = 0; /* add_grhead will get a new one */ + } skb = add_grhead(skb, pmc, type, &pgr); + } return skb; } pih = skb ? (struct igmpv3_report *)skb->h.igmph : 0; @@ -661,6 +670,7 @@ in_dev->mr_gq_running = 0; igmpv3_send_report(in_dev, 0); + __in_dev_put(in_dev); } static void igmp_ifc_timer_expire(unsigned long data) @@ -672,6 +682,7 @@ in_dev->mr_ifc_count--; igmp_ifc_start_timer(in_dev, IGMP_Unsolicited_Report_Interval); } + __in_dev_put(in_dev); } static void igmp_ifc_event(struct in_device *in_dev) @@ -773,7 +784,7 @@ /* cancel the interface change timer */ in_dev->mr_ifc_count = 0; if (del_timer(&in_dev->mr_ifc_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); /* clear deleted report items */ igmpv3_clear_delrec(in_dev); } else if (len < 12) { @@ -1188,10 +1199,10 @@ #ifdef CONFIG_IP_MULTICAST in_dev->mr_ifc_count = 0; if (del_timer(&in_dev->mr_ifc_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); in_dev->mr_gq_running = 0; if (del_timer(&in_dev->mr_gq_timer)) - atomic_dec(&in_dev->refcnt); + __in_dev_put(in_dev); #endif for (i=in_dev->mc_list; i; i=i->next) diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c --- a/net/ipv4/ip_output.c Wed Jun 4 17:57:08 2003 +++ b/net/ipv4/ip_output.c Thu Jun 19 14:25:16 2003 @@ -193,8 +193,11 @@ #endif /*CONFIG_NETFILTER_DEBUG*/ if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); diff -Nru a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c --- a/net/ipv4/netfilter/arp_tables.c Sat May 17 12:39:13 2003 +++ b/net/ipv4/netfilter/arp_tables.c Thu Jun 19 19:36:00 2003 @@ -247,14 +247,16 @@ { static const char nulldevname[IFNAMSIZ] = { 0 }; unsigned int verdict = NF_DROP; - struct arphdr *arp = (*pskb)->nh.arph; + struct arphdr *arp; int hotdrop = 0; struct arpt_entry *e, *back; const char *indev, *outdev; void *table_base; - /* FIXME: Push down to extensions --RR */ - if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) + + (2 * (*pskb)->dev->addr_len) + + (2 * sizeof(u32))))) return NF_DROP; indev = in ? in->name : nulldevname; @@ -267,6 +269,7 @@ e = get_entry(table_base, table->private->hook_entry[hook]); back = get_entry(table_base, table->private->underflow[hook]); + arp = (*pskb)->nh.arph; do { if (arp_packet_match(arp, (*pskb)->dev, indev, outdev, &e->arp)) { struct arpt_entry_target *t; diff -Nru a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c --- a/net/ipv4/netfilter/arptable_filter.c Mon Apr 28 02:27:56 2003 +++ b/net/ipv4/netfilter/arptable_filter.c Thu Jun 19 12:42:06 2003 @@ -8,7 +8,8 @@ #include #include -#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT)) +#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ + (1 << NF_ARP_FORWARD)) /* Standard entry. */ struct arpt_standard @@ -32,15 +33,17 @@ static struct { struct arpt_replace repl; - struct arpt_standard entries[2]; + struct arpt_standard entries[3]; struct arpt_error term; } initial_table __initdata -= { { "filter", FILTER_VALID_HOOKS, 3, - sizeof(struct arpt_standard) * 2 + sizeof(struct arpt_error), += { { "filter", FILTER_VALID_HOOKS, 4, + sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard) }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, { [NF_ARP_IN] = 0, - [NF_ARP_OUT] = sizeof(struct arpt_standard), }, + [NF_ARP_OUT] = sizeof(struct arpt_standard), + [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, 0, NULL, { } }, { /* ARP_IN */ @@ -84,6 +87,27 @@ { 0, 0 }, { } }, { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } + }, + /* ARP_FORWARD */ + { + { + { + { 0 }, { 0 }, { 0 }, { 0 }, + 0, 0, + { { 0, }, { 0, } }, + { { 0, }, { 0, } }, + 0, 0, + 0, 0, + 0, 0, + "", "", { 0 }, { 0 }, + 0, 0 + }, + sizeof(struct arpt_entry), + sizeof(struct arpt_standard), + 0, + { 0, 0 }, { } }, + { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } } }, /* ERROR */ @@ -142,35 +166,34 @@ .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_OUT, - } + }, + { + .hook = arpt_hook, + .owner = THIS_MODULE, + .pf = NF_ARP, + .hooknum = NF_ARP_FORWARD, + }, }; static int __init init(void) { - int ret; + int ret, i; /* Register table */ ret = arpt_register_table(&packet_filter); if (ret < 0) return ret; - /* Register hooks */ - ret = nf_register_hook(&arpt_ops[0]); - if (ret < 0) - goto cleanup_table; - - ret = nf_register_hook(&arpt_ops[1]); - if (ret < 0) - goto cleanup_hook0; - + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) + if ((ret = nf_register_hook(&arpt_ops[i])) < 0) + goto cleanup_hooks; return ret; -cleanup_hook0: - nf_unregister_hook(&arpt_ops[0]); +cleanup_hooks: + while (--i >= 0) + nf_unregister_hook(&arpt_ops[i]); -cleanup_table: arpt_unregister_table(&packet_filter); - return ret; } @@ -178,7 +201,7 @@ { unsigned int i; - for (i = 0; i < sizeof(arpt_ops)/sizeof(struct nf_hook_ops); i++) + for (i = 0; i < ARRAY_SIZE(arpt_ops); i++) nf_unregister_hook(&arpt_ops[i]); arpt_unregister_table(&packet_filter); diff -Nru a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c --- a/net/ipv4/netfilter/ipt_MIRROR.c Wed May 21 16:36:54 2003 +++ b/net/ipv4/netfilter/ipt_MIRROR.c Thu Jun 19 14:25:16 2003 @@ -90,8 +90,11 @@ struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); hh->hh_output(skb); diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c --- a/net/ipv4/raw.c Mon Jun 16 08:11:36 2003 +++ b/net/ipv4/raw.c Wed Jun 18 13:59:01 2003 @@ -91,17 +91,14 @@ write_lock_bh(&raw_v4_lock); sk_add_node(sk, head); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); write_unlock_bh(&raw_v4_lock); } static void raw_v4_unhash(struct sock *sk) { write_lock_bh(&raw_v4_lock); - if (sk_del_node_init(sk)) { + if (sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); - } write_unlock_bh(&raw_v4_lock); } diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Mon Jun 16 09:53:26 2003 +++ b/net/ipv4/tcp.c Tue Jun 17 09:35:27 2003 @@ -1909,7 +1909,7 @@ BUG_TRAP(sk_unhashed(sk)); /* If it has not 0 inet_sk(sk)->num, it must be bound */ - BUG_TRAP(!inet_sk(sk)->num || sk->sk_prev); + BUG_TRAP(!inet_sk(sk)->num || tcp_sk(sk)->bind_hash); #ifdef TCP_DEBUG if (sk->sk_zapped) { @@ -2164,7 +2164,7 @@ tcp_sack_reset(tp); __sk_dst_reset(sk); - BUG_TRAP(!inet->num || sk->sk_prev); + BUG_TRAP(!inet->num || tp->bind_hash); sk->sk_error_report(sk); return err; diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Mon Jun 16 09:53:26 2003 +++ b/net/ipv4/tcp_ipv4.c Wed Jun 18 13:59:01 2003 @@ -156,9 +156,9 @@ struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *)sk->sk_prev; + tb = tcp_sk(sk)->bind_hash; sk_add_bind_node(child, &tb->owners); - child->sk_prev = (struct sock *)tb; + tcp_sk(child)->bind_hash = tb; spin_unlock(&head->lock); } @@ -174,7 +174,7 @@ { inet_sk(sk)->num = snum; sk_add_bind_node(sk, &tb->owners); - sk->sk_prev = (struct sock *)tb; + tcp_sk(sk)->bind_hash = tb; } static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) @@ -279,9 +279,9 @@ (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) tb->fastreuse = 0; success: - if (!sk->sk_prev) + if (!tcp_sk(sk)->bind_hash) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->sk_prev == (struct sock *)tb); + BUG_TRAP(tcp_sk(sk)->bind_hash == tb); ret = 0; fail_unlock: @@ -301,9 +301,9 @@ struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *)sk->sk_prev; - __hlist_del(&sk->sk_bind_node); - sk->sk_prev = NULL; + tb = tcp_sk(sk)->bind_hash; + __sk_del_bind_node(sk); + tcp_sk(sk)->bind_hash = NULL; inet->num = 0; tcp_bucket_destroy(tb); spin_unlock(&head->lock); @@ -359,7 +359,7 @@ lock = &tcp_ehash[sk->sk_hashent].lock; write_lock(lock); } - sk_add_node(sk, list); + __sk_add_node(sk, list); sock_prot_inc_use(sk->sk_prot); write_unlock(lock); if (listen_possible && sk->sk_state == TCP_LISTEN) @@ -392,7 +392,7 @@ write_lock_bh(&head->lock); } - if (sk_del_node_init(sk)) + if (__sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); write_unlock_bh(lock); @@ -608,7 +608,7 @@ inet->sport = htons(lport); sk->sk_hashent = hash; BUG_TRAP(sk_unhashed(sk)); - sk_add_node(sk, &head->chain); + __sk_add_node(sk, &head->chain); sock_prot_inc_use(sk->sk_prot); write_unlock(&head->lock); @@ -730,7 +730,7 @@ } head = &tcp_bhash[tcp_bhashfn(snum)]; - tb = (struct tcp_bind_bucket *)sk->sk_prev; + tb = tcp_sk(sk)->bind_hash; spin_lock_bh(&head->lock); if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { __tcp_v4_hash(sk, 0); @@ -2101,7 +2101,7 @@ __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if (sk->sk_prev) + if (tp->bind_hash) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Mon Jun 16 11:44:09 2003 +++ b/net/ipv4/tcp_minisocks.c Wed Jun 18 13:59:01 2003 @@ -301,15 +301,15 @@ */ bhead = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)]; spin_lock(&bhead->lock); - tw->tw_tb = (struct tcp_bind_bucket *)sk->sk_prev; - BUG_TRAP(sk->sk_prev); + tw->tw_tb = tcp_sk(sk)->bind_hash; + BUG_TRAP(tcp_sk(sk)->bind_hash); tw_add_bind_node(tw, &tw->tw_tb->owners); spin_unlock(&bhead->lock); write_lock(&ehead->lock); /* Step 2: Remove SK from established hash. */ - if (sk_del_node_init(sk)) + if (__sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); /* Step 3: Hash TW into TIMEWAIT half of established hash table. */ @@ -620,7 +620,7 @@ /* SANITY */ sk_node_init(&newsk->sk_node); - newsk->sk_prev = NULL; + tcp_sk(newsk)->bind_hash = NULL; /* Clone the TCP header template */ inet_sk(newsk)->dport = req->rmt_port; diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c --- a/net/ipv4/udp.c Mon Jun 16 08:11:36 2003 +++ b/net/ipv4/udp.c Wed Jun 18 13:59:01 2003 @@ -189,7 +189,6 @@ sk_add_node(sk, h); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); } write_unlock_bh(&udp_hash_lock); return 0; @@ -210,7 +209,6 @@ if (sk_del_node_init(sk)) { inet_sk(sk)->num = 0; sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); } write_unlock_bh(&udp_hash_lock); } diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c --- a/net/ipv6/icmp.c Mon Jun 16 08:11:36 2003 +++ b/net/ipv6/icmp.c Thu Jun 19 19:42:10 2003 @@ -613,12 +613,6 @@ case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_REDIRECT: - if (skb_is_nonlinear(skb) && - skb_linearize(skb, GFP_ATOMIC) != 0) { - kfree_skb(skb); - return 0; - } - ndisc_rcv(skb); break; diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c Sat Jun 7 02:54:46 2003 +++ b/net/ipv6/ip6_output.c Thu Jun 19 14:25:16 2003 @@ -76,8 +76,11 @@ struct hh_cache *hh = dst->hh; if (hh) { + int hh_alen; + read_lock_bh(&hh->hh_lock); - memcpy(skb->data - 16, hh->hh_data, 16); + hh_alen = HH_DATA_ALIGN(hh->hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); read_unlock_bh(&hh->hh_lock); skb_push(skb, hh->hh_len); return hh->hh_output(skb); diff -Nru a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c --- a/net/ipv6/ip6_tunnel.c Mon Jun 9 07:56:44 2003 +++ b/net/ipv6/ip6_tunnel.c Tue Jun 17 11:17:42 2003 @@ -230,8 +230,6 @@ dev->init = ip6ip6_tnl_dev_init; memcpy(&t->parms, p, sizeof (*p)); t->parms.name[IFNAMSIZ - 1] = '\0'; - if (t->parms.hop_limit > 255) - t->parms.hop_limit = -1; strcpy(dev->name, t->parms.name); if (!dev->name[0]) { int i = 0; @@ -952,7 +950,7 @@ ipv6_addr_copy(&t->parms.laddr, &p->laddr); ipv6_addr_copy(&t->parms.raddr, &p->raddr); t->parms.flags = p->flags; - t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1); + t->parms.hop_limit = p->hop_limit; t->parms.encap_limit = p->encap_limit; t->parms.flowinfo = p->flowinfo; ip6ip6_tnl_link_config(t); diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c --- a/net/ipv6/mcast.c Thu Jun 12 00:04:26 2003 +++ b/net/ipv6/mcast.c Wed Jun 18 18:00:57 2003 @@ -930,7 +930,7 @@ idev->mc_gq_running = 1; if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2)) - atomic_inc(&idev->refcnt); + in6_dev_hold(idev); } static void mld_ifc_start_timer(struct inet6_dev *idev, int delay) @@ -938,7 +938,7 @@ int tv = net_random() % delay; if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2)) - atomic_inc(&idev->refcnt); + in6_dev_hold(idev); } /* @@ -1037,7 +1037,7 @@ /* cancel the interface change timer */ idev->mc_ifc_count = 0; if (del_timer(&idev->mc_ifc_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); /* clear deleted report items */ mld_clear_delrec(idev); } else if (len >= 28) { @@ -1321,8 +1321,17 @@ if (type == MLD2_ALLOW_NEW_SOURCES || type == MLD2_BLOCK_OLD_SOURCES) return skb; - if (pmc->mca_crcount || isquery) + if (pmc->mca_crcount || isquery) { + /* make sure we have room for group header and at + * least one source. + */ + if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)+ + sizeof(struct in6_addr)) { + mld_sendpack(skb); + skb = 0; /* add_grhead will get a new one */ + } skb = add_grhead(skb, pmc, type, &pgr); + } return skb; } pmr = skb ? (struct mld2_report *)skb->h.raw : 0; @@ -1895,6 +1904,7 @@ idev->mc_gq_running = 0; mld_send_report(idev, 0); + __in6_dev_put(idev); } static void mld_ifc_timer_expire(unsigned long data) @@ -1907,6 +1917,7 @@ if (idev->mc_ifc_count) mld_ifc_start_timer(idev, idev->mc_maxdelay); } + __in6_dev_put(idev); } static void mld_ifc_event(struct inet6_dev *idev) @@ -1945,10 +1956,10 @@ read_lock_bh(&idev->lock); idev->mc_ifc_count = 0; if (del_timer(&idev->mc_ifc_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); idev->mc_gq_running = 0; if (del_timer(&idev->mc_gq_timer)) - atomic_dec(&idev->refcnt); + __in6_dev_put(idev); for (i = idev->mc_list; i; i=i->next) igmp6_group_dropped(i); diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c Wed Jun 11 23:37:09 2003 +++ b/net/ipv6/ndisc.c Thu Jun 19 19:42:10 2003 @@ -714,12 +714,6 @@ struct inet6_ifaddr *ifp; struct neighbour *neigh; - if (skb->len < sizeof(struct nd_msg)) { - if (net_ratelimit()) - printk(KERN_WARNING "ICMP NS: packet too short\n"); - return; - } - if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) { if (net_ratelimit()) printk(KERN_WARNING "ICMP NS: target address is multicast\n"); @@ -1410,7 +1404,12 @@ int ndisc_rcv(struct sk_buff *skb) { - struct nd_msg *msg = (struct nd_msg *) skb->h.raw; + struct nd_msg *msg; + + if (!pskb_may_pull(skb, skb->len)) + return 0; + + msg = (struct nd_msg *) skb->h.raw; __skb_push(skb, skb->data-skb->h.raw); diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c --- a/net/ipv6/raw.c Mon Jun 16 08:11:36 2003 +++ b/net/ipv6/raw.c Wed Jun 18 13:59:01 2003 @@ -64,17 +64,14 @@ write_lock_bh(&raw_v6_lock); sk_add_node(sk, list); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); write_unlock_bh(&raw_v6_lock); } static void raw_v6_unhash(struct sock *sk) { write_lock_bh(&raw_v6_lock); - if (sk_del_node_init(sk)) { + if (sk_del_node_init(sk)) sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); - } write_unlock_bh(&raw_v6_lock); } diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Mon Jun 16 09:53:26 2003 +++ b/net/ipv6/tcp_ipv6.c Tue Jun 17 09:35:28 2003 @@ -225,9 +225,9 @@ tb->fastreuse = 0; success: - if (!sk->sk_prev) + if (!tcp_sk(sk)->bind_hash) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->sk_prev == (struct sock *)tb); + BUG_TRAP(tcp_sk(sk)->bind_hash == tb); ret = 0; fail_unlock: @@ -1947,7 +1947,7 @@ __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if (sk->sk_prev) + if (tcp_sk(sk)->bind_hash) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c --- a/net/ipv6/udp.c Mon Jun 16 08:24:58 2003 +++ b/net/ipv6/udp.c Wed Jun 18 13:59:01 2003 @@ -160,7 +160,6 @@ if (sk_unhashed(sk)) { sk_add_node(sk, &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]); sock_prot_inc_use(sk->sk_prot); - sock_hold(sk); } write_unlock_bh(&udp_hash_lock); return 0; @@ -181,7 +180,6 @@ if (sk_del_node_init(sk)) { inet_sk(sk)->num = 0; sock_prot_dec_use(sk->sk_prot); - __sock_put(sk); } write_unlock_bh(&udp_hash_lock); } diff -Nru a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c --- a/net/ipv6/xfrm6_policy.c Thu Jun 12 17:40:50 2003 +++ b/net/ipv6/xfrm6_policy.c Tue Jun 17 13:50:04 2003 @@ -60,8 +60,16 @@ read_lock_bh(&policy->lock); for (dst = policy->bundles; dst; dst = dst->next) { struct xfrm_dst *xdst = (struct xfrm_dst*)dst; - if (!ipv6_addr_cmp(&xdst->u.rt6.rt6i_dst.addr, &fl->fl6_dst) && - !ipv6_addr_cmp(&xdst->u.rt6.rt6i_src.addr, &fl->fl6_src) && + struct in6_addr fl_dst_prefix, fl_src_prefix; + + ipv6_addr_prefix(&fl_dst_prefix, + &fl->fl6_dst, + xdst->u.rt6.rt6i_dst.plen); + ipv6_addr_prefix(&fl_src_prefix, + &fl->fl6_src, + xdst->u.rt6.rt6i_src.plen); + if (!ipv6_addr_cmp(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) && + !ipv6_addr_cmp(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) && __xfrm6_bundle_ok(xdst, fl)) { dst_clone(dst); break; @@ -133,7 +141,6 @@ dst_prev->child = &rt->u.dst; for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; - x->u.rt.fl = *fl; dst_prev->dev = rt->u.dst.dev; if (rt->u.dst.dev) @@ -157,6 +164,8 @@ x->u.rt6.rt6i_node = rt0->rt6i_node; x->u.rt6.rt6i_gateway = rt0->rt6i_gateway; memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); + x->u.rt6.rt6i_dst = rt0->rt6i_dst; + x->u.rt6.rt6i_src = rt0->rt6i_src; header_len -= x->u.dst.xfrm->props.header_len; trailer_len -= x->u.dst.xfrm->props.trailer_len; } diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c --- a/net/ipx/af_ipx.c Mon Jun 16 08:11:36 2003 +++ b/net/ipx/af_ipx.c Wed Jun 18 13:59:01 2003 @@ -142,7 +142,6 @@ spin_lock_bh(&intrfc->if_sklist_lock); sk_del_node_init(sk); spin_unlock_bh(&intrfc->if_sklist_lock); - sock_put(sk); ipxitf_put(intrfc); out: return; @@ -229,7 +228,6 @@ static void ipxitf_insert_socket(struct ipx_interface *intrfc, struct sock *sk) { ipxitf_hold(intrfc); - sock_hold(sk); spin_lock_bh(&intrfc->if_sklist_lock); ipx_sk(sk)->intrfc = intrfc; sk_add_node(sk, &intrfc->if_sklist); @@ -269,7 +267,7 @@ #ifdef CONFIG_IPX_INTERN static struct sock *ipxitf_find_internal_socket(struct ipx_interface *intrfc, - unsigned char *node, + unsigned char *ipx_node, unsigned short port) { struct sock *s; @@ -282,7 +280,7 @@ struct ipx_opt *ipxs = ipx_sk(s); if (ipxs->port == port && - !memcmp(node, ipxs->node, IPX_NODE_LEN)) + !memcmp(ipx_node, ipxs->node, IPX_NODE_LEN)) goto found; } s = NULL; diff -Nru a/net/irda/irda_device.c b/net/irda/irda_device.c --- a/net/irda/irda_device.c Fri May 23 00:48:10 2003 +++ b/net/irda/irda_device.c Thu Jun 19 17:28:31 2003 @@ -231,7 +231,7 @@ void irda_task_delete(struct irda_task *task) { /* Unregister task */ - hashbin_remove(tasks, (int) task, NULL); + hashbin_remove(tasks, (long) task, NULL); __irda_task_delete(task); } @@ -345,7 +345,7 @@ init_timer(&task->timer); /* Register task */ - hashbin_insert(tasks, (irda_queue_t *) task, (int) task, NULL); + hashbin_insert(tasks, (irda_queue_t *) task, (long) task, NULL); /* No time to waste, so lets get going! */ ret = irda_task_kick(task); diff -Nru a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c --- a/net/irda/irnet/irnet_irda.c Sun May 25 19:36:24 2003 +++ b/net/irda/irnet/irnet_irda.c Thu Jun 19 17:28:31 2003 @@ -33,8 +33,8 @@ { int index; /* In the log */ - DENTER(CTRL_TRACE, "(ap=0x%X, event=%d, daddr=%08x, name=``%s'')\n", - (unsigned int) ap, event, daddr, name); + DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", + ap, event, daddr, name); /* Protect this section via spinlock. * Note : as we are the only event producer, we only need to exclude @@ -100,7 +100,7 @@ { notify_t notify; /* Callback structure */ - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); @@ -125,8 +125,8 @@ /* Remember which TSAP selector we actually got */ self->stsap_sel = self->tsap->stsap_sel; - DEXIT(IRDA_SR_TRACE, " - tsap=0x%X, sel=0x%X\n", - (unsigned int) self->tsap, self->stsap_sel); + DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", + self->tsap, self->stsap_sel); return 0; } @@ -151,7 +151,7 @@ { __u8 dtsap_sel = 0; /* TSAP we are looking for */ - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* By default, no error */ self->errno = 0; @@ -231,7 +231,7 @@ static inline int irnet_find_lsap_sel(irnet_socket * self) { - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* This should not happen */ DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); @@ -268,7 +268,7 @@ { int err; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Open a local TSAP (an IrTTP instance) */ err = irnet_open_tsap(self); @@ -369,7 +369,7 @@ { int ret; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, @@ -382,8 +382,8 @@ clear_bit(0, &self->ttp_connect); DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); } - DEBUG(IRDA_SR_INFO, "Got the log (0x%X), size is %d\n", - (unsigned int) self->discoveries, self->disco_number); + DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", + self->discoveries, self->disco_number); /* Start with the first discovery */ self->disco_index = -1; @@ -426,7 +426,7 @@ int number; /* Number of nodes in the log */ int i; - DENTER(IRDA_SR_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&number, 0xffff, @@ -474,7 +474,7 @@ int irda_irnet_create(irnet_socket * self) { - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); self->magic = IRNET_MAGIC; /* Paranoia */ @@ -518,7 +518,7 @@ { int err; - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); /* Check if we are already trying to connect. * Because irda_irnet_connect() can be called directly by pppd plus @@ -585,7 +585,7 @@ void irda_irnet_destroy(irnet_socket * self) { - DENTER(IRDA_SOCK_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); if(self == NULL) return; @@ -676,7 +676,7 @@ int number; /* Number of nodes in the log */ int i; - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Ask lmp for the current discovery log */ discoveries = irlmp_get_discoveries(&number, 0xffff, @@ -722,7 +722,7 @@ irnet_socket * new = (irnet_socket *) NULL; int err; - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Get the addresses of the requester */ self->daddr = irttp_get_daddr(self->tsap); @@ -741,8 +741,8 @@ new = (irnet_socket *) hashbin_find(irnet_server.list, 0, self->rname); if(new) - DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches rname ``%s''.\n", - (unsigned int) new, new->rname); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", + new, new->rname); } /* If no name matches, try to find an socket by the destination address */ @@ -758,8 +758,8 @@ if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) { /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%X matches daddr %#08x.\n", - (unsigned int) new, self->daddr); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", + new, self->daddr); break; } new = (irnet_socket *) hashbin_get_next(irnet_server.list); @@ -777,8 +777,8 @@ (new->rname[0] == '\0') && (new->ppp_open)) { /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%X is free.\n", - (unsigned int) new); + DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", + new); break; } new = (irnet_socket *) hashbin_get_next(irnet_server.list); @@ -788,7 +788,7 @@ /* Spin lock end */ spin_unlock_bh(&irnet_server.spinlock); - DEXIT(IRDA_SERV_TRACE, " - new = 0x%X\n", (unsigned int) new); + DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); return new; } @@ -806,8 +806,8 @@ __u32 max_sdu_size, __u8 max_header_size) { - DENTER(IRDA_SERV_TRACE, "(server=0x%X, new=0x%X)\n", - (unsigned int) server, (unsigned int) new); + DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", + server, new); /* Now attach up the new socket */ new->tsap = irttp_dup(server->tsap, new); @@ -878,7 +878,7 @@ irnet_disconnect_server(irnet_socket * self, struct sk_buff *skb) { - DENTER(IRDA_SERV_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); /* Put the received packet in the black hole */ kfree_skb(skb); @@ -1010,8 +1010,8 @@ unsigned char * p; int code = 0; - DENTER(IRDA_TCB_TRACE, "(self/ap=0x%X, skb=0x%X)\n", - (unsigned int) ap,(unsigned int) skb); + DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", + ap, skb); DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); /* Check is ppp is ready to receive our packet */ @@ -1081,7 +1081,7 @@ int test_open; int test_connect; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); /* Don't care about it, but let's not leak it */ @@ -1171,7 +1171,7 @@ { irnet_socket * self = (irnet_socket *) instance; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); /* Check if socket is closing down (via irda_irnet_destroy()) */ if(! test_bit(0, &self->ttp_connect)) @@ -1237,7 +1237,7 @@ irnet_socket * self = (irnet_socket *) instance; LOCAL_FLOW oldflow = self->tx_flow; - DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow); + DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); /* Update our state */ self->tx_flow = flow; @@ -1278,7 +1278,7 @@ { irnet_socket * self = (irnet_socket *) instance; - DENTER(IRDA_TCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); /* We can only get this event if we are connected */ @@ -1320,9 +1320,9 @@ irnet_socket * server = &irnet_server.s; irnet_socket * new = (irnet_socket *) NULL; - DENTER(IRDA_TCB_TRACE, "(server=0x%X)\n", (unsigned int) server); + DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) instance); + "Invalid instance (0x%p) !!!\n", instance); DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); /* Try to find the most appropriate IrNET socket */ @@ -1466,7 +1466,7 @@ { irnet_socket * self = (irnet_socket *) priv; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) @@ -1530,7 +1530,7 @@ irnet_socket * self = (irnet_socket *) priv; __u8 dtsap_sel; /* TSAP we are looking for */ - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); /* Check if already connected (via irnet_connect_socket()) @@ -1583,8 +1583,8 @@ self->iriap = NULL; /* No more items : remove the log and signal termination */ - DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%X)\n", - (unsigned int) self->discoveries); + DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", + self->discoveries); if(self->discoveries != NULL) { /* Cleanup our copy of the discovery log */ @@ -1643,9 +1643,9 @@ { irnet_socket * self = &irnet_server.s; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) priv); + "Invalid instance (0x%p) !!!\n", priv); DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", discovery->info); @@ -1674,9 +1674,9 @@ { irnet_socket * self = &irnet_server.s; - DENTER(IRDA_OCB_TRACE, "(self=0x%X)\n", (unsigned int) self); + DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%X) !!!\n", (unsigned int) priv); + "Invalid instance (0x%p) !!!\n", priv); DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", expiry->info); diff -Nru a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c --- a/net/irda/irnet/irnet_ppp.c Mon May 12 09:53:17 2003 +++ b/net/irda/irnet/irnet_ppp.c Thu Jun 19 17:28:31 2003 @@ -43,7 +43,7 @@ char * next; /* Next command to process */ int length; /* Length of current command */ - DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count); + DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); /* Check for overflow... */ DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM, @@ -58,7 +58,7 @@ /* Safe terminate the string */ command[count] = '\0'; - DEBUG(CTRL_INFO, "Command line received is ``%s'' (%d).\n", + DEBUG(CTRL_INFO, "Command line received is ``%s'' (%Zd).\n", command, count); /* Check every commands in the command line */ @@ -184,8 +184,8 @@ { int done_event = 0; - DENTER(CTRL_TRACE, "(ap=0x%X, event=0x%X)\n", - (unsigned int) ap, (unsigned int) event); + DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n", + ap, event); /* Test if we have some work to do or we have already finished */ if(ap->disco_number == -1) @@ -205,8 +205,8 @@ /* Check if the we got some results */ if(ap->discoveries == NULL) ap->disco_number = -1; - DEBUG(CTRL_INFO, "Got the log (0x%X), size is %d\n", - (unsigned int) ap->discoveries, ap->disco_number); + DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n", + ap->discoveries, ap->disco_number); } /* Check if we have more item to dump */ @@ -232,8 +232,8 @@ if(ap->disco_index >= ap->disco_number) { /* No more items : remove the log and signal termination */ - DEBUG(CTRL_INFO, "Cleaning up log (0x%X)\n", - (unsigned int) ap->discoveries); + DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n", + ap->discoveries); if(ap->discoveries != NULL) { /* Cleanup our copy of the discovery log */ @@ -261,7 +261,7 @@ char event[64]; /* Max event is 61 char */ ssize_t ret = 0; - DENTER(CTRL_TRACE, "(ap=0x%X, count=%d)\n", (unsigned int) ap, count); + DENTER(CTRL_TRACE, "(ap=0x%p, count=%Zd)\n", ap, count); /* Check if we can write an event out in one go */ DABORT(count < sizeof(event), -EOVERFLOW, CTRL_ERROR, "Buffer to small.\n"); @@ -307,7 +307,7 @@ if(ret != 0) { /* No, return the error code */ - DEXIT(CTRL_TRACE, " - ret %d\n", ret); + DEXIT(CTRL_TRACE, " - ret %Zd\n", ret); return ret; } @@ -402,7 +402,7 @@ { unsigned int mask; - DENTER(CTRL_TRACE, "(ap=0x%X)\n", (unsigned int) ap); + DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap); poll_wait(file, &irnet_events.rwait, wait); mask = POLLOUT | POLLWRNORM; @@ -439,7 +439,7 @@ struct irnet_socket * ap; int err; - DENTER(FS_TRACE, "(file=0x%X)\n", (unsigned int) file); + DENTER(FS_TRACE, "(file=0x%p)\n", file); #ifdef SECURE_DEVIRNET /* This could (should?) be enforced by the permissions on /dev/irnet. */ @@ -482,7 +482,7 @@ /* Put our stuff where we will be able to find it later */ file->private_data = ap; - DEXIT(FS_TRACE, " - ap=0x%X\n", (unsigned int) ap); + DEXIT(FS_TRACE, " - ap=0x%p\n", ap); return 0; } @@ -498,8 +498,8 @@ { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n", - (unsigned int) file, (unsigned int) ap); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n"); /* Detach ourselves */ @@ -535,8 +535,8 @@ { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n", - (unsigned int) file, (unsigned int) ap, count); + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", + file, ap, count); DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); /* If we are connected to ppp_generic, let it handle the job */ @@ -559,8 +559,8 @@ { irnet_socket * ap = (struct irnet_socket *) file->private_data; - DPASS(FS_TRACE, "(file=0x%X, ap=0x%X, count=%d)\n", - (unsigned int) file, (unsigned int) ap, count); + DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%Zd)\n", + file, ap, count); DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); /* If we are connected to ppp_generic, let it handle the job */ @@ -581,8 +581,8 @@ irnet_socket * ap = (struct irnet_socket *) file->private_data; unsigned int mask; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X)\n", - (unsigned int) file, (unsigned int) ap); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", + file, ap); mask = POLLOUT | POLLWRNORM; DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n"); @@ -611,8 +611,8 @@ int err; int val; - DENTER(FS_TRACE, "(file=0x%X, ap=0x%X, cmd=0x%X)\n", - (unsigned int) file, (unsigned int) ap, cmd); + DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n", + file, ap, cmd); /* Basic checks... */ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); @@ -777,8 +777,8 @@ int islcp; /* Protocol == LCP */ int needaddr; /* Need PPP address */ - DENTER(PPP_TRACE, "(ap=0x%X, skb=0x%X)\n", - (unsigned int) ap, (unsigned int) skb); + DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n", + ap, skb); /* Extract PPP protocol from the frame */ data = skb->data; @@ -845,8 +845,8 @@ irnet_socket * self = (struct irnet_socket *) chan->private; int ret; - DENTER(PPP_TRACE, "(channel=0x%X, ap/self=0x%X)\n", - (unsigned int) chan, (unsigned int) self); + DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n", + chan, self); /* Check if things are somewhat valid... */ DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); @@ -949,8 +949,8 @@ int val; u32 accm[8]; - DENTER(PPP_TRACE, "(channel=0x%X, ap=0x%X, cmd=0x%X)\n", - (unsigned int) chan, (unsigned int) ap, cmd); + DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n", + chan, ap, cmd); /* Basic checks... */ DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); diff -Nru a/net/irda/irttp.c b/net/irda/irttp.c --- a/net/irda/irttp.c Mon May 12 10:16:55 2003 +++ b/net/irda/irttp.c Thu Jun 19 17:28:31 2003 @@ -1408,7 +1408,7 @@ spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); /* Find the old instance */ - if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) { + if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) { IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __FUNCTION__); spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; diff -Nru a/net/key/af_key.c b/net/key/af_key.c --- a/net/key/af_key.c Mon Jun 16 08:11:36 2003 +++ b/net/key/af_key.c Wed Jun 18 13:59:01 2003 @@ -115,15 +115,13 @@ { pfkey_table_grab(); sk_add_node(sk, &pfkey_table); - sock_hold(sk); pfkey_table_ungrab(); } static void pfkey_remove(struct sock *sk) { pfkey_table_grab(); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); pfkey_table_ungrab(); } diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c --- a/net/llc/llc_c_ac.c Wed Jun 4 17:57:09 2003 +++ b/net/llc/llc_c_ac.c Wed Jun 18 19:15:16 2003 @@ -102,13 +102,13 @@ if (ev->type == LLC_CONN_EV_TYPE_PDU) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM) { reason = LLC_DISC_REASON_RX_DM_RSP_PDU; rc = 0; - } else if (!LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + } else if (LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC) { reason = LLC_DISC_REASON_RX_DISC_CMD_PDU; rc = 0; @@ -146,13 +146,13 @@ switch (ev->type) { case LLC_CONN_EV_TYPE_PDU: - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR) { reason = LLC_RESET_REASON_LOCAL; rc = 0; - } else if (!LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + } else if (LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME) { reason = LLC_RESET_REASON_REMOTE; rc = 0; @@ -198,9 +198,9 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf) + if (LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && llc_sk(sk)->ack_pf) llc_conn_ac_clear_remote_busy(sk, skb); return 0; } @@ -310,7 +310,7 @@ struct llc_opt *llc = llc_sk(sk); llc->rx_pdu_hdr = *((u32 *)pdu); - if (!LLC_PDU_IS_CMD(pdu)) + if (LLC_PDU_IS_CMD(pdu)) llc_pdu_decode_pf_bit(skb, &f_bit); else f_bit = 0; @@ -1228,7 +1228,7 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_IS_RSP(pdu)) { u8 f_bit; llc_pdu_decode_pf_bit(skb, &f_bit); diff -Nru a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c --- a/net/llc/llc_c_ev.c Tue Apr 29 22:38:37 2003 +++ b/net/llc/llc_c_ev.c Wed Jun 18 19:15:16 2003 @@ -170,7 +170,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1; } @@ -178,7 +178,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1; } @@ -186,7 +186,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1; } @@ -195,8 +195,8 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && + LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -205,8 +205,8 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && + LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -217,8 +217,8 @@ u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && ns != vr && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -229,8 +229,8 @@ u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && ns != vr && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -240,7 +240,7 @@ struct llc_pdu_sn * pdu = llc_pdu_sn_hdr(skb); u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + u16 rc = LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", @@ -253,8 +253,8 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -262,8 +262,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -272,7 +272,7 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; } @@ -283,8 +283,8 @@ u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_0(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_0(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -295,8 +295,8 @@ u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && - !LLC_I_PF_IS_1(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && + LLC_I_PF_IS_1(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -307,7 +307,7 @@ u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; } @@ -317,7 +317,7 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); u8 vr = llc_sk(sk)->vR; u8 ns = LLC_I_GET_NS(pdu); - u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && + u16 rc = LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", @@ -329,8 +329,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; } @@ -338,8 +338,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1; } @@ -347,8 +347,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -356,8 +356,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -365,7 +365,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1; } @@ -373,8 +373,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; } @@ -382,8 +382,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1; } @@ -391,8 +391,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; } @@ -400,8 +400,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1; } @@ -409,8 +409,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; } @@ -418,8 +418,8 @@ { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1; } @@ -428,8 +428,8 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_0(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_0(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } @@ -438,8 +438,8 @@ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); return llc_conn_space(sk, skb) && - !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && - !LLC_S_PF_IS_1(pdu) && + LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_S(pdu) && + LLC_S_PF_IS_1(pdu) && LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; } @@ -447,7 +447,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_CMD(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1; } @@ -455,7 +455,7 @@ { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) && + return LLC_PDU_IS_RSP(pdu) && LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1; } @@ -464,11 +464,11 @@ u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_1(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_1(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu) && !LLC_U_PF_IS_1(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PF_IS_1(pdu)) rc = 0; } return rc; @@ -479,15 +479,15 @@ u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_0(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_0(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: - if (!LLC_U_PF_IS_0(pdu)) + if (LLC_U_PF_IS_0(pdu)) rc = 0; break; } @@ -500,10 +500,10 @@ u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_CMD(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_IS_CMD(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: @@ -519,16 +519,16 @@ u16 rc = 1; struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) { - if (!LLC_I_PF_IS_1(pdu)) + if (LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) { + if (LLC_I_PF_IS_1(pdu)) rc = 0; - } else if (!LLC_PDU_TYPE_IS_U(pdu)) + } else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_RSP(pdu)) { case LLC_2_PDU_RSP_UA: case LLC_2_PDU_RSP_DM: case LLC_2_PDU_RSP_FRMR: - if (!LLC_U_PF_IS_1(pdu)) + if (LLC_U_PF_IS_1(pdu)) rc = 0; break; } @@ -541,10 +541,10 @@ u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_IS_RSP(pdu)) { - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_IS_RSP(pdu)) { + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_RSP(pdu)) { case LLC_2_PDU_RSP_UA: case LLC_2_PDU_RSP_DM: @@ -562,9 +562,9 @@ u16 rc = 1; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) + if (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) rc = 0; - else if (!LLC_PDU_TYPE_IS_U(pdu)) + else if (LLC_PDU_TYPE_IS_U(pdu)) switch (LLC_U_PDU_CMD(pdu)) { case LLC_2_PDU_CMD_SABME: case LLC_2_PDU_CMD_DISC: @@ -585,8 +585,8 @@ u8 vs = llc_sk(sk)->vS; u8 nr = LLC_I_GET_NR(pdu); - if (!LLC_PDU_IS_CMD(pdu) && - (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && + if (LLC_PDU_IS_CMD(pdu) && + (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", __FUNCTION__, llc_sk(sk)->state, vs, nr); @@ -603,8 +603,8 @@ u8 vs = llc_sk(sk)->vS; u8 nr = LLC_I_GET_NR(pdu); - if (!LLC_PDU_IS_RSP(pdu) && - (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && + if (LLC_PDU_IS_RSP(pdu) && + (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { rc = 0; dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c --- a/net/llc/llc_conn.c Mon Jun 16 08:11:36 2003 +++ b/net/llc/llc_conn.c Wed Jun 18 19:15:16 2003 @@ -356,7 +356,7 @@ while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - if (!LLC_PDU_TYPE_IS_I(pdu) && + if (LLC_PDU_TYPE_IS_I(pdu) && !(skb->dev->flags & IFF_LOOPBACK)) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); diff -Nru a/net/llc/llc_evnt.c b/net/llc/llc_evnt.c --- a/net/llc/llc_evnt.c Tue Apr 29 22:38:37 2003 +++ b/net/llc/llc_evnt.c Wed Jun 18 19:15:16 2003 @@ -68,8 +68,8 @@ struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_CMD(pdu) && /* command PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_CMD(pdu) && /* command PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap ? 0 : 1; /* NULL DSAP value */ } @@ -81,8 +81,8 @@ struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_RSP(pdu) && /* response PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_RSP(pdu) && /* response PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap && /* NULL DSAP value */ !station->xid_r_count ? 0 : 1; @@ -95,8 +95,8 @@ struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_RSP(pdu) && /* response PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_RSP(pdu) && /* response PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID && !pdu->dsap && /* NULL DSAP value */ station->xid_r_count == 1 ? 0 : 1; @@ -109,8 +109,8 @@ struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); return ev->type == LLC_STATION_EV_TYPE_PDU && - !LLC_PDU_IS_CMD(pdu) && /* command PDU */ - !LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ + LLC_PDU_IS_CMD(pdu) && /* command PDU */ + LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && !pdu->dsap ? 0 : 1; /* NULL DSAP */ } diff -Nru a/net/llc/llc_s_ev.c b/net/llc/llc_s_ev.c --- a/net/llc/llc_s_ev.c Tue Apr 29 22:38:37 2003 +++ b/net/llc/llc_s_ev.c Wed Jun 18 19:15:16 2003 @@ -33,8 +33,8 @@ struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1; } @@ -62,8 +62,8 @@ struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; } @@ -72,8 +72,8 @@ struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1; } @@ -91,8 +91,8 @@ struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_CMD(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; } @@ -101,8 +101,8 @@ struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); - return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) && - !LLC_PDU_TYPE_IS_U(pdu) && + return ev->type == LLC_SAP_EV_TYPE_PDU && LLC_PDU_IS_RSP(pdu) && + LLC_PDU_TYPE_IS_U(pdu) && LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1; } diff -Nru a/net/llc/llc_sap.c b/net/llc/llc_sap.c --- a/net/llc/llc_sap.c Mon Jun 16 08:11:36 2003 +++ b/net/llc/llc_sap.c Wed Jun 18 13:59:01 2003 @@ -35,7 +35,6 @@ write_lock_bh(&sap->sk_list.lock); llc_sk(sk)->sap = sap; sk_add_node(sk, &sap->sk_list.list); - sock_hold(sk); write_unlock_bh(&sap->sk_list.lock); } @@ -50,8 +49,7 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) { write_lock_bh(&sap->sk_list.lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&sap->sk_list.lock); } diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c --- a/net/netlink/af_netlink.c Mon Jun 16 08:11:36 2003 +++ b/net/netlink/af_netlink.c Wed Jun 18 13:59:01 2003 @@ -193,7 +193,6 @@ if (nlk_sk(sk)->pid == 0) { nlk_sk(sk)->pid = pid; sk_add_node(sk, &nl_table[sk->sk_protocol]); - sock_hold(sk); err = 0; } } @@ -204,8 +203,7 @@ static void netlink_remove(struct sock *sk) { netlink_table_grab(); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); netlink_table_ungrab(); } diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Wed Jun 11 23:37:09 2003 +++ b/net/netsyms.c Wed Jun 18 18:06:18 2003 @@ -148,7 +148,7 @@ EXPORT_SYMBOL(sock_wfree); EXPORT_SYMBOL(sock_wmalloc); EXPORT_SYMBOL(sock_rmalloc); -EXPORT_SYMBOL(skb_linearize); +EXPORT_SYMBOL(__skb_linearize); EXPORT_SYMBOL(skb_checksum); EXPORT_SYMBOL(skb_checksum_help); EXPORT_SYMBOL(skb_recv_datagram); @@ -563,6 +563,7 @@ EXPORT_SYMBOL(unregister_netdevice); EXPORT_SYMBOL(synchronize_net); EXPORT_SYMBOL(netdev_state_change); +EXPORT_SYMBOL(netdev_boot_setup_check); EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_get_by_flags); EXPORT_SYMBOL(__dev_get_by_flags); diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c --- a/net/packet/af_packet.c Mon Jun 16 08:11:36 2003 +++ b/net/packet/af_packet.c Wed Jun 18 13:59:01 2003 @@ -758,8 +758,7 @@ return 0; write_lock_bh(&packet_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&packet_sklist_lock); /* @@ -984,7 +983,6 @@ write_lock_bh(&packet_sklist_lock); sk_add_node(sk, &packet_sklist); - sock_hold(sk); write_unlock_bh(&packet_sklist_lock); return(0); diff -Nru a/net/sched/sch_htb.c b/net/sched/sch_htb.c --- a/net/sched/sch_htb.c Sun May 4 06:08:55 2003 +++ b/net/sched/sch_htb.c Thu Jun 19 12:36:59 2003 @@ -9,6 +9,8 @@ * Authors: Martin Devera, * * Credits (in time order) for older HTB versions: + * Stef Coene + * HTB support at LARTC mailing list * Ondrej Kraus, * found missing INIT_QDISC(htb) * Vladimir Smelhaus, Aamer Akhter, Bert Hubert @@ -19,7 +21,7 @@ * created test case so that I was able to fix nasty bug * and many others. thanks. * - * $Id: sch_htb.c,v 1.17 2003/01/29 09:22:18 devik Exp devik $ + * $Id: sch_htb.c,v 1.20 2003/06/18 19:55:49 devik Exp devik $ */ #include #include @@ -71,7 +73,7 @@ #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock) #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock) -#define HTB_VER 0x3000a /* major must be matched with number suplied by TC as version */ +#define HTB_VER 0x3000c /* major must be matched with number suplied by TC as version */ #if HTB_VER >> 16 != TC_HTB_PROTOVER #error "Mismatched sch_htb.c and pkt_sch.h" @@ -217,6 +219,9 @@ /* time of nearest event per level (row) */ unsigned long near_ev_cache[TC_HTB_MAXDEPTH]; + /* cached value of jiffies in dequeue */ + unsigned long jiffies; + /* whether we hit non-work conserving class during this dequeue; we use */ int nwc_hit; /* this to disable mindelay complaint in dequeue */ @@ -336,7 +341,7 @@ static void htb_debug_dump (struct htb_sched *q) { int i,p; - printk(KERN_DEBUG "htb*g j=%lu\n",jiffies); + printk(KERN_DEBUG "htb*g j=%lu lj=%lu\n",jiffies,q->jiffies); /* rows */ for (i=TC_HTB_MAXDEPTH-1;i>=0;i--) { printk(KERN_DEBUG "htb*r%d m=%x",i,q->row_mask[i]); @@ -419,8 +424,8 @@ if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit()) printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint); #endif - cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay); - if (cl->pq_key == jiffies) + cl->pq_key = q->jiffies + PSCHED_US2JIFFIE(delay); + if (cl->pq_key == q->jiffies) cl->pq_key++; /* update the nearest event cache */ @@ -587,7 +592,7 @@ long toks; if ((toks = (cl->ctokens + *diff)) < ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode != HTB_CANT_SEND ? -cl->cbuffer : #endif 0)) { @@ -595,7 +600,7 @@ return HTB_CANT_SEND; } if ((toks = (cl->tokens + *diff)) >= ( -#ifdef HTB_HYSTERESIS +#if HTB_HYSTERESIS cl->cmode == HTB_CAN_SEND ? -cl->buffer : #endif 0)) @@ -798,7 +803,7 @@ cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -841,6 +846,7 @@ * * Scans event queue for pending events and applies them. Returns jiffies to * next pending event (0 for no event in pq). + * Note: Aplied are events whose have cl->pq_key <= jiffies. */ static long htb_do_events(struct htb_sched *q,int level) { @@ -855,9 +861,9 @@ while (p->rb_left) p = p->rb_left; cl = rb_entry(p, struct htb_class, pq_node); - if (cl->pq_key - (jiffies+1) < 0x80000000) { - HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - jiffies); - return cl->pq_key - jiffies; + if (cl->pq_key - (q->jiffies+1) < 0x80000000) { + HTB_DBG(8,3,"htb_do_ev_ret delay=%ld\n",cl->pq_key - q->jiffies); + return cl->pq_key - q->jiffies; } htb_safe_rb_erase(p,q->wait_pq+level); diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0); @@ -868,7 +874,7 @@ cl->classid, diff, (unsigned long long) q->now, (unsigned long long) cl->t_c, - jiffies); + q->jiffies); diff = 1000; } #endif @@ -975,7 +981,8 @@ printk(KERN_INFO "HTB delay %ld > 5sec\n", delay); delay = 5*HZ; } - mod_timer(&q->timer, jiffies + delay); + /* why don't use jiffies here ? because expires can be in past */ + mod_timer(&q->timer, q->jiffies + delay); sch->flags |= TCQ_F_THROTTLED; sch->stats.overlimits++; HTB_DBG(3,1,"htb_deq t_delay=%ld\n",delay); @@ -991,6 +998,7 @@ int evs_used = 0; #endif + q->jiffies = jiffies; HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue), sch->q.qlen); @@ -1010,14 +1018,14 @@ /* common case optimization - skip event handler quickly */ int m; long delay; - if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { + if (q->jiffies - q->near_ev_cache[level] < 0x80000000 || 0) { delay = htb_do_events(q,level); - q->near_ev_cache[level] += delay ? delay : HZ; + q->near_ev_cache[level] = q->jiffies + (delay ? delay : HZ); #ifdef HTB_DEBUG evs_used++; #endif } else - delay = q->near_ev_cache[level] - jiffies; + delay = q->near_ev_cache[level] - q->jiffies; if (delay && min_delay > delay) min_delay = delay; @@ -1036,8 +1044,8 @@ #ifdef HTB_DEBUG if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) { if (min_delay == LONG_MAX) { - printk(KERN_ERR "HTB: dequeue bug (%d), report it please !\n", - evs_used); + printk(KERN_ERR "HTB: dequeue bug (%d,%lu,%lu), report it please !\n", + evs_used,q->jiffies,jiffies); htb_debug_dump(q); } else printk(KERN_WARNING "HTB: mindelay=%ld, some class has " @@ -1046,7 +1054,7 @@ #endif htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay); fin: - HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb); + HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,q->jiffies,skb); return skb; } @@ -1409,7 +1417,7 @@ parent = parentid == TC_H_ROOT ? NULL : htb_find (parentid,sch); hopt = RTA_DATA(tb[TCA_HTB_PARMS-1]); - HTB_DBG(0,1,"htb_chg cl=%p, clid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); + HTB_DBG(0,1,"htb_chg cl=%p(%X), clid=%X, parid=%X, opt/prio=%d, rate=%u, buff=%d, quant=%d\n", cl,cl?cl->classid:0,classid,parentid,(int)hopt->prio,hopt->rate.rate,hopt->buffer,hopt->quantum); rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB-1]); ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB-1]); if (!rtab || !ctab) goto failure; diff -Nru a/net/sctp/endpointola.c b/net/sctp/endpointola.c --- a/net/sctp/endpointola.c Sat Jun 21 07:36:01 2003 +++ b/net/sctp/endpointola.c Tue Jun 17 09:35:28 2003 @@ -209,7 +209,7 @@ sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ - if (ep->base.sk->sk_prev) + if (sctp_sk(ep->base.sk)->bind_hash) sctp_put_port(ep->base.sk); /* Give up our hold on the sock. */ diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c Mon Jun 16 08:11:36 2003 +++ b/net/sctp/socket.c Wed Jun 18 18:59:41 2003 @@ -3078,9 +3078,9 @@ */ success: inet_sk(sk)->num = snum; - if (!sk->sk_prev) { + if (!sctp_sk(sk)->bind_hash) { sk_add_bind_node(sk, &pp->sk_list); - sk->sk_prev = (struct sock *) pp; + sctp_sk(sk)->bind_hash = pp; } ret = 0; @@ -3328,7 +3328,7 @@ /* Caller must hold hashbucket lock for this tb with local BH disabled */ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) { - if (!hlist_empty(&pp->sk_list)) { + if (hlist_empty(&pp->sk_list)) { if (pp->next) pp->next->pprev = pp->pprev; *(pp->pprev) = pp->next; @@ -3345,9 +3345,9 @@ struct sctp_bind_bucket *pp; sctp_spin_lock(&head->lock); - pp = (struct sctp_bind_bucket *)sk->sk_prev; - hlist_del(&sk->sk_bind_node); - sk->sk_prev = NULL; + pp = sctp_sk(sk)->bind_hash; + __sk_del_bind_node(sk); + sctp_sk(sk)->bind_hash = NULL; inet_sk(sk)->num = 0; sctp_bucket_destroy(pp); sctp_spin_unlock(&head->lock); diff -Nru a/net/sunrpc/cache.c b/net/sunrpc/cache.c --- a/net/sunrpc/cache.c Sat May 10 11:46:35 2003 +++ b/net/sunrpc/cache.c Tue Jun 17 16:18:16 2003 @@ -310,14 +310,17 @@ cp = & current_detail->hash_table[current_index]; ch = *cp; for (; ch; cp= & ch->next, ch= *cp) { - if (atomic_read(&ch->refcnt)) - continue; - if (ch->expiry_time < get_seconds() - || ch->last_refresh < current_detail->flush_time - ) - break; if (current_detail->nextcheck > ch->expiry_time) current_detail->nextcheck = ch->expiry_time+1; + if (ch->expiry_time >= get_seconds() + && ch->last_refresh >= current_detail->flush_time + ) + continue; + if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) + queue_loose(current_detail, ch); + + if (atomic_read(&ch->refcnt)) + continue; } if (ch) { cache_get(ch); @@ -464,6 +467,31 @@ dreq = list_entry(pending.next, struct cache_deferred_req, recent); list_del_init(&dreq->recent); dreq->revisit(dreq, 0); + } +} + +void cache_clean_deferred(void *owner) +{ + struct cache_deferred_req *dreq, *tmp; + struct list_head pending; + + + INIT_LIST_HEAD(&pending); + spin_lock(&cache_defer_lock); + + list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { + if (dreq->owner == owner) { + list_del(&dreq->hash); + list_move(&dreq->recent, &pending); + cache_defer_cnt--; + } + } + spin_unlock(&cache_defer_lock); + + while (!list_empty(&pending)) { + dreq = list_entry(pending.next, struct cache_deferred_req, recent); + list_del_init(&dreq->recent); + dreq->revisit(dreq, 1); } } diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c --- a/net/sunrpc/svc.c Fri Feb 7 12:25:20 2003 +++ b/net/sunrpc/svc.c Tue Jun 17 16:18:16 2003 @@ -98,6 +98,8 @@ sk_list); svc_delete_socket(svsk); } + + cache_clean_deferred(serv); /* Unregister service with the portmapper */ svc_register(serv, 0, 0); diff -Nru a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c --- a/net/sunrpc/svcauth_unix.c Tue Mar 11 20:03:48 2003 +++ b/net/sunrpc/svcauth_unix.c Tue Jun 17 16:18:16 2003 @@ -195,12 +195,12 @@ ipm.m_addr.s_addr = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); ipm.h.flags = 0; - if (dom) + if (dom) { ipm.m_client = container_of(dom, struct unix_domain, h); - else + ipm.m_add_change = ipm.m_client->addr_changes; + } else set_bit(CACHE_NEGATIVE, &ipm.h.flags); ipm.h.expiry_time = expiry; - ipm.m_add_change = ipm.m_client->addr_changes; ipmp = ip_map_lookup(&ipm, 1); if (ipmp) diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c --- a/net/sunrpc/svcsock.c Wed Jun 4 17:57:09 2003 +++ b/net/sunrpc/svcsock.c Tue Jun 17 16:31:29 2003 @@ -681,8 +681,17 @@ dprintk("svc: socket %p TCP (listen) state change %d\n", sk, sk->sk_state); - if (sk->sk_state != TCP_ESTABLISHED) { - /* Aborted connection, SYN_RECV or whatever... */ + if (sk->sk_state != TCP_LISTEN) { + /* + * This callback may called twice when a new connection + * is established as a child socket inherits everything + * from a parent LISTEN socket. + * 1) data_ready method of the parent socket will be called + * when one of child sockets become ESTABLISHED. + * 2) data_ready method of the child socket may be called + * when it receives data before the socket is accepted. + * In case of 2, we should ignore it silently. + */ goto out; } if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { @@ -1060,6 +1069,8 @@ set_bit(SK_CHNGBUF, &svsk->sk_flags); set_bit(SK_DATA, &svsk->sk_flags); + if (sk->sk_state != TCP_ESTABLISHED) + set_bit(SK_CLOSE, &svsk->sk_flags); } } @@ -1211,7 +1222,6 @@ } rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024; - rqstp->rq_userset = 0; rqstp->rq_chandle.defer = svc_defer; if (serv->sv_stats) @@ -1443,7 +1453,7 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many) { struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle); - struct svc_serv *serv = dr->serv; + struct svc_serv *serv = dreq->owner; struct svc_sock *svsk; if (too_many) { @@ -1481,7 +1491,7 @@ if (dr == NULL) return NULL; - dr->serv = rqstp->rq_server; + dr->handle.owner = rqstp->rq_server; dr->prot = rqstp->rq_prot; dr->addr = rqstp->rq_addr; dr->argslen = rqstp->rq_arg.len >> 2; diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c --- a/net/unix/af_unix.c Mon Jun 16 12:46:51 2003 +++ b/net/unix/af_unix.c Wed Jun 18 13:59:01 2003 @@ -211,15 +211,13 @@ static void __unix_remove_socket(struct sock *sk) { - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); } static void __unix_insert_socket(struct hlist_head *list, struct sock *sk) { BUG_TRAP(sk_unhashed(sk)); sk_add_node(sk, list); - sock_hold(sk); } static inline void unix_remove_socket(struct sock *sk) diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c --- a/net/wanrouter/af_wanpipe.c Mon Jun 16 08:11:36 2003 +++ b/net/wanrouter/af_wanpipe.c Wed Jun 18 13:59:01 2003 @@ -982,8 +982,7 @@ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); @@ -1143,8 +1142,7 @@ } write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(sk)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); @@ -1206,8 +1204,7 @@ * appropriate locks */ write_lock(&wanpipe_sklist_lock); - if (sk_del_node_init(init)) - __sock_put(sk); + sk_del_node_init(sk); write_unlock(&wanpipe_sklist_lock); sk->sk_socket = NULL; @@ -1536,7 +1533,6 @@ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_add_node(sk, &wanpipe_sklist); - sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); @@ -2434,7 +2430,6 @@ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); sk_add_node(newsk, &wanpipe_sklist); - sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c --- a/net/x25/af_x25.c Mon Jun 16 08:11:36 2003 +++ b/net/x25/af_x25.c Wed Jun 18 13:59:01 2003 @@ -154,8 +154,7 @@ static void x25_remove_socket(struct sock *sk) { write_lock_bh(&x25_list_lock); - if (sk_del_node_init(sk)) - sock_put(sk); + sk_del_node_init(sk); write_unlock_bh(&x25_list_lock); } @@ -219,7 +218,6 @@ { write_lock_bh(&x25_list_lock); sk_add_node(sk, &x25_list); - sock_hold(sk); write_unlock_bh(&x25_list_lock); } diff -Nru a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c --- a/scripts/kconfig/mconf.c Wed May 28 14:06:32 2003 +++ b/scripts/kconfig/mconf.c Thu Jun 19 16:51:11 2003 @@ -492,7 +492,7 @@ switch (type) { case 'm': if (single_menu_mode) - submenu->data = (void *) !submenu->data; + submenu->data = (void *) (long) !submenu->data; else conf(submenu); break; diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c Thu May 8 01:44:29 2003 +++ b/sound/pci/korg1212/korg1212.c Thu Jun 19 17:01:29 2003 @@ -2070,7 +2070,7 @@ snd_iprintf(buffer, korg1212->card->longname); snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1); snd_iprintf(buffer, "\nGeneral settings\n"); - snd_iprintf(buffer, " period size: %d bytes\n", K1212_PERIOD_BYTES); + snd_iprintf(buffer, " period size: %Zd bytes\n", K1212_PERIOD_BYTES); snd_iprintf(buffer, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] ); snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens ); snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens ); @@ -2336,7 +2336,7 @@ korg1212->sharedBufferPhy = (unsigned long)phys_addr; if (korg1212->sharedBufferPtr == NULL) { - snd_printk(KERN_ERR "can not allocate shared buffer memory (%d bytes)\n", sizeof(KorgSharedBuffer)); + snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer)); return -ENOMEM; } @@ -2385,9 +2385,12 @@ korg1212->dspCodeSize = sizeof (dspCode); - korg1212->VolumeTablePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->volumeData; - korg1212->RoutingTablePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->routeData; - korg1212->AdatTimeCodePhy = (u32) &((KorgSharedBuffer *) korg1212->sharedBufferPhy)->AdatTimeCode; + korg1212->VolumeTablePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, volumeData); + korg1212->RoutingTablePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, routeData); + korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + + offsetof(KorgSharedBuffer, AdatTimeCode); korg1212->dspMemPtr = snd_malloc_pci_pages(korg1212->pci, korg1212->dspCodeSize, &phys_addr); korg1212->dspMemPhy = (u32)phys_addr; diff -Nru a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c --- a/usr/gen_init_cpio.c Fri Mar 7 16:36:36 2003 +++ b/usr/gen_init_cpio.c Thu Jun 19 16:54:41 2003 @@ -56,7 +56,7 @@ const char *name = "TRAILER!!!"; sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ 0, /* ino */ 0, /* mode */ @@ -87,7 +87,7 @@ time_t mtime = time(NULL); sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ S_IFDIR | mode, /* mode */ @@ -119,7 +119,7 @@ mode |= S_IFCHR; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */ @@ -176,7 +176,7 @@ } sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" - "%08X%08X%08X%08X%08X%08X%08X", + "%08X%08X%08X%08X%08X%08ZX%08X", "070701", /* magic */ ino++, /* ino */ mode, /* mode */